@v1nt1248/3nclient-lib 0.0.13 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/libs/index.d.ts +3 -4
  3. package/dist/libs/ipc-service-caller.d.ts +2 -3
  4. package/dist/libs/ipc-service.d.ts +5 -6
  5. package/dist/libs/serialization-for-ipc/copy-json.d.ts +8 -0
  6. package/dist/libs/serialization-for-ipc/protobuf-type.d.ts +10 -0
  7. package/dist/libs/sqlite-on-3nstorage/deferred.d.ts +6 -0
  8. package/dist/libs/sqlite-on-3nstorage/index.d.ts +6 -6
  9. package/dist/libs/sqlite-on-3nstorage/synced.d.ts +1 -1
  10. package/dist/ui-3n-lib.js +11897 -7953
  11. package/package.json +8 -5
  12. package/src/libs/index.ts +11 -0
  13. package/src/libs/ipc-service-caller.ts +121 -0
  14. package/src/libs/ipc-service.ts +422 -0
  15. package/src/libs/serialization-for-ipc/copy-json.ts +55 -0
  16. package/src/libs/serialization-for-ipc/json-ipc.proto.d.ts +432 -0
  17. package/src/libs/serialization-for-ipc/json-ipc.proto.js +1093 -0
  18. package/src/libs/serialization-for-ipc/json-n-binary.ts +275 -0
  19. package/src/libs/serialization-for-ipc/protobuf-type.ts +61 -0
  20. package/src/libs/sqlite-on-3nstorage/deferred.ts +32 -0
  21. package/src/libs/sqlite-on-3nstorage/index.ts +291 -0
  22. package/{dist → src}/libs/sqlite-on-3nstorage/sqljs.d.ts +26 -26
  23. package/{dist/libs/sqlite-on-3nstorage/index.js → src/libs/sqlite-on-3nstorage/sqljs.js} +97 -2680
  24. package/src/libs/sqlite-on-3nstorage/synced.ts +194 -0
  25. package/dist/libs/index.js +0 -4
  26. package/dist/libs/ipc-service-caller.js +0 -6129
  27. package/dist/libs/ipc-service.js +0 -6337
  28. package/dist/libs/serialization-for-ipc/json-n-binary.js +0 -6040
@@ -0,0 +1,275 @@
1
+ /*
2
+ Copyright (C) 2022 - 2023 3NSoft Inc.
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU General Public License as published by the Free Software
6
+ Foundation, either version 3 of the License, or (at your option) any later
7
+ version.
8
+
9
+ This program is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+ See the GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import root from './json-ipc.proto';
19
+ import { ProtoType } from './protobuf-type';
20
+ import { copyJSON } from './copy-json';
21
+
22
+ interface ValuesSequence {
23
+ values: Value[];
24
+ }
25
+
26
+ interface Value {
27
+ json?: string;
28
+ binaryInJson?: BinaryValue[];
29
+ transferredInJson?: TransferredObj[];
30
+ arr?: BinaryValue;
31
+ transferred?: TransferredObj;
32
+ }
33
+
34
+ interface BinaryValue {
35
+ arr: Uint8Array;
36
+ objLocation: string[];
37
+ }
38
+
39
+ interface TransferredObj {
40
+ indexInPassed: number;
41
+ objLocation: string[];
42
+ }
43
+
44
+ const valuesType = ProtoType.for<ValuesSequence>(root.json_ipc.ValuesSequence);
45
+
46
+ export function serializeArgs(
47
+ args: any[]
48
+ ): { bytes: Uint8Array; passedByReference?: any[]; } {
49
+ const { seq, passedByReference } = argsToValuesSequence(args);
50
+ return { bytes: valuesType.pack(seq), passedByReference };
51
+ }
52
+
53
+ function argsToValuesSequence(
54
+ args: any[]
55
+ ): { seq: ValuesSequence; passedByReference?: any[]; } {
56
+ const seq: ValuesSequence = { values: [] };
57
+ const passedByReference: any[] = [];
58
+ for (const arg of args) {
59
+ if (arg && (typeof arg === 'object')) {
60
+ if (ArrayBuffer.isView(arg)) {
61
+ seq.values.push({
62
+ arr: { arr: arg as Uint8Array, objLocation: [] }
63
+ });
64
+ } else if ((arg as ObjectFromCore)._isObjectFromCore) {
65
+ const indexInPassed = addToArray(passedByReference, arg);
66
+ seq.values.push({
67
+ transferred: { indexInPassed, objLocation: [] }
68
+ });
69
+ } else {
70
+ seq.values.push(turnToJsonExtractingBinaryAndTransferable(
71
+ arg, passedByReference
72
+ ));
73
+ }
74
+ } else {
75
+ seq.values.push({
76
+ json: JSON.stringify(arg)
77
+ });
78
+ }
79
+ }
80
+ return {
81
+ seq,
82
+ passedByReference: ((passedByReference.length > 0) ?
83
+ passedByReference : undefined
84
+ )
85
+ };
86
+ }
87
+
88
+ function addToArray(arr: Array<any>, o: any): number {
89
+ let foundIndex = arr.indexOf(o);
90
+ if (foundIndex < 0) {
91
+ arr.push(o);
92
+ return arr.length - 1;
93
+ } else {
94
+ return foundIndex;
95
+ }
96
+ }
97
+
98
+ function turnToJsonExtractingBinaryAndTransferable<T extends object>(
99
+ arg: T, passedByReference: any[]
100
+ ): {
101
+ json: string; binaryInJson?: BinaryValue[];
102
+ transferredInJson?: TransferredObj[];
103
+ } {
104
+ const parts = extractNonJsonableFrom(arg, passedByReference);
105
+ if (parts) {
106
+ const { copy, binaryInJson, transferredInJson } = parts;
107
+ return {
108
+ json: JSON.stringify(copy),
109
+ binaryInJson: ((binaryInJson.length > 0) ? binaryInJson : undefined),
110
+ transferredInJson: ((transferredInJson.length > 0) ?
111
+ transferredInJson : undefined
112
+ )
113
+ };
114
+ } else {
115
+ return { json: JSON.stringify(arg) };
116
+ }
117
+ }
118
+
119
+ function extractNonJsonableFrom<T extends object>(
120
+ arg: T, passedByReference: any[]
121
+ ): {
122
+ copy: T; binaryInJson: BinaryValue[];
123
+ transferredInJson: TransferredObj[];
124
+ }|undefined {
125
+ const nonJsonLocations = findAllNonJsonable(arg);
126
+ if (!nonJsonLocations) { return; }
127
+ const copy = copyJSON(arg);
128
+ const binaryInJson: BinaryValue[] = [];
129
+ const transferredInJson: TransferredObj[] = [];
130
+ for (const objLocation of nonJsonLocations) {
131
+ const nonJson = getValueAtObjLocation(arg, objLocation);
132
+ setNewValueAtObjLocation(copy, objLocation, null);
133
+ if ((nonJson as ObjectFromCore)._isObjectFromCore) {
134
+ const indexInPassed = addToArray(passedByReference, nonJson);
135
+ transferredInJson.push({ indexInPassed, objLocation });
136
+ } else {
137
+ binaryInJson.push({ arr: nonJson, objLocation });
138
+ }
139
+ }
140
+ return { copy, binaryInJson, transferredInJson };
141
+ }
142
+
143
+ interface ObjectFromCore {
144
+ _isObjectFromCore: true;
145
+ }
146
+
147
+ function findAllNonJsonable(o: object): string[][]|undefined {
148
+ const foundObjLocations: string[][] = [];
149
+ if (ArrayBuffer.isView(o)
150
+ || (o as ObjectFromCore)._isObjectFromCore) {
151
+ return [ [] ];
152
+ }
153
+ if (Array.isArray(o)) {
154
+ for (let i=0; i<o.length; i+=1) {
155
+ const child = o[i];
156
+ if (child && (typeof child === 'object')) {
157
+ const inChild = findAllNonJsonable(child);
158
+ if (inChild) {
159
+ for (const objLocation of inChild) {
160
+ foundObjLocations.push([ `${i}`, ...objLocation ]);
161
+ }
162
+ }
163
+ }
164
+ }
165
+ } else {
166
+ for (const [ field, child ] of Object.entries(o)) {
167
+ if (child && (typeof child === 'object')) {
168
+ const inChild = findAllNonJsonable(child);
169
+ if (inChild) {
170
+ for (const objLocation of inChild) {
171
+ foundObjLocations.push([ field, ...objLocation ]);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ return ((foundObjLocations.length > 0) ? foundObjLocations : undefined);
178
+ }
179
+
180
+ function getValueAtObjLocation(o: object, objLocation: string[]): any {
181
+ const value = (o as any)[objLocation[0]];
182
+ if (objLocation.length > 1) {
183
+ return getValueAtObjLocation(value, objLocation.slice(1));
184
+ } else {
185
+ return value;
186
+ }
187
+ }
188
+
189
+ function setNewValueAtObjLocation(
190
+ o: object, objLocation: string[], newValue: any
191
+ ): void {
192
+ const value = (o as any)[objLocation[0]];
193
+ if (objLocation.length > 1) {
194
+ setNewValueAtObjLocation(value, objLocation.slice(1), newValue);
195
+ } else {
196
+ (o as any)[objLocation[0]] = newValue;
197
+ }
198
+ }
199
+
200
+ function getInitAndSetNewValueAt(
201
+ o: object, objLocation: string[], newValue: any
202
+ ): any {
203
+ const value = (o as any)[objLocation[0]];
204
+ if (objLocation.length > 1) {
205
+ return getInitAndSetNewValueAt(value, objLocation.slice(1), newValue);
206
+ } else {
207
+ (o as any)[objLocation[0]] = newValue;
208
+ return value;
209
+ }
210
+ }
211
+
212
+ export function deserializeArgs(
213
+ bytes: Uint8Array, passedByReference: any[]|undefined
214
+ ): any[] {
215
+ const values = valuesType.unpack(bytes as Buffer);
216
+ const args: any[] = [];
217
+ for (const val of values.values) {
218
+ const {
219
+ json, binaryInJson, transferredInJson, arr, transferred
220
+ } = val;
221
+ if (arr) {
222
+ args.push(arr.arr);
223
+ } else if (transferred) {
224
+ args.push(getTransferred(
225
+ transferred.indexInPassed, passedByReference
226
+ ));
227
+ } else if ((typeof json === 'string') && (json.length > 0)) {
228
+ const arg = JSON.parse(json);
229
+ if (binaryInJson) {
230
+ attachBinaryArrays(arg, binaryInJson);
231
+ }
232
+ if (transferredInJson) {
233
+ attachTransferred(arg, transferredInJson, passedByReference);
234
+ }
235
+ args.push(arg);
236
+ } else {
237
+ // XXX throw error here
238
+ }
239
+ }
240
+ return args;
241
+ }
242
+
243
+ function attachBinaryArrays<T extends object>(
244
+ arg: T, binaryInJson: BinaryValue[]
245
+ ): void {
246
+ for (const { arr, objLocation } of binaryInJson) {
247
+ setNewValueAtObjLocation(arg, objLocation, arr);
248
+ }
249
+ }
250
+
251
+ function getTransferred(
252
+ indexInPassed: number, passedByReference: any[]|undefined
253
+ ): any {
254
+ if (!passedByReference) {
255
+ // XXX throw error here
256
+ throw new Error(`need better error`);
257
+ }
258
+ const o = passedByReference[indexInPassed];
259
+ if (!o || !(o as ObjectFromCore)._isObjectFromCore) {
260
+ // XXX throw error here
261
+ throw new Error(`need better error`);
262
+ }
263
+ return o;
264
+ }
265
+
266
+ function attachTransferred<T extends object>(
267
+ arg: T, transferredInJson: TransferredObj[],
268
+ passedByReference: any[]|undefined
269
+ ): void {
270
+ for (const { indexInPassed, objLocation } of transferredInJson) {
271
+ setNewValueAtObjLocation(arg, objLocation, getTransferred(
272
+ indexInPassed, passedByReference
273
+ ));
274
+ }
275
+ }
@@ -0,0 +1,61 @@
1
+ /*
2
+ Copyright (C) 2020 - 2022 3NSoft Inc.
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU General Public License as published by the Free Software
6
+ Foundation, either version 3 of the License, or (at your option) any later
7
+ version.
8
+
9
+ This program is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+ See the GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import { Type as PBType } from 'protobufjs';
19
+
20
+
21
+ export class ProtoType<T extends object> {
22
+
23
+ private constructor(
24
+ private readonly type: PBType
25
+ ) {
26
+ this.type = type;
27
+ Object.freeze(this);
28
+ }
29
+
30
+ static for<T extends object>(type: any): ProtoType<T> {
31
+ return new ProtoType<T>(type);
32
+ }
33
+
34
+ pack(msg: T): Buffer {
35
+ const err = this.type.verify(msg);
36
+ if (err) { throw new Error(err); }
37
+ return this.type.encode(msg).finish() as Buffer;
38
+ }
39
+
40
+ unpack(bytes: Buffer|void): T {
41
+ if (!bytes) {
42
+ throw {
43
+ runtimeException: true,
44
+ type: 'ipc',
45
+ missingBodyBytes: true
46
+ };
47
+ }
48
+ return this.type.decode(bytes) as T;
49
+ }
50
+
51
+ packToBase64(msg: T): string {
52
+ return this.pack(msg).toString('base64');
53
+ }
54
+
55
+ unpackFromBase64(str: string): T {
56
+ return this.unpack(Buffer.from(str, 'base64'));
57
+ }
58
+
59
+ }
60
+ Object.freeze(ProtoType.prototype);
61
+ Object.freeze(ProtoType);
@@ -0,0 +1,32 @@
1
+ /*
2
+ Copyright (C) 2015, 2017, 2019 - 2022 3NSoft Inc.
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU General Public License as published by the Free Software
6
+ Foundation, either version 3 of the License, or (at your option) any later
7
+ version.
8
+
9
+ This program is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+ See the GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ export interface Deferred<T> {
19
+ promise: Promise<T>;
20
+ resolve: (result?: T|PromiseLike<T>) => void;
21
+ reject: (err: any) => void;
22
+ }
23
+
24
+ export function defer<T>(): Deferred<T> {
25
+ const d = <Deferred<T>> {};
26
+ d.promise = new Promise<T>((resolve, reject) => {
27
+ d.resolve = resolve as Deferred<T>['resolve'];
28
+ d.reject = reject;
29
+ });
30
+ Object.freeze(d);
31
+ return d;
32
+ }
@@ -0,0 +1,291 @@
1
+ /*
2
+ Copyright (C) 2022 3NSoft Inc.
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU General Public License as published by the Free Software
6
+ Foundation, either version 3 of the License, or (at your option) any later
7
+ version.
8
+
9
+ This program is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+ See the GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import initSqlJs, { Database as DBClass, BindParams as QueryParams, QueryExecResult as QueryResult } from './sqljs';
19
+ import { SingleProc, Action } from './synced';
20
+
21
+ export type Database = DBClass;
22
+ export type BindParams = QueryParams;
23
+ export type QueryExecResult = QueryResult;
24
+
25
+ type WritableFile = web3n.files.WritableFile;
26
+ type ReadonlyFile = web3n.files.ReadonlyFile;
27
+ type FileException = web3n.files.FileException;
28
+
29
+ export interface SaveOpts {
30
+ skipUpload?: boolean;
31
+ }
32
+
33
+
34
+ export abstract class SQLiteOn3NStorage {
35
+
36
+ protected readonly syncProc = new SingleProc();
37
+
38
+ protected constructor(
39
+ protected readonly database: Database,
40
+ protected readonly file: WritableFile
41
+ ) {}
42
+
43
+ static async makeAndStart(file: WritableFile): Promise<SQLiteOn3NStorage> {
44
+ const SQL = await initSqlJs(true);
45
+ const fileContent = await readFileContent(file);
46
+ const db = new SQL.Database(fileContent);
47
+ let sqlite: SQLiteOn3NStorage;
48
+ if (file.v?.sync) {
49
+ sqlite = new SQLiteOnSyncedFS(db, file);
50
+ } else if (file.v) {
51
+ sqlite = new SQLiteOnLocalFS(db, file);
52
+ } else {
53
+ sqlite = new SQLiteOnDeviceFS(db, file);
54
+ }
55
+ await sqlite.start();
56
+ return sqlite;
57
+ }
58
+
59
+ private async start(): Promise<void> {
60
+ // XXX add listening process(es)
61
+
62
+ }
63
+
64
+ async saveToFile(opts?: SaveOpts): Promise<void> {
65
+ await this.syncProc.startOrChain(async () => {
66
+ const dbFileContent = this.database.export();
67
+ await this.file.writeBytes(dbFileContent);
68
+ });
69
+ }
70
+
71
+ get db(): Database {
72
+ return this.database;
73
+ }
74
+
75
+ sync<T>(action: Action<T>): Promise<T> {
76
+ return this.syncProc.startOrChain(action);
77
+ }
78
+
79
+ listTables(): string[] {
80
+ const result = this.database.exec(
81
+ `SELECT tbl_name FROM sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%'`
82
+ );
83
+ return ((result.length > 0) ?
84
+ result[0].values.map(row => row[0] as string) :
85
+ []
86
+ );
87
+ }
88
+
89
+ }
90
+ Object.freeze(SQLiteOn3NStorage.prototype);
91
+ Object.freeze(SQLiteOn3NStorage);
92
+
93
+
94
+ class SQLiteOnSyncedFS extends SQLiteOn3NStorage {
95
+
96
+ constructor(db: Database, file: WritableFile) {
97
+ super(db, file);
98
+ Object.seal(this);
99
+ }
100
+
101
+ async saveToFile(opts?: SaveOpts): Promise<void> {
102
+ await super.saveToFile();
103
+ if (opts?.skipUpload) {
104
+ return;
105
+ } else {
106
+ await this.file.v!.sync!.upload();
107
+ }
108
+ }
109
+
110
+ }
111
+ Object.freeze(SQLiteOnSyncedFS.prototype);
112
+ Object.freeze(SQLiteOnSyncedFS);
113
+
114
+
115
+ class SQLiteOnLocalFS extends SQLiteOn3NStorage {
116
+
117
+ constructor(db: Database, file: WritableFile) {
118
+ super(db, file);
119
+ Object.seal(this);
120
+ }
121
+
122
+ }
123
+ Object.freeze(SQLiteOnLocalFS.prototype);
124
+ Object.freeze(SQLiteOnLocalFS);
125
+
126
+
127
+ class SQLiteOnDeviceFS extends SQLiteOn3NStorage {
128
+
129
+ constructor(db: Database, file: WritableFile) {
130
+ super(db, file);
131
+ Object.seal(this);
132
+ }
133
+
134
+ }
135
+ Object.freeze(SQLiteOnDeviceFS.prototype);
136
+ Object.freeze(SQLiteOnDeviceFS);
137
+
138
+
139
+ async function readFileContent(
140
+ file: ReadonlyFile
141
+ ): Promise<Uint8Array|undefined> {
142
+ try {
143
+ return await file.readBytes();
144
+ } catch (exc) {
145
+ if ((exc as FileException).notFound) {
146
+ return undefined;
147
+ } else {
148
+ throw exc;
149
+ }
150
+ }
151
+ }
152
+
153
+ export function objectFromQueryExecResult<T>(
154
+ sqlResult: QueryExecResult
155
+ ): Array<T> {
156
+ const { columns, values: rows } = sqlResult;
157
+ return rows.map(row => row.reduce((obj, cellValue, index) => {
158
+ const field = columns[index] as keyof T;
159
+ obj[field] = cellValue as any;
160
+ return obj;
161
+ }, {} as T));
162
+ }
163
+
164
+
165
+ export class TableColumnsAndParams<ColumnDefs extends object> {
166
+
167
+ public readonly c: { [columnName in keyof ColumnDefs]: string; };
168
+ public readonly cReversed: { [snakedColName: string ]: keyof ColumnDefs; };
169
+ public readonly p: { [columnName in keyof ColumnDefs]: string; };
170
+ public readonly q: { [columnName in keyof ColumnDefs]: string; };
171
+
172
+ constructor(
173
+ public readonly name: string,
174
+ private readonly columnDefs: ColumnDefs
175
+ ) {
176
+ this.c = {} as this['c'];
177
+ this.cReversed = {} as this['cReversed'];
178
+ this.p = {} as this['p'];
179
+ this.q = {} as this['q'];
180
+ for (const cName of Object.keys(this.columnDefs)) {
181
+ const snakedColName = toSnakeCaseName(cName);
182
+ this.c[cName as keyof ColumnDefs] = snakedColName;
183
+ this.cReversed[snakedColName] = cName as keyof ColumnDefs;
184
+ this.p[cName as keyof ColumnDefs] = `$${cName}`;
185
+ this.q[cName as keyof ColumnDefs] = `${this.name}.${snakedColName}`;
186
+ }
187
+ Object.freeze(this.c);
188
+ Object.freeze(this.p);
189
+ Object.freeze(this.q);
190
+ }
191
+
192
+ private toC(cName: string): string {
193
+ const snakedColName = this.c[cName as keyof ColumnDefs];
194
+ if (snakedColName === undefined) {
195
+ throw new Error(`Column ${cName} is not found among columns of table ${this.name}`);
196
+ }
197
+ return snakedColName;
198
+ }
199
+
200
+ toParams<T extends { [columnName in keyof ColumnDefs]: any; }>(
201
+ value: Partial<T>, throwOnUnknownField = true
202
+ ): any {
203
+ const params = {} as any;
204
+ for (const [cName, columnValue] of Object.entries(value)) {
205
+ this.toC(cName); // does implicit check for column existence
206
+ params[this.p[cName as keyof ColumnDefs]] = columnValue;
207
+ }
208
+ for (const paramName of Object.values(this.p)) {
209
+ if (params[paramName as string] === undefined) {
210
+ params[paramName as string] = null;
211
+ }
212
+ }
213
+ return params;
214
+ }
215
+
216
+ getFromQueryExecResult<T>(
217
+ sqlResult: QueryExecResult
218
+ ): Array<T> {
219
+ const { columns, values: rows } = sqlResult;
220
+ return rows.map(row => row.reduce((obj, cellValue, index) => {
221
+ const tabColumn = columns[index];
222
+ let field = this.cReversed[tabColumn as string];
223
+ if (field === undefined) {
224
+ field = tabColumn as keyof ColumnDefs;
225
+ }
226
+ obj[field as string as keyof T] = cellValue as any;
227
+ return obj;
228
+ }, {} as T));
229
+ }
230
+
231
+ get insertQuery(): string {
232
+ const colAndParamNames = Object.entries(this.p);
233
+ return `INSERT INTO ${this.name} (${
234
+ colAndParamNames.map(([cName]) => this.toC(cName)).join(', ')
235
+ }) VALUES (${
236
+ colAndParamNames.map(([n, colParam]) => colParam).join(', ')
237
+ })`;
238
+ }
239
+
240
+ updateQuery(
241
+ withTabName: boolean,
242
+ columns: (keyof ColumnDefs)[]|undefined = undefined,
243
+ skipColumns = false
244
+ ): string {
245
+ let colAndParamNames = Object.entries(this.p);
246
+ if (columns) {
247
+ if (skipColumns) {
248
+ colAndParamNames = colAndParamNames.filter(
249
+ ([cName]) => !columns.includes(cName as keyof ColumnDefs)
250
+ );
251
+ } else {
252
+ colAndParamNames = colAndParamNames.filter(
253
+ ([cName]) => columns.includes(cName as keyof ColumnDefs)
254
+ );
255
+ }
256
+ }
257
+ return `UPDATE ${withTabName ? `${this.name} ` : ''}SET ${
258
+ colAndParamNames
259
+ .map(([cName, pName]) => `${this.toC(cName)}=${pName}`)
260
+ .join(', ')
261
+ }`;
262
+ }
263
+
264
+ get columnsCreateSection(): string {
265
+ return Object.entries(this.columnDefs)
266
+ .map(([cName, columnDef]) => `${this.toC(cName)} ${columnDef}`)
267
+ .join(`,\n`);
268
+ }
269
+
270
+ selectQuery(
271
+ columnsToSelect: (keyof ColumnDefs)[] | string,
272
+ ...whereAndColEqual: (keyof ColumnDefs)[]
273
+ ): string {
274
+ const whereClause = (whereAndColEqual.length > 0) ?
275
+ ` WHERE ${
276
+ (whereAndColEqual as string[]).map(n => `${n}=$${n}`).join(' AND ')
277
+ }` : '';
278
+ return `SELECT ${(typeof columnsToSelect === 'string') ?
279
+ this.toC(columnsToSelect) :
280
+ columnsToSelect.map(cName => this.toC(cName as string)).join(', ')
281
+ } FROM ${this.name}${whereClause}`;
282
+ }
283
+
284
+ }
285
+ Object.freeze(TableColumnsAndParams.prototype);
286
+ Object.freeze(TableColumnsAndParams);
287
+
288
+
289
+ function toSnakeCaseName(str: string): string {
290
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
291
+ }