1 /**
    2  * WARNING: automatically generated by ort 0.14.0.
    3  * DO NOT EDIT!
    4  * @packageDocumentation
    5  */
    6 
    7 import bcrypt from 'bcrypt';
    8 import Database from 'better-sqlite3';
    9 
   10 /**
   11  * Namespace for data interfaces and representative classes.  The 
   12  * interfaces are for the data itself, while the classes manage roles and 
   13  * metadata.
   14  */
   15 export namespace ortns
   16 {
   17 	/**
   18 	 * Birthsex of individual
   19 	 */
   20 	export enum sex
   21 	{
   22 		/**
   23 		 * Male
   24 		 */
   25 		male = '0',
   26 		/**
   27 		 * Female
   28 		 */
   29 		female = '1',
   30 		/**
   31 		 * Other
   32 		 */
   33 		other = '2'
   34 	}
   35 
   36 	/**
   37 	 * Controlling organisation.
   38 	 */
   39 	export interface companyData
   40 	{
   41 		/**
   42 		 * Name of the organisation.
   43 		 */
   44 		name: string;
   45 		id: bigint;
   46 		/**
   47 		 * Simply a check for null values.
   48 		 */
   49 		somenum: bigint|null;
   50 	}
   51 
   52 	function db_export_company(role: string, obj: companyData): any
   53 	{
   54 		const res: any = {}
   55 
   56 		res['name'] = obj['name'];
   57 		res['id'] = obj['id'].toString();
   58 		res['somenum'] = (obj['somenum'] === null) ?
   59 			null : obj['somenum'].toString();
   60 
   61 		return res;
   62 	}
   63 
   64 	/**
   65 	 * Class instance of {@link ortns.companyData}.
   66 	 */
   67 	export class company
   68 	{
   69 		readonly #role: string;
   70 		readonly obj: ortns.companyData;
   71 
   72 		/**
   73 		 * A {@link ortns.companyData} as extracted from the database in 
   74 		 * a particular role.
   75 		 * @param role The role in which this was extracted from the 
   76 		 * database. When exported, this role will be checked for 
   77 		 * permission to export.
   78 		 * @param obj The raw data.
   79 		 */
   80 		constructor(role: string, obj: ortns.companyData)
   81 		{
   82 			this.#role = role;
   83 			this.obj = obj;
   84 		}
   85 
   86 		/**
   87 		 * Export the contained {@link ortns.companyData} respecting 
   88 		 * fields not exported, roles, etc.  It's safe to call 
   89 		 * `JSON.stringify()` on the returned object to write responses.
   90 		 */
   91 		export(): any
   92 		{
   93 			return db_export_company(this.#role, this.obj);
   94 		}
   95 	}
   96 
   97 	/**
   98 	 * A regular user.
   99 	 */
  100 	export interface userData
  101 	{
  102 		/**
  103 		 * This struct will be filled in from an inner join
  104 		 *     on the "cid" variable.
  105 		 */
  106 		company: ortns.companyData;
  107 		/**
  108 		 * A foreign key reference.
  109 		 */
  110 		cid: bigint;
  111 		/**
  112 		 * User's birth sex.
  113 		 */
  114 		sex: ortns.sex;
  115 		/**
  116 		 * Password hash.
  117 		 *     This is passed to inserts and updates as a password,
  118 		 *     then hashed within the implementation and extracted
  119 		 *     (in listings and searches) as the hash value.
  120 		 */
  121 		hash: string;
  122 		/**
  123 		 * Unique e-mail address.
  124 		 */
  125 		email: string;
  126 		/**
  127 		 * A PNG image or something.
  128 		 */
  129 		image: Buffer|null;
  130 		/**
  131 		 * User's full name.
  132 		 */
  133 		name: string;
  134 		uid: bigint;
  135 	}
  136 
  137 	function db_export_user(role: string, obj: userData): any
  138 	{
  139 		const res: any = {}
  140 
  141 		res['company'] = db_export_company(role, obj['company'])
  142 		res['cid'] = obj['cid'].toString();
  143 		res['sex'] = obj['sex'];
  144 		/**
  145 		 * Don't output hash: password.
  146 		 */
  147 		res['email'] = obj['email'];
  148 		res['image'] = (obj['image'] === null) ?
  149 			null : obj['image'].toString('base64');
  150 		res['name'] = obj['name'];
  151 		res['uid'] = obj['uid'].toString();
  152 
  153 		return res;
  154 	}
  155 
  156 	/**
  157 	 * Class instance of {@link ortns.userData}.
  158 	 */
  159 	export class user
  160 	{
  161 		readonly #role: string;
  162 		readonly obj: ortns.userData;
  163 
  164 		/**
  165 		 * A {@link ortns.userData} as extracted from the database in a 
  166 		 * particular role.
  167 		 * @param role The role in which this was extracted from the 
  168 		 * database. When exported, this role will be checked for 
  169 		 * permission to export.
  170 		 * @param obj The raw data.
  171 		 */
  172 		constructor(role: string, obj: ortns.userData)
  173 		{
  174 			this.#role = role;
  175 			this.obj = obj;
  176 		}
  177 
  178 		/**
  179 		 * Export the contained {@link ortns.userData} respecting fields 
  180 		 * not exported, roles, etc.  It's safe to call 
  181 		 * `JSON.stringify()` on the returned object to write responses.
  182 		 */
  183 		export(): any
  184 		{
  185 			return db_export_user(this.#role, this.obj);
  186 		}
  187 	}
  188 
  189 	/**
  190 	 * Authenticated session.
  191 	 */
  192 	export interface sessionData
  193 	{
  194 		user: ortns.userData;
  195 		/**
  196 		 * Associated user.
  197 		 */
  198 		userid: bigint;
  199 		/**
  200 		 * Random cookie.
  201 		 */
  202 		token: bigint;
  203 		mtime: bigint;
  204 		id: bigint;
  205 	}
  206 
  207 	function db_export_session(role: string, obj: sessionData): any
  208 	{
  209 		const res: any = {}
  210 
  211 		res['user'] = db_export_user(role, obj['user'])
  212 		res['userid'] = obj['userid'].toString();
  213 		res['token'] = obj['token'].toString();
  214 		res['mtime'] = obj['mtime'].toString();
  215 		res['id'] = obj['id'].toString();
  216 
  217 		return res;
  218 	}
  219 
  220 	/**
  221 	 * Class instance of {@link ortns.sessionData}.
  222 	 */
  223 	export class session
  224 	{
  225 		readonly #role: string;
  226 		readonly obj: ortns.sessionData;
  227 
  228 		/**
  229 		 * A {@link ortns.sessionData} as extracted from the database in 
  230 		 * a particular role.
  231 		 * @param role The role in which this was extracted from the 
  232 		 * database. When exported, this role will be checked for 
  233 		 * permission to export.
  234 		 * @param obj The raw data.
  235 		 */
  236 		constructor(role: string, obj: ortns.sessionData)
  237 		{
  238 			this.#role = role;
  239 			this.obj = obj;
  240 		}
  241 
  242 		/**
  243 		 * Export the contained {@link ortns.sessionData} respecting 
  244 		 * fields not exported, roles, etc.  It's safe to call 
  245 		 * `JSON.stringify()` on the returned object to write responses.
  246 		 */
  247 		export(): any
  248 		{
  249 			return db_export_session(this.#role, this.obj);
  250 		}
  251 	}
  252 }
  253 
  254 namespace ortstmt
  255 {
  256 	export enum ortstmt
  257 	{
  258 		STMT_company_BY_UNIQUE_id,
  259 		STMT_company_BY_SEARCH_0,
  260 		STMT_company_INSERT,
  261 		STMT_company_DELETE_0,
  262 		STMT_user_BY_UNIQUE_email,
  263 		STMT_user_BY_UNIQUE_uid,
  264 		STMT_user_BY_SEARCH_0,
  265 		STMT_user_BY_SEARCH_1,
  266 		STMT_user_BY_SEARCH_2,
  267 		STMT_user_INSERT,
  268 		STMT_user_UPDATE_0,
  269 		STMT_user_UPDATE_1,
  270 		STMT_user_DELETE_0,
  271 		STMT_session_BY_UNIQUE_id,
  272 		STMT_session_BY_SEARCH_0,
  273 		STMT_session_INSERT,
  274 		STMT_session_DELETE_0,
  275 	}
  276 
  277 	export function stmtBuilder(idx: ortstmt): string
  278 	{
  279 		return ortstmts[idx];
  280 	}
  281 
  282 	const ortstmts: readonly string[] =
  283 	[
  284 		/* STMT_company_BY_UNIQUE_id */
  285 		'SELECT ' + ort_schema_company('company') + ' FROM company WHERE company.id = ?',
  286 		/* STMT_company_BY_SEARCH_0 */
  287 		'SELECT ' + ort_schema_company('company') + ' FROM company '
  288 			+ 'WHERE company.somenum ISNULL',
  289 		/* STMT_company_INSERT */
  290 		'INSERT INTO company (name,somenum) VALUES (?,?)',
  291 		/* STMT_company_DELETE_0 */
  292 		'DELETE FROM company',
  293 		/* STMT_user_BY_UNIQUE_email */
  294 		'SELECT ' + ort_schema_user('user') + ',' + ort_schema_company('_a') + ' FROM user '
  295 			+ 'INNER JOIN company AS _a ON _a.id=user.cid '
  296 			+ 'WHERE user.email = ?',
  297 		/* STMT_user_BY_UNIQUE_uid */
  298 		'SELECT ' + ort_schema_user('user') + ',' + ort_schema_company('_a') + ' FROM user '
  299 			+ 'INNER JOIN company AS _a ON _a.id=user.cid '
  300 			+ 'WHERE user.uid = ?',
  301 		/* STMT_user_BY_SEARCH_0 */
  302 		'SELECT ' + ort_schema_user('user') + ',' + ort_schema_company('_a') + ' FROM user '
  303 			+ 'INNER JOIN company AS _a ON _a.id=user.cid '
  304 			+ 'WHERE user.name = ? LIMIT 5',
  305 		/* STMT_user_BY_SEARCH_1 */
  306 		'SELECT ' + ort_schema_user('user') + ',' + ort_schema_company('_a') + ' FROM user '
  307 			+ 'INNER JOIN company AS _a ON _a.id=user.cid '
  308 			+ 'WHERE user.email = ?',
  309 		/* STMT_user_BY_SEARCH_2 */
  310 		'SELECT ' + ort_schema_user('user') + ',' + ort_schema_company('_a') + ' FROM user '
  311 			+ 'INNER JOIN company AS _a ON _a.id=user.cid '
  312 			+ 'WHERE user.uid = ? ORDER BY _a.name ASC',
  313 		/* STMT_user_INSERT */
  314 		'INSERT INTO user (cid,sex,hash,email,image,name) VALUES '
  315 			+ '(?,?,?,?,?,?)',
  316 		/* STMT_user_UPDATE_0 */
  317 		'UPDATE user SET hash = ? WHERE uid = ?',
  318 		/* STMT_user_UPDATE_1 */
  319 		'UPDATE user SET email = ? WHERE uid = ?',
  320 		/* STMT_user_DELETE_0 */
  321 		'DELETE FROM user',
  322 		/* STMT_session_BY_UNIQUE_id */
  323 		'SELECT ' + ort_schema_session('session') + ',' + ort_schema_user('_b') + ',' 
  324 			+ ort_schema_company('_c') + ' FROM session '
  325 			+ 'INNER JOIN user AS _b ON _b.uid=session.userid '
  326 			+ 'INNER JOIN company AS _c ON _c.id=_b.cid '
  327 			+ 'WHERE session.id = ?',
  328 		/* STMT_session_BY_SEARCH_0 */
  329 		'SELECT ' + ort_schema_session('session') + ',' + ort_schema_user('_b') + ',' 
  330 			+ ort_schema_company('_c') + ' FROM session '
  331 			+ 'INNER JOIN user AS _b ON _b.uid=session.userid '
  332 			+ 'INNER JOIN company AS _c ON _c.id=_b.cid '
  333 			+ 'WHERE _c.name = ? AND session.mtime = ?',
  334 		/* STMT_session_INSERT */
  335 		'INSERT INTO session (userid,token,mtime) VALUES (?,?,?)',
  336 		/* STMT_session_DELETE_0 */
  337 		'DELETE FROM session WHERE id = ?',
  338 	];
  339 
  340 	function ort_schema_company(v: string): string
  341 	{
  342 		return v + '.name' + ',' +
  343 		       v + '.id' + ',' +
  344 		       v + '.somenum';
  345 	}
  346 
  347 	function ort_schema_user(v: string): string
  348 	{
  349 		return v + '.cid' + ',' +
  350 		       v + '.sex' + ',' +
  351 		       v + '.hash' + ',' +
  352 		       v + '.email' + ',' +
  353 		       v + '.image' + ',' +
  354 		       v + '.name' + ',' +
  355 		       v + '.uid';
  356 	}
  357 
  358 	function ort_schema_session(v: string): string
  359 	{
  360 		return v + '.userid' + ',' +
  361 		       v + '.token' + ',' +
  362 		       v + '.mtime' + ',' +
  363 		       v + '.id';
  364 	}
  365 }
  366 
  367 /**
  368  * Manages each sequence of database interaction.
  369  */
  370 export class ortctx
  371 {
  372 	#role: string = 'default';
  373 	readonly #o: ortdb;
  374 
  375 	constructor(o: ortdb)
  376 	{
  377 		this.#o = o;
  378 	}
  379 
  380 	/**
  381 	 * Open a transaction with a unique identifier.  This is the 
  382 	 * preferred way of creating database transactions.  The transaction 
  383 	 * immediately enters unshared lock mode (single writer, readers 
  384 	 * allowed).
  385 	 * @param id The unique identifier.
  386 	 * @throws Throws on database error.
  387 	 */
  388 	db_trans_open_immediate(id: number): void
  389 	{
  390 		this.#o.db.exec('BEGIN TRANSACTION IMMEDIATE');
  391 	}
  392 
  393 	/**
  394 	 * Open a transaction with a unique identifier.  The transaction 
  395 	 * locks the database on first access with shared locks (no writes 
  396 	 * allowed, reads allowed) on queries and unshared locks (single 
  397 	 * writer, reads allowed) on modification.
  398 	 * @param id The unique identifier.
  399 	 * @throws Throws on database error.
  400 	 */
  401 	db_trans_open_deferred(id: number): void
  402 	{
  403 		this.#o.db.exec('BEGIN TRANSACTION DEFERRED');
  404 	}
  405 
  406 	/**
  407 	 * Open a transaction with a unique identifier.  The transaction 
  408 	 * locks exclusively, preventing all other access.
  409 	 * @param id The unique identifier.
  410 	 * @throws Throws on database error.
  411 	 */
  412 	db_trans_open_exclusive(id: number): void
  413 	{
  414 		this.#o.db.exec('BEGIN TRANSACTION EXCLUSIVE');
  415 	}
  416 
  417 	/**
  418 	 * Roll-back a transaction opened by {@link db_trans_open_immediate} 
  419 	 * or similar.
  420 	 * @param id The transaction identifier.
  421 	 * @throws Throws on database error.
  422 	 */
  423 	db_trans_rollback(id: number): void
  424 	{
  425 		this.#o.db.exec('ROLLBACK TRANSACTION');
  426 	}
  427 
  428 	/**
  429 	 * Commit a transaction opened by {@link db_trans_open_immediate} or 
  430 	 * similar.
  431 	 * @param id The transaction identifier.
  432 	 * @throws Throws on database error.
  433 	 */
  434 	db_trans_commit(id: number): void
  435 	{
  436 		this.#o.db.exec('COMMIT TRANSACTION');
  437 	}
  438 
  439 	private db_company_fill(data: {row: any[], pos: number}):
  440 		ortns.companyData
  441 	{
  442 		const obj: ortns.companyData = {
  443 			'name': <string>data.row[data.pos + 0],
  444 			'id': <bigint>data.row[data.pos + 1],
  445 			'somenum': <bigint|null>data.row[data.pos + 2],
  446 		};
  447 		data.pos += 3;
  448 		return obj;
  449 	}
  450 
  451 	/**
  452 	 * Insert a row.  Accepts all native fields as parameters excluding 
  453 	 * rowid, which is automatically set by the database.  If any fields 
  454 	 * are specified as null, they may be passed as null values.
  455 	 * @param v1 name
  456 	 * @param v2 somenum
  457 	 * @return Row identifier on success or -1 on constraint violation.
  458 	 * @throws Throws on database error.
  459 	 */
  460 	db_company_insert(v1: string, v2: bigint|null): bigint
  461 	{
  462 		const parms: any[] = [];
  463 		let info: Database.RunResult;
  464 		const stmt: Database.Statement =
  465 			this.#o.db.prepare(ortstmt.stmtBuilder
  466 			(ortstmt.ortstmt.STMT_company_INSERT));
  467 
  468 		parms.push(v1);
  469 		parms.push(v2);
  470 
  471 		try {
  472 			info = stmt.run(parms);
  473 		} catch (er) {
  474 			if (er.code === 'SQLITE_CONSTRAINT_UNIQUE' ||
  475 			    er.code === 'SQLITE_CONSTRAINT_FOREIGNKEY')
  476 				return BigInt(-1);
  477 			throw er;
  478 		}
  479 
  480 		return BigInt(info.lastInsertRowid.toString());
  481 	}
  482 
  483 	/**
  484 	 * Search for a set of {@link ortns.company}.
  485 	 * The following fields are constrained by unary operations: 
  486 	 * somenum (checked is null)
  487 	 * @return Result of null if no results found.
  488 	 * @throws Throws on database error.
  489 	 */
  490 	db_company_list_by_somenum_isnull(): ortns.company[]
  491 	{
  492 		const parms: any[] = [];
  493 		const stmt: Database.Statement =
  494 			this.#o.db.prepare(ortstmt.stmtBuilder
  495 			(ortstmt.ortstmt.STMT_company_BY_SEARCH_0));
  496 		stmt.raw(true);
  497 
  498 		const rows: any[] = stmt.all(parms);
  499 		const objs: ortns.company[] = [];
  500 		let i: number;
  501 
  502 		for (i = 0; i < rows.length; i++) {
  503 			const obj: ortns.companyData =
  504 				this.db_company_fill({row: <any[]>rows[i], pos: 0});
  505 			objs.push(new ortns.company(this.#role, obj));
  506 		}
  507 		return objs;
  508 	}
  509 
  510 	/**
  511 	 * @throws Throws on database error.
  512 	 */
  513 	db_company_delete(): void
  514 	{
  515 		const parms: any[] = [];
  516 		let info: Database.RunResult;
  517 		const stmt: Database.Statement =
  518 			this.#o.db.prepare(ortstmt.stmtBuilder
  519 			(ortstmt.ortstmt.STMT_company_DELETE_0));
  520 
  521 
  522 		stmt.run(parms);
  523 	}
  524 
  525 	private db_user_fill(data: {row: any[], pos: number}):
  526 		ortns.userData
  527 	{
  528 		const obj: ortns.userData = {
  529 			/* A dummy value for now. */
  530 			'company': <ortns.companyData>{},
  531 			'cid': <bigint>data.row[data.pos + 0],
  532 			'sex': <ortns.sex>data.row[data.pos + 1].toString(),
  533 			'hash': <string>data.row[data.pos + 2],
  534 			'email': <string>data.row[data.pos + 3],
  535 			'image': <Buffer|null>data.row[data.pos + 4],
  536 			'name': <string>data.row[data.pos + 5],
  537 			'uid': <bigint>data.row[data.pos + 6],
  538 		};
  539 		data.pos += 7;
  540 		obj.company = this.db_company_fill(data);
  541 		return obj;
  542 	}
  543 
  544 	/**
  545 	 * Insert a row.  Accepts all native fields as parameters excluding 
  546 	 * rowid, which is automatically set by the database.  If any fields 
  547 	 * are specified as null, they may be passed as null values.
  548 	 * @param v1 cid
  549 	 * @param v2 sex
  550 	 * @param v3 hash
  551 	 * @param v4 email
  552 	 * @param v5 image
  553 	 * @param v6 name
  554 	 * @return Row identifier on success or -1 on constraint violation.
  555 	 * @throws Throws on database error.
  556 	 */
  557 	db_user_insert(v1: bigint, v2: ortns.sex, v3: string, v4: string,
  558 		v5: Buffer|null, v6: string): bigint
  559 	{
  560 		const parms: any[] = [];
  561 		let info: Database.RunResult;
  562 		const stmt: Database.Statement =
  563 			this.#o.db.prepare(ortstmt.stmtBuilder
  564 			(ortstmt.ortstmt.STMT_user_INSERT));
  565 
  566 		parms.push(v1);
  567 		parms.push(v2);
  568 		parms.push(bcrypt.hashSync(v3, this.#o.args.bcrypt_cost));
  569 		parms.push(v4);
  570 		parms.push(v5);
  571 		parms.push(v6);
  572 
  573 		try {
  574 			info = stmt.run(parms);
  575 		} catch (er) {
  576 			if (er.code === 'SQLITE_CONSTRAINT_UNIQUE' ||
  577 			    er.code === 'SQLITE_CONSTRAINT_FOREIGNKEY')
  578 				return BigInt(-1);
  579 			throw er;
  580 		}
  581 
  582 		return BigInt(info.lastInsertRowid.toString());
  583 	}
  584 
  585 	/**
  586 	 * Create a function that searches for users by a given
  587 	 *     name; and, when found, invokes a callback function
  588 	 *     provided the user structure.
  589 	 * The callback is called during an implicit transaction: thus, it 
  590 	 * should not invoke any database modifications or risk deadlock.
  591 	 * @param v1 name
  592 	 * @param cb Callback with retrieved data.
  593 	 * @throws Throws on database error.
  594 	 */
  595 	db_user_iterate_by_name_eq(v1: string,
  596 		cb: (res: ortns.user) => void): void
  597 	{
  598 		const parms: any[] = [];
  599 		const stmt: Database.Statement =
  600 			this.#o.db.prepare(ortstmt.stmtBuilder
  601 			(ortstmt.ortstmt.STMT_user_BY_SEARCH_0));
  602 		stmt.raw(true);
  603 
  604 		parms.push(v1);
  605 
  606 		for (const cols of stmt.iterate(parms)) {
  607 			const obj: ortns.userData =
  608 				this.db_user_fill({row: <any>cols, pos: 0});
  609 			cb(new ortns.user(this.#role, obj));
  610 		}
  611 	}
  612 
  613 	/**
  614 	 * Search for a unique user with their e-mail and
  615 	 *     password.
  616 	 *     This is a quick way to verify that a user has entered
  617 	 *     the correct password for logging in.
  618 	 * @param v1 email
  619 	 * @param v2 hash (hashed password)
  620 	 * @return Result or null if no results found.
  621 	 * @throws Throws on database error.
  622 	 */
  623 	db_user_get_creds(v1: string, v2: string): ortns.user|null
  624 	{
  625 		const parms: any[] = [];
  626 		const stmt: Database.Statement =
  627 			this.#o.db.prepare(ortstmt.stmtBuilder
  628 			(ortstmt.ortstmt.STMT_user_BY_SEARCH_1));
  629 		stmt.raw(true);
  630 
  631 		parms.push(v1);
  632 
  633 		const cols: any = stmt.get(parms);
  634 
  635 		if (typeof cols === 'undefined')
  636 			return null;
  637 		const obj: ortns.userData = 
  638 			this.db_user_fill({row: <any[]>cols, pos: 0});
  639 		if (!bcrypt.compareSync(v2, obj.hash))
  640 			return null;
  641 		return new ortns.user(this.#role, obj);
  642 	}
  643 
  644 	/**
  645 	 * Lookup by unique identifier.
  646 	 * @param v1 uid
  647 	 * @return Result or null if no results found.
  648 	 * @throws Throws on database error.
  649 	 */
  650 	db_user_get_by_uid_eq(v1: bigint): ortns.user|null
  651 	{
  652 		const parms: any[] = [];
  653 		const stmt: Database.Statement =
  654 			this.#o.db.prepare(ortstmt.stmtBuilder
  655 			(ortstmt.ortstmt.STMT_user_BY_SEARCH_2));
  656 		stmt.raw(true);
  657 
  658 		parms.push(v1);
  659 
  660 		const cols: any = stmt.get(parms);
  661 
  662 		if (typeof cols === 'undefined')
  663 			return null;
  664 		const obj: ortns.userData = 
  665 			this.db_user_fill({row: <any[]>cols, pos: 0});
  666 		return new ortns.user(this.#role, obj);
  667 	}
  668 
  669 	/**
  670 	 * @throws Throws on database error.
  671 	 */
  672 	db_user_delete(): void
  673 	{
  674 		const parms: any[] = [];
  675 		let info: Database.RunResult;
  676 		const stmt: Database.Statement =
  677 			this.#o.db.prepare(ortstmt.stmtBuilder
  678 			(ortstmt.ortstmt.STMT_user_DELETE_0));
  679 
  680 
  681 		stmt.run(parms);
  682 	}
  683 
  684 	/**
  685 	 * @param v1 update hash (hashed)
  686 	 * @param v2 constraint uid (eq)
  687 	 * @return False on constraint violation, true on success.
  688 	 * @throws Throws on database error.
  689 	 */
  690 	db_user_update_hash_set_by_uid_eq(v1: string, v2: bigint): boolean
  691 	{
  692 		const parms: any[] = [];
  693 		let info: Database.RunResult;
  694 		const stmt: Database.Statement =
  695 			this.#o.db.prepare(ortstmt.stmtBuilder
  696 			(ortstmt.ortstmt.STMT_user_UPDATE_0));
  697 
  698 		parms.push(bcrypt.hashSync(v1, this.#o.args.bcrypt_cost));
  699 		parms.push(v2);
  700 
  701 		try {
  702 			info = stmt.run(parms);
  703 		} catch (er) {
  704 			if (er.code === 'SQLITE_CONSTRAINT_UNIQUE' ||
  705 			    er.code === 'SQLITE_CONSTRAINT_FOREIGNKEY')
  706 				return false;
  707 			throw er;
  708 		}
  709 
  710 		return true;
  711 	}
  712 
  713 	/**
  714 	 * @param v1 update email
  715 	 * @param v2 constraint uid (eq)
  716 	 * @return False on constraint violation, true on success.
  717 	 * @throws Throws on database error.
  718 	 */
  719 	db_user_update_email_set_by_uid_eq(v1: string, v2: bigint):
  720 		boolean
  721 	{
  722 		const parms: any[] = [];
  723 		let info: Database.RunResult;
  724 		const stmt: Database.Statement =
  725 			this.#o.db.prepare(ortstmt.stmtBuilder
  726 			(ortstmt.ortstmt.STMT_user_UPDATE_1));
  727 
  728 		parms.push(v1);
  729 		parms.push(v2);
  730 
  731 		try {
  732 			info = stmt.run(parms);
  733 		} catch (er) {
  734 			if (er.code === 'SQLITE_CONSTRAINT_UNIQUE' ||
  735 			    er.code === 'SQLITE_CONSTRAINT_FOREIGNKEY')
  736 				return false;
  737 			throw er;
  738 		}
  739 
  740 		return true;
  741 	}
  742 
  743 	private db_session_fill(data: {row: any[], pos: number}):
  744 		ortns.sessionData
  745 	{
  746 		const obj: ortns.sessionData = {
  747 			/* A dummy value for now. */
  748 			'user': <ortns.userData>{},
  749 			'userid': <bigint>data.row[data.pos + 0],
  750 			'token': <bigint>data.row[data.pos + 1],
  751 			'mtime': <bigint>data.row[data.pos + 2],
  752 			'id': <bigint>data.row[data.pos + 3],
  753 		};
  754 		data.pos += 4;
  755 		obj.user = this.db_user_fill(data);
  756 		return obj;
  757 	}
  758 
  759 	/**
  760 	 * Insert a row.  Accepts all native fields as parameters excluding 
  761 	 * rowid, which is automatically set by the database.  If any fields 
  762 	 * are specified as null, they may be passed as null values.
  763 	 * @param v1 userid
  764 	 * @param v2 token
  765 	 * @param v3 mtime
  766 	 * @return Row identifier on success or -1 on constraint violation.
  767 	 * @throws Throws on database error.
  768 	 */
  769 	db_session_insert(v1: bigint, v2: bigint, v3: bigint): bigint
  770 	{
  771 		const parms: any[] = [];
  772 		let info: Database.RunResult;
  773 		const stmt: Database.Statement =
  774 			this.#o.db.prepare(ortstmt.stmtBuilder
  775 			(ortstmt.ortstmt.STMT_session_INSERT));
  776 
  777 		parms.push(v1);
  778 		parms.push(v2);
  779 		parms.push(v3);
  780 
  781 		try {
  782 			info = stmt.run(parms);
  783 		} catch (er) {
  784 			if (er.code === 'SQLITE_CONSTRAINT_UNIQUE' ||
  785 			    er.code === 'SQLITE_CONSTRAINT_FOREIGNKEY')
  786 				return BigInt(-1);
  787 			throw er;
  788 		}
  789 
  790 		return BigInt(info.lastInsertRowid.toString());
  791 	}
  792 
  793 	/**
  794 	 * Search for company's logged-in users.
  795 	 * The callback is called during an implicit transaction: thus, it 
  796 	 * should not invoke any database modifications or risk deadlock.
  797 	 * @param v1 user.company.name
  798 	 * @param v2 mtime
  799 	 * @param cb Callback with retrieved data.
  800 	 * @throws Throws on database error.
  801 	 */
  802 	db_session_iterate_foo(v1: string, v2: bigint,
  803 		cb: (res: ortns.session) => void): void
  804 	{
  805 		const parms: any[] = [];
  806 		const stmt: Database.Statement =
  807 			this.#o.db.prepare(ortstmt.stmtBuilder
  808 			(ortstmt.ortstmt.STMT_session_BY_SEARCH_0));
  809 		stmt.raw(true);
  810 
  811 		parms.push(v1);
  812 		parms.push(v2);
  813 
  814 		for (const cols of stmt.iterate(parms)) {
  815 			const obj: ortns.sessionData =
  816 				this.db_session_fill({row: <any>cols, pos: 0});
  817 			cb(new ortns.session(this.#role, obj));
  818 		}
  819 	}
  820 
  821 	/**
  822 	 * @param v1 constraint id (eq)
  823 	 * @throws Throws on database error.
  824 	 */
  825 	db_session_delete_by_id_eq(v1: bigint): void
  826 	{
  827 		const parms: any[] = [];
  828 		let info: Database.RunResult;
  829 		const stmt: Database.Statement =
  830 			this.#o.db.prepare(ortstmt.stmtBuilder
  831 			(ortstmt.ortstmt.STMT_session_DELETE_0));
  832 
  833 		parms.push(v1);
  834 
  835 		stmt.run(parms);
  836 	}
  837 }
  838 
  839 /**
  840  * Interface configuration.
  841  */
  842 export interface ortargs
  843 {
  844 	/**
  845 	 * The number of rounds when bcrypting passwords.
  846 	 */
  847 	bcrypt_cost: number;
  848 }
  849 
  850 /**
  851  * Application-wide database instance. There should only be one of these 
  852  * per server.
  853  */
  854 export class ortdb
  855 {
  856 	readonly args: ortargs;
  857 	readonly db: Database.Database;
  858 
  859 	/**
  860 	 * The version of ort-nodejs used to create the module.
  861 	 */
  862 	readonly version: string = '0.14.0';
  863 
  864 	/**
  865 	 * The numeric version of ort-nodejs used to create the module.
  866 	 */
  867 	readonly vstamp: number = 11501;
  868 
  869 	/**
  870 	 * Do not call this: use {@link ort} instead.
  871 	 */
  872 	constructor(dbname: string, args?: ortargs)
  873 	{
  874 		this.db = new Database(dbname);
  875 		this.db.defaultSafeIntegers(true);
  876 		if (typeof args !== 'undefined') {
  877 			this.args = Object.assign({}, args);
  878 		} else {
  879 			this.args = { bcrypt_cost: 10 };
  880 		}
  881 	}
  882 
  883 	/**
  884 	 * Connect to the database.  This should be invoked for each request.  
  885 	 * In applications not having a request, this corresponds to a single 
  886 	 * operator sequence.  If roles are enabled, the connection will 
  887 	 * begin in the "default" role.
  888 	 */
  889 	connect(): ortctx
  890 	{
  891 		return new ortctx(this);
  892 	}
  893 }
  894 
  895 /**
  896  * Create an application-wide database instance. This should only be 
  897  * called once per server.
  898  * @param dbname An existing sqlite3 database.
  899  * @param args Optional configuration parameters. If not given, the 
  900  * number of bcrypt rounds defaults to 10.
  901  * @throws Throws on database error.
  902  */
  903 export function ort(dbname: string, args?: optargs): ortdb
  904 {
  905 	return new ortdb(dbname, args);
  906 }