diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 8af13b1..64cf666 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -1156,37 +1156,44 @@ declare namespace lib_plankton.database { function sql_common_value_format(value: any): string; /** */ - function sql_common_formulation_create_table(description_create_table: type_description_create_table, options: { - auto_increment_keyword: string; - omit_comments: boolean; - type_map: Record; + function sql_common_formulation_create_table(description_create_table: type_description_create_table, options?: { + auto_increment_keyword?: string; + omit_comments?: boolean; + type_map?: Record; + wrap_names?: boolean; }): type_query; /** */ - function sql_common_formulation_insert(description_insert: type_description_insert): type_query; + function sql_common_formulation_insert(description_insert: type_description_insert, options?: { + wrap_names?: boolean; + }): type_query; /** */ - function sql_common_formulation_update(description_update: type_description_update): type_query; + function sql_common_formulation_update(description_update: type_description_update, options?: { + wrap_names?: boolean; + }): type_query; /** */ - function sql_common_formulation_delete(description_delete: type_description_delete): type_query; + function sql_common_formulation_delete(description_delete: type_description_delete, options?: { + wrap_names?: boolean; + }): type_query; /** */ - function sql_common_formulation_select(description_select: type_description_select): type_query; + function sql_common_formulation_select(description_select: type_description_select, options?: { + wrap_names?: boolean; + }): type_query; } declare namespace lib_plankton.database { /** */ type type_sqlite_subject = { path: string; - verbose: boolean; handle: any; }; /** */ type type_sqlite_parameters = { path: string; - verbose?: boolean; }; /** */ @@ -1254,6 +1261,98 @@ declare namespace lib_plankton.database { query_select(description_select: any): Promise[]>; } } +declare namespace lib_plankton.database { + /** + * @todo + */ + type type_postgresql_subject = { + host: string; + port: int; + username: string; + password: string; + schema: string; + client: any; + }; + /** + * @todo + */ + type type_postgresql_parameters = { + host: string; + port?: int; + username: string; + password: string; + schema: string; + }; + /** + * @see https://node-postgres.com/apis/client#new-client + */ + function postgresql_make(parameters: type_postgresql_parameters): type_postgresql_subject; + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_get(subject: type_postgresql_subject, query: type_query): Promise; + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_put(subject: type_postgresql_subject, query: type_query): Promise; + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_set(subject: type_postgresql_subject, query: type_query): Promise; + /** + */ + function postgresql_formulation_create_table(description_create_table: type_description_create_table): type_query; + /** + */ + function postgresql_query_create_table(subject: type_postgresql_subject, description: type_description_create_table): Promise; + /** + */ + function postgresql_formulation_insert(description_insert: type_description_insert): type_query; + /** + */ + function postgresql_query_insert(subject: type_postgresql_subject, description_insert: type_description_insert): Promise; + /** + */ + function postgresql_formulation_update(description_update: type_description_update): type_query; + /** + */ + function postgresql_query_update(subject: type_postgresql_subject, description_update: type_description_update): Promise; + /** + */ + function postgresql_formulation_delete(description_delete: type_description_delete): type_query; + /** + */ + function postgresql_query_delete(subject: type_postgresql_subject, description_delete: type_description_delete): Promise; + /** + */ + function postgresql_formulation_select(description_select: type_description_select): type_query; + /** + */ + function postgresql_query_select(subject: type_postgresql_subject, description_select: type_description_select): Promise>>; + /** + */ + function postgresql_database(parameters: type_postgresql_parameters): type_database; +} +declare namespace lib_plankton.database { + /** + * @author fenris + */ + class class_postgresql implements interface_database { + private subject; + constructor(parameters: type_postgresql_parameters); + query_free_get(query: any): Promise; + query_free_put(query: any): Promise; + query_free_set(query: any): Promise; + query_create_table(description_create_table: any): Promise; + query_insert(description_insert: any): Promise; + query_update(description_update: any): Promise; + query_delete(description_delete: any): Promise; + query_select(description_select: any): Promise[]>; + } +} declare namespace lib_plankton.database { /** * @todo diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 8058bfa..08be59b 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -3337,8 +3337,18 @@ var lib_plankton; database.sql_common_value_format = sql_common_value_format; /** */ - function sql_common_formulation_create_table(description_create_table, options) { - var _a, _b, _c, _d, _e, _f; + function wrap_name(name, options = {}) { + options = Object.assign({ + "active": true, + }, options); + return (options.active + ? ("`" + name + "`") + : name); + } + /** + */ + function sql_common_formulation_create_table(description_create_table, options = {}) { + var _a, _b, _c, _d, _e; options = Object.assign({ "auto_increment_keyword": "AUTO INCREMENT", "omit_comments": false, @@ -3350,10 +3360,11 @@ var lib_plankton; "string_long": "TEXT", "float": "REAL", }, + "wrap_names": true, }, options); return { - "template": lib_plankton.string.coin("CREATE TABLE\n\t`{{name}}`(\n{{entries}}\n\t){{comment}}\n;", { - "name": description_create_table.name, + "template": lib_plankton.string.coin("CREATE TABLE\n\t{{name}}(\n{{entries}}\n\t){{comment}}\n;", { + "name": wrap_name(description_create_table.name, { "active": options.wrap_names }), "comment": ((options.omit_comments || (((_a = description_create_table.description) !== null && _a !== void 0 ? _a : null) === null)) @@ -3365,31 +3376,35 @@ var lib_plankton; // key field .concat((((_b = description_create_table.key_field) !== null && _b !== void 0 ? _b : null) === null) ? [] - : lib_plankton.string.coin("`{{name}}` {{parameters}}", { - "name": description_create_table.key_field.name, + : lib_plankton.string.coin("{{name}} {{parameters}}", { + "name": wrap_name(description_create_table.key_field.name, { "active": options.wrap_names }), "parameters": (([] + /* // type - .concat([ - options.type_map[(_c = description_create_table.key_field.type) !== null && _c !== void 0 ? _c : "integer"], - ]) - // primary key - .concat([ - "PRIMARY KEY", - ]) + .concat( + [ + options.type_map[description_create_table.key_field.type ?? "integer"], + ] + ) + */ // auto increment - .concat((((_d = description_create_table.key_field.auto_increment) !== null && _d !== void 0 ? _d : true) === null) + .concat((((_c = description_create_table.key_field.auto_increment) !== null && _c !== void 0 ? _c : true) === null) ? [] : [ options.auto_increment_keyword, - ])) + ]) + // primary key + .concat([ + "PRIMARY KEY", + ])) .join(" ")), })) // data fields - .concat(((_e = description_create_table.data_fields) !== null && _e !== void 0 ? _e : []) + .concat(((_d = description_create_table.data_fields) !== null && _d !== void 0 ? _d : []) .map((data_field) => { var _a, _b; - return lib_plankton.string.coin("`{{name}}` {{parameters}}", { - "name": data_field.name, + return lib_plankton.string.coin("{{name}} {{parameters}}", { + "name": wrap_name(data_field.name, { "active": options.wrap_names }), "parameters": (([] // type .concat([ @@ -3421,7 +3436,7 @@ var lib_plankton; }); })) // constraints - .concat(((_f = description_create_table.constraints) !== null && _f !== void 0 ? _f : []) + .concat(((_e = description_create_table.constraints) !== null && _e !== void 0 ? _e : []) .map((constraint) => { switch (constraint.kind) { default: { @@ -3429,13 +3444,13 @@ var lib_plankton; break; } case "foreign_key": { - return lib_plankton.string.coin("FOREIGN KEY ({{fields}}) REFERENCES `{{reference_name}}`({{reference_fields}})", { + return lib_plankton.string.coin("FOREIGN KEY ({{fields}}) REFERENCES {{reference_name}}({{reference_fields}})", { "fields": (constraint.parameters["fields"] - .map(x => ('`' + x + '`')) + .map(x => wrap_name(x, { "active": options.wrap_names })) .join(",")), - "reference_name": constraint.parameters["reference"]["name"], + "reference_name": wrap_name(constraint.parameters["reference"]["name"], { "active": options.wrap_names }), "reference_fields": (constraint.parameters["reference"]["fields"] - .map(x => ('`' + x + '`')) + .map(x => wrap_name(x, { "active": options.wrap_names })) .join(",")), }); break; @@ -3443,7 +3458,7 @@ var lib_plankton; case "unique": { return lib_plankton.string.coin("UNIQUE ({{fields}})", { "fields": (constraint.parameters["fields"] - .map(x => ('`' + x + '`')) + .map(x => wrap_name(x, { "active": options.wrap_names })) .join(",")), }); break; @@ -3459,14 +3474,17 @@ var lib_plankton; database.sql_common_formulation_create_table = sql_common_formulation_create_table; /** */ - function sql_common_formulation_insert(description_insert) { + function sql_common_formulation_insert(description_insert, options = {}) { + options = Object.assign({ + "wrap_names": true, + }, options); const field_names = Object.keys(description_insert.values); return { - "template": lib_plankton.string.coin("INSERT INTO `{{table_name}}`({{schema}}) VALUES ({{values}});", { - "table_name": description_insert.table_name, + "template": lib_plankton.string.coin("INSERT INTO {{table_name}}({{schema}}) VALUES ({{values}});", { + "table_name": wrap_name(description_insert.table_name, { "active": options.wrap_names }), "schema": (field_names - .map((field_name) => lib_plankton.string.coin("`{{name}}`", { - "name": field_name, + .map((field_name) => lib_plankton.string.coin("{{name}}", { + "name": wrap_name(field_name, { "active": options.wrap_names }), })) .join(",")), "values": (field_names @@ -3487,15 +3505,19 @@ var lib_plankton; database.sql_common_formulation_insert = sql_common_formulation_insert; /** */ - function sql_common_formulation_update(description_update) { + function sql_common_formulation_update(description_update, options = {}) { var _a, _b; + options = Object.assign({ + "wrap_names": true, + }, options); const field_names = Object.keys(description_update.values); return { - "template": lib_plankton.string.coin("UPDATE `{{table_name}}` SET {{assignments}}{{macro_where}};", { - "table_name": description_update.table_name, + "template": lib_plankton.string.coin("UPDATE {{table_name}} SET {{assignments}}{{macro_where}};", { + "table_name": wrap_name(description_update.table_name, { "active": options.wrap_names }), "assignments": (field_names - .map((field_name) => lib_plankton.string.coin("`{{name}}` = $value_{{name}}", { - "name": field_name, + .map((field_name) => lib_plankton.string.coin("{{name}} = $value_{{suffix}}", { + "name": wrap_name(field_name, { "active": options.wrap_names }), + "suffix": field_name, })) .join(", ")), "macro_where": ((((_a = description_update.condition) !== null && _a !== void 0 ? _a : null) === null) @@ -3516,11 +3538,14 @@ var lib_plankton; database.sql_common_formulation_update = sql_common_formulation_update; /** */ - function sql_common_formulation_delete(description_delete) { + function sql_common_formulation_delete(description_delete, options = {}) { var _a, _b; + options = Object.assign({ + "wrap_names": true, + }, options); return { - "template": lib_plankton.string.coin("DELETE FROM `{{table_name}}`{{macro_where}};", { - "table_name": description_delete.table_name, + "template": lib_plankton.string.coin("DELETE FROM {{table_name}}{{macro_where}};", { + "table_name": wrap_name(description_delete.table_name, { "active": options.wrap_names }), "macro_where": ((((_a = description_delete.condition) !== null && _a !== void 0 ? _a : null) === null) ? "" : lib_plankton.string.coin(" WHERE {{expression}}", { @@ -3533,15 +3558,18 @@ var lib_plankton; database.sql_common_formulation_delete = sql_common_formulation_delete; /** */ - function sql_common_formulation_select(description_select) { + function sql_common_formulation_select(description_select, options = {}) { var _a, _b, _c, _d, _e, _f, _g; + options = Object.assign({ + "wrap_names": true, + }, options); return { - "template": lib_plankton.string.coin("SELECT {{fields}} FROM `{{source}}`{{macro_where}}{{macro_group_by}}{{macro_having}}{{macro_order_by}}{{macro_limit}};", { - "source": description_select.source, + "template": lib_plankton.string.coin("SELECT {{fields}} FROM {{source}}{{macro_where}}{{macro_group_by}}{{macro_having}}{{macro_order_by}}{{macro_limit}};", { + "source": wrap_name(description_select.source, { "active": options.wrap_names }), "fields": ((((_a = description_select.fields) !== null && _a !== void 0 ? _a : null) === null) ? "*" : (description_select.fields - .map(field_name => lib_plankton.string.coin("`{{name}}`", { "name": field_name })) + .map(field_name => lib_plankton.string.coin("{{name}}", { "name": wrap_name(field_name, { "active": options.wrap_names }) })) .join(","))), "macro_where": ((((_b = description_select.condition) !== null && _b !== void 0 ? _b : null) === null) ? "" @@ -3601,10 +3629,8 @@ var lib_plankton; /** */ function sqlite_make(parameters) { - var _a; return { "path": parameters.path, - "verbose": ((_a = parameters.verbose) !== null && _a !== void 0 ? _a : false), "handle": null, }; } @@ -3629,22 +3655,25 @@ var lib_plankton; * @author fenris */ function sqlite_adjust_query(subject, query) { - if (subject.verbose) { - console.info(query); - } - return { + const query_adjusted = { "template": query.template, - "arguments": Object.fromEntries(Object.entries(query.arguments).map(([key, value]) => ([ - ('$' + key), + "arguments": Object.fromEntries(Object.entries(query.arguments) + .map(([key, value]) => ([ + ("$" + key), (((value === null) || (value === undefined)) ? null - : ((typeof (value) === 'boolean') - ? (value ? '1' : '0') + : ((typeof (value) === "boolean") + ? (value ? "1" : "0") : value.toString())) ]))), }; + lib_plankton.log.debug("database_sqlite_query", { + "original": query, + "adjusted": query_adjusted, + }); + return query_adjusted; } /** * @author fenris @@ -3714,7 +3743,7 @@ var lib_plankton; */ function sqlite_formulation_create_table(description_create_table) { return database.sql_common_formulation_create_table(description_create_table, { - "auto_increment_keyword": "AUTOINCREMENT", + "auto_increment_keyword": "INTEGER NOT NULL AUTOINCREMENT", "omit_comments": true, "type_map": { "boolean": "INTEGER", @@ -3856,6 +3885,286 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:database«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var database; + (function (database) { + /** + * @see https://node-postgres.com/apis/client#new-client + */ + function postgresql_make(parameters) { + var _a; + return { + "host": parameters.host, + "port": ((_a = parameters.port) !== null && _a !== void 0 ? _a : 5432), + "username": parameters.username, + "password": parameters.password, + "schema": parameters.schema, + "client": null, + }; + } + database.postgresql_make = postgresql_make; + /** + */ + function postgresql_init(subject) { + return __awaiter(this, void 0, void 0, function* () { + if (subject.client === null) { + const nm_pg = require("pg"); + subject.client = (new nm_pg.Client({ + "host": subject.host, + "port": subject.port, + "database": subject.schema, + "user": subject.username, + "password": subject.password, + })); + } + else { + // do nothing + } + return Promise.resolve(undefined); + }); + } + /** + * @author fenris + */ + function postgresql_adjust_query(subject, query) { + let query_adjusted = { + "template": query.template, + "arguments": [] + }; + let index = 1; + while (true) { + const regexp = (new RegExp("\\$([a-zA-Z_][0-9a-zA-Z_]*)", "g")); + const matching = regexp.exec(query_adjusted.template); + if (matching === null) { + break; + } + else { + const part = matching[0]; + const name = matching[1]; + query_adjusted.template = (query_adjusted.template.slice(0, matching.index) + + + ("$" + index.toFixed(0)) + + + query_adjusted.template.slice(matching.index + part.length)); + query_adjusted.arguments.push(query.arguments[name]); + index += 1; + } + } + lib_plankton.log.debug("database_postgresql_query", { + "original": query, + "adjusted": query_adjusted, + }); + return query_adjusted; + } + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_get(subject, query) { + return __awaiter(this, void 0, void 0, function* () { + yield postgresql_init(subject); + const query_adjusted = postgresql_adjust_query(subject, query); + yield subject.client.connect(); + const result = yield subject.client.query({ + "text": query_adjusted.template, + "values": query_adjusted.arguments, + }); + yield subject.client.end(); + return result["rows"]; + }); + } + database.postgresql_query_free_get = postgresql_query_free_get; + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_put(subject, query) { + return __awaiter(this, void 0, void 0, function* () { + yield postgresql_init(subject); + const query_adjusted = postgresql_adjust_query(subject, query); + yield subject.client.connect(); + const result1 = yield subject.client.query({ + "text": query_adjusted.template, + "values": query_adjusted.arguments, + }); + const result2 = yield subject.client.query({ + "text": "LASTVAL();", + "values": {}, + }); + yield subject.client.end(); + return result2["rows"][0]["LASTVAL"]; + }); + } + database.postgresql_query_free_put = postgresql_query_free_put; + /** + * @author fenris + * @see https://node-postgres.com/apis/client#clientquery + */ + function postgresql_query_free_set(subject, query) { + return __awaiter(this, void 0, void 0, function* () { + yield postgresql_init(subject); + const query_adjusted = postgresql_adjust_query(subject, query); + yield subject.client.connect(); + const result = yield subject.client.query({ + "text": query_adjusted.template, + "values": query_adjusted.arguments, + }); + yield subject.client.end(); + return result["rowCount"]; + }); + } + database.postgresql_query_free_set = postgresql_query_free_set; + /** + */ + function postgresql_formulation_create_table(description_create_table) { + return database.sql_common_formulation_create_table(description_create_table, { + "auto_increment_keyword": "SERIAL", + "omit_comments": false, + "type_map": { + "boolean": "BOOLEAN", + "integer": "INTEGER", + "string_short": "VARCHAR(63)", + "string_medium": "VARCHAR(255)", + "string_long": "TEXT", + "float": "REAL", + }, + "wrap_names": false, + }); + } + database.postgresql_formulation_create_table = postgresql_formulation_create_table; + /** + */ + function postgresql_query_create_table(subject, description) { + return (postgresql_query_free_set(subject, postgresql_formulation_create_table(description)) + .then(x => Promise.resolve(undefined))); + } + database.postgresql_query_create_table = postgresql_query_create_table; + /** + */ + function postgresql_formulation_insert(description_insert) { + return database.sql_common_formulation_insert(description_insert, { "wrap_names": false }); + } + database.postgresql_formulation_insert = postgresql_formulation_insert; + /** + */ + function postgresql_query_insert(subject, description_insert) { + return postgresql_query_free_put(subject, postgresql_formulation_insert(description_insert)); + } + database.postgresql_query_insert = postgresql_query_insert; + /** + */ + function postgresql_formulation_update(description_update) { + return database.sql_common_formulation_update(description_update, { "wrap_names": false }); + } + database.postgresql_formulation_update = postgresql_formulation_update; + /** + */ + function postgresql_query_update(subject, description_update) { + return postgresql_query_free_set(subject, postgresql_formulation_update(description_update)); + } + database.postgresql_query_update = postgresql_query_update; + /** + */ + function postgresql_formulation_delete(description_delete) { + return database.sql_common_formulation_delete(description_delete, { "wrap_names": false }); + } + database.postgresql_formulation_delete = postgresql_formulation_delete; + /** + */ + function postgresql_query_delete(subject, description_delete) { + return postgresql_query_free_set(subject, postgresql_formulation_delete(description_delete)); + } + database.postgresql_query_delete = postgresql_query_delete; + /** + */ + function postgresql_formulation_select(description_select) { + return database.sql_common_formulation_select(description_select, { "wrap_names": false }); + } + database.postgresql_formulation_select = postgresql_formulation_select; + /** + */ + function postgresql_query_select(subject, description_select) { + return postgresql_query_free_get(subject, postgresql_formulation_select(description_select)); + } + database.postgresql_query_select = postgresql_query_select; + /** + */ + function postgresql_database(parameters) { + const subject = postgresql_make(parameters); + return { + "query_free_get": (query) => postgresql_query_free_get(subject, query), + "query_free_put": (query) => postgresql_query_free_put(subject, query), + "query_free_set": (query) => postgresql_query_free_set(subject, query), + "query_create_table": (description_create_table) => postgresql_query_create_table(subject, description_create_table), + "query_insert": (description_insert) => postgresql_query_insert(subject, description_insert), + "query_update": (description_update) => postgresql_query_update(subject, description_update), + "query_delete": (description_delete) => postgresql_query_delete(subject, description_delete), + "query_select": (description_select) => postgresql_query_select(subject, description_select), + }; + } + database.postgresql_database = postgresql_database; + })(database = lib_plankton.database || (lib_plankton.database = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:database«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:database« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:database« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:database«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var database; + (function (database) { + /** + * @author fenris + */ + class class_postgresql { + constructor(parameters) { this.subject = database.postgresql_make(parameters); } + query_free_get(query) { return database.postgresql_query_free_get(this.subject, query); } + query_free_put(query) { return database.postgresql_query_free_put(this.subject, query); } + query_free_set(query) { return database.postgresql_query_free_set(this.subject, query); } + query_create_table(description_create_table) { return database.postgresql_query_create_table(this.subject, description_create_table); } + query_insert(description_insert) { return database.postgresql_query_insert(this.subject, description_insert); } + query_update(description_update) { return database.postgresql_query_update(this.subject, description_update); } + query_delete(description_delete) { return database.postgresql_query_delete(this.subject, description_delete); } + query_select(description_select) { return database.postgresql_query_select(this.subject, description_select); } + } + database.class_postgresql = class_postgresql; + })(database = lib_plankton.database || (lib_plankton.database = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:database«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:database« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:database« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with »bacterio-plankton:database«. If not, see . */