[mod] datenbank-steuerung:automatische migrationen
This commit is contained in:
parent
adf0e9675f
commit
2b7d791da2
|
|
@ -111,10 +111,30 @@ namespace _espe.conf
|
||||||
})) (conf_raw["server"] ?? {})
|
})) (conf_raw["server"] ?? {})
|
||||||
),
|
),
|
||||||
"database": (
|
"database": (
|
||||||
((node_database) => ({
|
((node_database) => {
|
||||||
"kind": (node_database["kind"] ?? "sqlite"),
|
const kind : string = (node_database["kind"] ?? "sqlite");
|
||||||
"data": node_database["data"],
|
const node_database_data_raw = (node_database["data"] ?? {});
|
||||||
})) (conf_raw["database"] ?? {})
|
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": (
|
"email_sending": (
|
||||||
((node_email_sending) => ({
|
((node_email_sending) => ({
|
||||||
|
|
|
||||||
251
source/database.ts
Normal file
251
source/database.ts
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
namespace _espe.database
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
enum enum_revision {
|
||||||
|
r0 = 0,
|
||||||
|
r1 = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
const _revision_order : Array<enum_revision> = [
|
||||||
|
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<enum_revision>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(
|
||||||
|
get_implementation().query_select(
|
||||||
|
{
|
||||||
|
"source": "meta",
|
||||||
|
"fields": ["revision"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then<int>(
|
||||||
|
(rows) => Promise.resolve<int>(rows[0]["revision"])
|
||||||
|
)
|
||||||
|
.catch<int>(
|
||||||
|
() => Promise.resolve<int>(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then<enum_revision>(
|
||||||
|
(revision_raw) => Promise.resolve<enum_revision>(revision_raw)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async function advance(
|
||||||
|
) : Promise<boolean>
|
||||||
|
{
|
||||||
|
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<boolean>(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return Promise.reject<boolean>("unhandled advancement step");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lib_plankton.log.notice(
|
||||||
|
"database_up_to_date",
|
||||||
|
{
|
||||||
|
"revision_current": revision_current,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return Promise.resolve<boolean>(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function advance_all(
|
||||||
|
) : Promise<void>
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
const modified : boolean = await advance();
|
||||||
|
if (modified) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -50,24 +50,12 @@ namespace _espe.helpers
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
export function database_implementation(
|
export function database_implementation(
|
||||||
) : lib_plankton.database.type_database
|
) : lib_plankton.database.type_database
|
||||||
{
|
{
|
||||||
switch (_espe.conf.get().database.kind) {
|
return _espe.database.get_implementation();
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,10 @@ async function main(
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// prepare database
|
||||||
|
await _espe.database.advance_all();
|
||||||
|
|
||||||
switch (args["action"]) {
|
switch (args["action"]) {
|
||||||
default: {
|
default: {
|
||||||
process.stderr.write("invalid action: " + args["action"] + "\n");
|
process.stderr.write("invalid action: " + args["action"] + "\n");
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ node_modules:
|
||||||
${dir_temp}/espe-unlinked.js: \
|
${dir_temp}/espe-unlinked.js: \
|
||||||
${dir_lib}/plankton/plankton.d.ts \
|
${dir_lib}/plankton/plankton.d.ts \
|
||||||
${dir_source}/helpers.ts \
|
${dir_source}/helpers.ts \
|
||||||
|
${dir_source}/database.ts \
|
||||||
${dir_source}/service-member.ts \
|
${dir_source}/service-member.ts \
|
||||||
${dir_source}/service-admin.ts \
|
${dir_source}/service-admin.ts \
|
||||||
${dir_source}/api/base.ts \
|
${dir_source}/api/base.ts \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue