namespace _heimdall.helpers.sqlite
{
	
	/**
	 */
	export type type_query_raw = {
		template : string;
		arguments : Record<string, any>;
	};
	
	
	/**
	 */
	type type_query_transformed = {
		template : string;
		arguments : Record<string, any>;
	};
	
	
	/**
	 */
	function query_transform(
		query_raw : type_query_raw
	) : type_query_transformed
	{
		return {
			"template": query_raw.template,
			"arguments": lib_plankton.call.convey(
				query_raw.arguments,
				[
					x => Object.entries(x),
					x => (
						x.map(
							([key, value]) => ([
								(":" + key),
								value
							])
						)
					),
					x => Object.fromEntries(x),
				]
			),
		};
	}
	
	
	/**
	 */
	function execute(
		database_path : string,
		action : ((handle) => Promise<void>),
	) : Promise<void>
	{
		return (
			new Promise<void>(
				async (resolve, reject) => {
					const nm_sqlite3 = require("sqlite3");
					const handle = new nm_sqlite3.Database(database_path);
					try {
						await action(handle);
						handle.close();
						resolve(undefined);
					}
					catch (error) {
						handle.close();
						reject(error);
					}
				}
			)
		);
	}
	
	
	/**
	 * for CREATE TABLE, DROP TABLE, etc.
	 */
	export async function query_set(
		database_path : string,
		query_raw : type_query_raw
	) : Promise<any>
	{
		const query_transformed : type_query_transformed = query_transform(query_raw);
		await execute(
			database_path,
			(handle) => new Promise<void>(
				(resolve, reject) => {
					handle.run(
						query_transformed.template,
						query_transformed.arguments,
						(error) => {
							if (error) {
								reject(error);
							}
							else {
								resolve(undefined);
							}
						}
					);
				}
			)
		);
		return undefined;
	}
	
	
	/**
	 * for INSERT, UPDATE, DELETE
	 */
	export async function query_put(
		database_path : string,
		query_raw : type_query_raw
	) : Promise<{id : (null | int); affected : (null | int);}>
	{
		let result : {id : (null | int); affected : (null | int);};
		const query_transformed : type_query_transformed = query_transform(query_raw);
		await execute(
			database_path,
			(handle) => new Promise<void>(
				(resolve, reject) => {
					handle.run(
						query_transformed.template,
						query_transformed.arguments,
						function (error) {
							if (error) {
								reject(error);
							}
							else {
								result = {
									"id": this.lastID,
									"affected": this.changes,
								};
								resolve(undefined);
							}
						}
					);
				}
			)
		);
		return result;
	}
	
	
	/**
	 * for SELECT
	 */
	export async function query_get(
		database_path : string,
		query_raw : type_query_raw
	) : Promise<Array<Array<any>>>
	{
		const query_transformed : type_query_transformed = query_transform(query_raw);
		let rows : Array<Array<any>> = [];
		await execute(
			database_path,
			(handle) => new Promise<void>(
				(resolve, reject) => {
					handle.all(
						query_transformed.template,
						query_transformed.arguments,
						(error, row) => {
							if (error) {
								reject(error);
							}
							else {
								rows.push(row);
								resolve(undefined);
							}
						}
					);
				}
			)
		);
		return rows;
	}
	
}
