diff --git a/source/conf.ts b/source/conf.ts index 24e47a7..0389c2b 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -111,10 +111,30 @@ namespace _espe.conf })) (conf_raw["server"] ?? {}) ), "database": ( - ((node_database) => ({ - "kind": (node_database["kind"] ?? "sqlite"), - "data": node_database["data"], - })) (conf_raw["database"] ?? {}) + ((node_database) => { + const kind : string = (node_database["kind"] ?? "sqlite"); + const node_database_data_raw = (node_database["data"] ?? {}); + switch (kind) { + case "sqlite": { + return { + "kind": kind, + "data": { + "path": (node_database_data_raw["path"] ?? "data.sqlite"), + } + }; + } + case "postgresql": { + return { + "kind": kind, + "data": node_database_data_raw, + }; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["database"] ?? {}) ), "email_sending": ( ((node_email_sending) => ({ diff --git a/source/database.ts b/source/database.ts new file mode 100644 index 0000000..8ad002e --- /dev/null +++ b/source/database.ts @@ -0,0 +1,251 @@ +namespace _espe.database +{ + + /** + */ + enum enum_revision { + r0 = 0, + r1 = 1, + } + + + /** + */ + const _revision_order : Array = [ + enum_revision.r0, + enum_revision.r1, + ]; + + + /** + */ + export function get_implementation( + ) : lib_plankton.database.type_database + { + switch (_espe.conf.get().database.kind) { + case "sqlite": { + return lib_plankton.database.sqlite_database( + { + "path": _espe.conf.get().database.data["path"], + "verbose": false, + } + ); + break; + } + default: { + throw (new Error("database implementation not available: " + _espe.conf.get().database.kind)); + } + } + } + + + /** + */ + function get_revision( + ) : Promise + { + return ( + ( + get_implementation().query_select( + { + "source": "meta", + "fields": ["revision"], + } + ) + .then( + (rows) => Promise.resolve(rows[0]["revision"]) + ) + .catch( + () => Promise.resolve(0) + ) + ) + .then( + (revision_raw) => Promise.resolve(revision_raw) + ) + ); + } + + + /** + */ + async function advance( + ) : Promise + { + const implementation : lib_plankton.database.type_database = get_implementation(); + + const revision_current : enum_revision = await get_revision(); + const index_current : int = _revision_order.indexOf(revision_current); + const index_next : (null | int) = ( + (index_current < (_revision_order.length - 1)) + ? (index_current + 1) + : null + ); + const revision_next : (null | enum_revision) = ( + (index_next !== null) + ? _revision_order[index_next] + : null + ); + if (revision_next !== null) { + lib_plankton.log.notice( + "database_advancement_necessary", + { + "revision_current": revision_current, + "revision_next": revision_next, + } + ); + switch (revision_next) { + case enum_revision.r1: { + // structure + { + await implementation.query_create_table( + { + "name": "meta", + "data_fields": [ + { + "name": "revision", + "type": lib_plankton.database.enum_type.integer, + "nullable": false, + }, + ], + } + ); + await implementation.query_create_table( + { + "name": "members", + "key_field": { + "name": "id" + }, + "data_fields": [ + { + "name": "membership_number", + "type": lib_plankton.database.enum_type.string_short, + "nullable": false + }, + { + "name": "enabled", + "type": lib_plankton.database.enum_type.boolean, + "nullable": false + }, + { + "name": "name_login", + "type": lib_plankton.database.enum_type.string_short, + "nullable": true + }, + { + "name": "password_image", + "type": lib_plankton.database.enum_type.string_medium, + "nullable": true + }, + { + "name": "name_real_value", + "type": lib_plankton.database.enum_type.string_medium, + "nullable": false + }, + { + "name": "name_real_extension", + "type": lib_plankton.database.enum_type.string_short, + "nullable": true + }, + { + "name": "name_display", + "type": lib_plankton.database.enum_type.string_medium, + "nullable": true + }, + { + "name": "salutation", + "type": lib_plankton.database.enum_type.string_short, + "nullable": true + }, + { + "name": "email_address_private_value", + "type": lib_plankton.database.enum_type.string_short, + "nullable": true + }, + { + "name": "email_address_numberbased_use", + "type": lib_plankton.database.enum_type.boolean, + "nullable": false + }, + { + "name": "email_address_namebased_use", + "type": lib_plankton.database.enum_type.boolean, + "nullable": false + }, + { + "name": "email_redirect_to_private", + "type": lib_plankton.database.enum_type.boolean, + "nullable": false + } + ], + "constraints": [ + { + "kind": "unique", + "parameters": { + "fields": ["membership_number"] + } + }, + { + "kind": "unique", + "parameters": { + "fields": ["name_real_value","name_real_extension"] + } + }, + { + "kind": "unique", + "parameters": { + "fields": ["name_login"] + } + } + ] + } + ); + } + // data + { + await implementation.query_insert( + { + "table_name": "meta", + "values": { + "revision": revision_next, + } + } + ); + } + return Promise.resolve(true); + break; + } + default: { + return Promise.reject("unhandled advancement step"); + break; + } + } + } + else { + lib_plankton.log.notice( + "database_up_to_date", + { + "revision_current": revision_current, + } + ); + return Promise.resolve(false); + } + } + + + /** + */ + export async function advance_all( + ) : Promise + { + while (true) { + const modified : boolean = await advance(); + if (modified) { + // do nothing + } + else { + break; + } + } + } + +} diff --git a/source/helpers.ts b/source/helpers.ts index c547baa..05b2802 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -50,24 +50,12 @@ namespace _espe.helpers /** + * @deprecated */ export function database_implementation( ) : lib_plankton.database.type_database { - switch (_espe.conf.get().database.kind) { - case "sqlite": { - return lib_plankton.database.sqlite_database( - { - "path": _espe.conf.get().database.data["path"], - "verbose": false, - } - ); - break; - } - default: { - throw (new Error("database implementation not available: " + _espe.conf.get().database.kind)); - } - } + return _espe.database.get_implementation(); } diff --git a/source/main.ts b/source/main.ts index 8905028..3653000 100644 --- a/source/main.ts +++ b/source/main.ts @@ -125,6 +125,10 @@ async function main( ), ] ); + + // prepare database + await _espe.database.advance_all(); + switch (args["action"]) { default: { process.stderr.write("invalid action: " + args["action"] + "\n"); diff --git a/tools/makefile b/tools/makefile index c0b19d1..8cdf9da 100644 --- a/tools/makefile +++ b/tools/makefile @@ -27,6 +27,7 @@ node_modules: ${dir_temp}/espe-unlinked.js: \ ${dir_lib}/plankton/plankton.d.ts \ ${dir_source}/helpers.ts \ + ${dir_source}/database.ts \ ${dir_source}/service-member.ts \ ${dir_source}/service-admin.ts \ ${dir_source}/api/base.ts \