adminforth 1.3.54-next.23 → 1.3.54-next.25

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 (41) hide show
  1. package/dist/plugins/audit-log/types.js +2 -0
  2. package/dist/plugins/audit-log/types.js.map +1 -0
  3. package/dist/plugins/chat-gpt/types.js +2 -0
  4. package/dist/plugins/chat-gpt/types.js.map +1 -0
  5. package/dist/plugins/email-password-reset/types.js +2 -0
  6. package/dist/plugins/email-password-reset/types.js.map +1 -0
  7. package/dist/plugins/foreign-inline-list/types.js +2 -0
  8. package/dist/plugins/foreign-inline-list/types.js.map +1 -0
  9. package/dist/plugins/import-export/types.js +2 -0
  10. package/dist/plugins/import-export/types.js.map +1 -0
  11. package/dist/plugins/rich-editor/custom/async-queue.js +29 -0
  12. package/dist/plugins/rich-editor/custom/async-queue.js.map +1 -0
  13. package/dist/plugins/rich-editor/dist/async-queue.js +41 -0
  14. package/dist/plugins/rich-editor/dist/custom/async-queue.js +29 -0
  15. package/dist/plugins/rich-editor/dist/custom/async-queue.js.map +1 -0
  16. package/dist/plugins/rich-editor/types.js +16 -0
  17. package/dist/plugins/rich-editor/types.js.map +1 -0
  18. package/dist/plugins/two-factors-auth/types.js +2 -0
  19. package/dist/plugins/two-factors-auth/types.js.map +1 -0
  20. package/dist/plugins/upload/types.js +2 -0
  21. package/dist/plugins/upload/types.js.map +1 -0
  22. package/package.json +5 -1
  23. package/auth.ts +0 -140
  24. package/basePlugin.ts +0 -70
  25. package/dataConnectors/baseConnector.ts +0 -221
  26. package/dataConnectors/clickhouse.ts +0 -343
  27. package/dataConnectors/mongo.ts +0 -202
  28. package/dataConnectors/postgres.ts +0 -310
  29. package/dataConnectors/sqlite.ts +0 -258
  30. package/index.ts +0 -428
  31. package/modules/codeInjector.ts +0 -747
  32. package/modules/configValidator.ts +0 -588
  33. package/modules/operationalResource.ts +0 -98
  34. package/modules/restApi.ts +0 -718
  35. package/modules/styleGenerator.ts +0 -55
  36. package/modules/styles.ts +0 -126
  37. package/modules/utils.ts +0 -472
  38. package/servers/express.ts +0 -259
  39. package/tsconfig.json +0 -112
  40. package/types/AdminForthConfig.ts +0 -1762
  41. package/types/FrontendAPI.ts +0 -143
@@ -1,310 +0,0 @@
1
- import dayjs from 'dayjs';
2
- import pkg from 'pg';
3
- import { AdminForthDataTypes, AdminForthResource, AdminForthFilterOperators, AdminForthSortDirections, IAdminForthDataSourceConnector } from '../types/AdminForthConfig.js';
4
- import AdminForthBaseConnector from './baseConnector.js';
5
- const { Client } = pkg;
6
-
7
-
8
- class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
9
-
10
- db: any;
11
-
12
- constructor({ url }) {
13
- super();
14
- this.db = new Client({
15
- connectionString: url
16
- });
17
- (async () => {
18
- await this.db.connect();
19
- this.db.on('error', (err) => {
20
- console.log('Postgres error: ', err.message, err.stack)
21
- this.db.end();
22
- this.db = new PostgresConnector({ url }).db;
23
- });
24
- })();
25
- }
26
-
27
- OperatorsMap = {
28
- [AdminForthFilterOperators.EQ]: '=',
29
- [AdminForthFilterOperators.NE]: '!=',
30
- [AdminForthFilterOperators.GT]: '>',
31
- [AdminForthFilterOperators.LT]: '<',
32
- [AdminForthFilterOperators.GTE]: '>=',
33
- [AdminForthFilterOperators.LTE]: '<=',
34
- [AdminForthFilterOperators.LIKE]: 'LIKE',
35
- [AdminForthFilterOperators.ILIKE]: 'ILIKE',
36
- [AdminForthFilterOperators.IN]: 'IN',
37
- [AdminForthFilterOperators.NIN]: 'NOT IN',
38
- };
39
-
40
- SortDirectionsMap = {
41
- [AdminForthSortDirections.asc]: 'ASC',
42
- [AdminForthSortDirections.desc]: 'DESC',
43
- };
44
-
45
- async discoverFields(resource) {
46
- const tableName = resource.table;
47
- const stmt = await this.db.query(`
48
- SELECT
49
- a.attname AS name,
50
- pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
51
- a.attnotnull AS notnull,
52
- COALESCE(pg_get_expr(d.adbin, d.adrelid), '') AS dflt_value,
53
- CASE
54
- WHEN ct.contype = 'p' THEN 1
55
- ELSE 0
56
- END AS pk
57
- FROM
58
- pg_catalog.pg_attribute a
59
- LEFT JOIN pg_catalog.pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
60
- LEFT JOIN pg_catalog.pg_constraint ct ON a.attnum = ANY (ct.conkey) AND a.attrelid = ct.conrelid
61
- LEFT JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
62
- LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
63
- WHERE
64
- c.relname = $1
65
- AND a.attnum > 0
66
- AND NOT a.attisdropped
67
- ORDER BY
68
- a.attnum;
69
- `, [tableName]);
70
- const rows = stmt.rows;
71
- const fieldTypes = {};
72
-
73
- rows.forEach((row) => {
74
- const field: any = {};
75
- const baseType = row.type.toLowerCase();
76
- if (baseType == 'int') {
77
- field.type = AdminForthDataTypes.INTEGER;
78
- field._underlineType = 'int';
79
-
80
- } else if (baseType.includes('float') || baseType.includes('double')) {
81
- field.type = AdminForthDataTypes.FLOAT;
82
- field._underlineType = 'float';
83
-
84
- } else if (baseType.includes('bool')) {
85
- field.type = AdminForthDataTypes.BOOLEAN;
86
- field._underlineType = 'bool';
87
-
88
- } else if (baseType == 'uuid') {
89
- field.type = AdminForthDataTypes.STRING;
90
- field._underlineType = 'uuid';
91
-
92
- } else if (baseType.includes('character varying')) {
93
- field.type = AdminForthDataTypes.STRING;
94
- field._underlineType = 'varchar';
95
- const length = baseType.match(/\d+/);
96
- field.maxLength = length ? parseInt(length[0]) : null;
97
-
98
- } else if (baseType == 'text') {
99
- field.type = AdminForthDataTypes.TEXT;
100
- field._underlineType = 'text';
101
-
102
- } else if (baseType.includes('decimal(')) {
103
- field.type = AdminForthDataTypes.DECIMAL;
104
- field._underlineType = 'decimal';
105
- const [precision, scale] = baseType.match(/\d+/g);
106
- field.precision = parseInt(precision);
107
- field.scale = parseInt(scale);
108
-
109
- } else if (baseType == 'real') {
110
- field.type = AdminForthDataTypes.FLOAT;
111
- field._underlineType = 'real';
112
-
113
- } else if (baseType == 'date') {
114
- field.type = AdminForthDataTypes.DATE;
115
- field._underlineType = 'timestamp';
116
-
117
- } else if (baseType.includes('date') || baseType.includes('time')) {
118
- field.type = AdminForthDataTypes.DATETIME;
119
- field._underlineType = 'timestamp';
120
-
121
- } else {
122
- field.type = 'unknown'
123
- }
124
- field._baseTypeDebug = baseType;
125
- field.primaryKey = row.pk == 1;
126
- field.default = row.dflt_value;
127
- field.required = row.notnull && !row.dflt_value;
128
- fieldTypes[row.name] = field
129
- });
130
- return fieldTypes;
131
- }
132
-
133
- getFieldValue(field, value) {
134
- if (field.type == AdminForthDataTypes.DATETIME) {
135
- if (!value) {
136
- return null;
137
- }
138
- if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
139
- return dayjs(value).toISOString();
140
- } else if (field._underlineType == 'varchar') {
141
- return dayjs(value).toISOString();
142
- } else {
143
- throw new Error(`AdminForth does not support row type: ${field._underlineType} for timestamps, use VARCHAR (with iso strings) or TIMESTAMP/INT (with unix timestamps)`);
144
- }
145
- }
146
-
147
- if (field.type == AdminForthDataTypes.DATE) {
148
- if (!value) {
149
- return null;
150
- }
151
- return dayjs(value).toISOString().split('T')[0];
152
- }
153
-
154
- if (field.type == AdminForthDataTypes.JSON) {
155
- if (typeof value == 'string') {
156
- try {
157
- return JSON.parse(value);
158
- } catch (e) {
159
- return {'error': `Failed to parse JSON: ${e.message}`}
160
- }
161
- } else if (typeof value == 'object') {
162
- return value;
163
- } else {
164
- console.error('JSON field value is not string or object, but has type:', typeof value);
165
- console.error('Field:', field);
166
- return {}
167
- }
168
- }
169
-
170
- return value;
171
- }
172
-
173
-
174
- setFieldValue(field, value) {
175
- if (field.type == AdminForthDataTypes.DATETIME) {
176
- if (!value) {
177
- return null;
178
- }
179
- if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
180
- return dayjs(value);
181
- } else if (field._underlineType == 'varchar') {
182
- return dayjs(value).toISOString();
183
- }
184
- } else if (field.type == AdminForthDataTypes.BOOLEAN) {
185
- return value ? 1 : 0;
186
- }
187
- return value;
188
- }
189
-
190
- whereClauseAndValues(resource: AdminForthResource, filters: { field: string, operator: AdminForthFilterOperators, value: any }[]) : {
191
- sql: string,
192
- paramsCount: number,
193
- values: any[],
194
- } {
195
-
196
- let totalCounter = 1;
197
- const where = filters.length ? `WHERE ${filters.map((f, i) => {
198
- let placeholder = '$'+(totalCounter);
199
- const fieldData = resource.dataSourceColumns.find((col) => col.name == f.field);
200
- let field = f.field;
201
- let operator = this.OperatorsMap[f.operator];
202
- if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
203
- placeholder = `(${f.value.map((_, i) => `$${totalCounter + i}`).join(', ')})`;
204
- totalCounter += f.value.length;
205
- } else {
206
- totalCounter += 1;
207
- }
208
-
209
- if (fieldData._underlineType == 'uuid') {
210
- field = `cast("${field}" as text)`
211
- } else {
212
- field = `"${field}"`
213
- }
214
- return `${field} ${operator} ${placeholder}`;
215
- }).join(' AND ')}` : '';
216
-
217
- const filterValues = [];
218
- filters.length ? filters.forEach((f) => {
219
- // for arrays do set in map
220
- let v = f.value;
221
-
222
- if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
223
- filterValues.push(`%${v}%`);
224
- } else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
225
- filterValues.push(...v);
226
- } else {
227
- filterValues.push(v);
228
- }
229
- }) : [];
230
- return {
231
- sql: where,
232
- paramsCount: totalCounter,
233
- values: filterValues,
234
- };
235
-
236
- }
237
-
238
-
239
- async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }): Promise<any[]> {
240
- const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
241
- const tableName = resource.table;
242
-
243
- const { sql: where, paramsCount, values: filterValues } = this.whereClauseAndValues(resource, filters);
244
-
245
- const limitOffset = `LIMIT $${paramsCount} OFFSET $${paramsCount + 1}`;
246
- const d = [...filterValues, limit, offset];
247
- const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `"${s.field}" ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
248
- const selectQuery = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} ${limitOffset}`;
249
- if (process.env.HEAVY_DEBUG) {
250
- console.log('🪲 PG selectQuery:', selectQuery, 'params:', d);
251
- }
252
- const stmt = await this.db.query(selectQuery, d);
253
- const rows = stmt.rows;
254
- return rows.map((row) => {
255
- const newRow = {};
256
- for (const [key, value] of Object.entries(row)) {
257
- newRow[key] = value;
258
- }
259
- return newRow;
260
- });
261
- }
262
-
263
- async getCount({ resource, filters }: { resource: AdminForthResource; filters: { field: string, operator: AdminForthFilterOperators, value: any }[]; }): Promise<number> {
264
- const tableName = resource.table;
265
- const { sql: where, values: filterValues } = this.whereClauseAndValues(resource, filters);
266
- const stmt = await this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues);
267
- return stmt.rows[0].count;
268
- }
269
-
270
- async getMinMaxForColumnsWithOriginalTypes({ resource, columns }) {
271
- const tableName = resource.table;
272
- const result = {};
273
- await Promise.all(columns.map(async (col) => {
274
- const stmt = await this.db.query(`SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`);
275
- const { min, max } = stmt.rows[0];
276
- result[col.name] = {
277
- min, max,
278
- };
279
- }))
280
- return result;
281
- }
282
-
283
- async createRecordOriginalValues({ resource, record }) {
284
- const tableName = resource.table;
285
- const columns = Object.keys(record);
286
- const placeholders = columns.map((_, i) => `$${i + 1}`).join(', ');
287
- const values = columns.map((colName) => record[colName]);
288
- for (let i = 0; i < columns.length; i++) {
289
- columns[i] = `"${columns[i]}"`;
290
- }
291
- await this.db.query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`, values);
292
- }
293
-
294
- async updateRecordOriginalValues({ resource, recordId, newValues }) {
295
- const values = [...Object.values(newValues), recordId];
296
- const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `"${col}" = $${i + 1}`).join(', ');
297
- await this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`, values);
298
- }
299
-
300
- async deleteRecord({ resource, recordId }): Promise<boolean> {
301
- const res = await this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
302
- return res.rowCount > 0;
303
- }
304
-
305
- async close() {
306
- await this.db.end();
307
- }
308
- }
309
-
310
- export default PostgresConnector;
@@ -1,258 +0,0 @@
1
- import betterSqlite3 from 'better-sqlite3';
2
- import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, IAdminForthDataSourceConnector, AdminForthResource, AdminForthResourceColumn } from '../types/AdminForthConfig.js';
3
- import AdminForthBaseConnector from './baseConnector.js';
4
- import dayjs from 'dayjs';
5
-
6
- class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
7
-
8
- db: any;
9
-
10
- constructor({ url }: { url: string }) {
11
- super();
12
- // create connection here
13
- this.db = betterSqlite3(url.replace('sqlite://', ''));
14
- }
15
-
16
- async discoverFields(resource: AdminForthResource): Promise<{[key: string]: AdminForthResourceColumn}> {
17
- const tableName = resource.table;
18
- const stmt = this.db.prepare(`PRAGMA table_info(${tableName})`);
19
- const rows = await stmt.all();
20
- const fieldTypes = {};
21
- rows.forEach((row) => {
22
- const field: any = {};
23
- const baseType = row.type.toLowerCase();
24
- if (baseType == 'int') {
25
- field.type = AdminForthDataTypes.INTEGER;
26
- field._underlineType = 'int';
27
- } else if (baseType.includes('varchar(')) {
28
- field.type = AdminForthDataTypes.STRING;
29
- field._underlineType = 'varchar';
30
- const length = baseType.match(/\d+/);
31
- field.maxLength = length ? parseInt(length[0]) : null;
32
- } else if (baseType == 'text') {
33
- field.type = AdminForthDataTypes.TEXT;
34
- field._underlineType = 'text';
35
- } else if (baseType.includes('decimal(')) {
36
- field.type = AdminForthDataTypes.DECIMAL;
37
- field._underlineType = 'decimal';
38
- const [precision, scale] = baseType.match(/\d+/g);
39
- field.precision = parseInt(precision);
40
- field.scale = parseInt(scale);
41
- } else if (baseType == 'real') {
42
- field.type = AdminForthDataTypes.FLOAT; //8-byte IEEE floating point number. It
43
- field._underlineType = 'real';
44
- } else if (baseType == 'timestamp') {
45
- field.type = AdminForthDataTypes.DATETIME;
46
- field._underlineType = 'timestamp';
47
- } else if (baseType == 'boolean') {
48
- field.type = AdminForthDataTypes.BOOLEAN;
49
- field._underlineType = 'boolean';
50
- } else if (baseType == 'datetime') {
51
- field.type = AdminForthDataTypes.DATETIME;
52
- field._underlineType = 'datetime';
53
- } else {
54
- field.type = 'unknown'
55
- }
56
- field._baseTypeDebug = baseType;
57
- field.required = row.notnull == 1;
58
- field.primaryKey = row.pk == 1;
59
- field.default = row.dflt_value;
60
- fieldTypes[row.name] = field
61
- });
62
- return fieldTypes;
63
- }
64
-
65
- getFieldValue(field: AdminForthResourceColumn, value: any): any {
66
- if (field.type == AdminForthDataTypes.DATETIME) {
67
- if (!value) {
68
- return null;
69
- }
70
- if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
71
- return dayjs.unix(+value).toISOString();
72
- } else if (field._underlineType == 'varchar') {
73
- return dayjs(value).toISOString();
74
- } else if (field._underlineType == 'datetime') {
75
- return dayjs(value).toISOString();
76
- } else {
77
- throw new Error(`AdminForth does not support row type: ${field._underlineType} for timestamps, use VARCHAR (with iso strings) or TIMESTAMP/INT (with unix timestamps). Issue in field "${field.name}"`);
78
- }
79
-
80
- } else if (field.type == AdminForthDataTypes.DATE) {
81
- if (!value) {
82
- return null;
83
- }
84
- return dayjs(value).toISOString().split('T')[0];
85
-
86
- } else if (field.type == AdminForthDataTypes.BOOLEAN) {
87
- return !!value;
88
- } else if (field.type == AdminForthDataTypes.JSON) {
89
- if (field._underlineType == 'text' || field._underlineType == 'varchar') {
90
- try {
91
- return JSON.parse(value);
92
- } catch (e) {
93
- return {'error': `Failed to parse JSON: ${e.message}`}
94
- }
95
- } else {
96
- console.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
97
- }
98
- }
99
-
100
- return value;
101
- }
102
-
103
- setFieldValue(field: AdminForthResourceColumn, value: any): any {
104
- if (field.type == AdminForthDataTypes.DATETIME) {
105
- if (!value) {
106
- return null;
107
- }
108
- if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
109
- // value is iso string now, convert to unix timestamp
110
- return dayjs(value).unix();
111
- } else if (field._underlineType == 'varchar') {
112
- // value is iso string now, convert to unix timestamp
113
- return dayjs(value).toISOString();
114
- } else {
115
- return value;
116
- }
117
- } else if (field.type == AdminForthDataTypes.BOOLEAN) {
118
- return value ? 1 : 0;
119
- } else if (field.type == AdminForthDataTypes.JSON) {
120
- // check underline type is text or string
121
- if (field._underlineType == 'text' || field._underlineType == 'varchar') {
122
- return JSON.stringify(value);
123
- } else {
124
- console.error(`AdminForth: JSON field is not a string/text but ${field._underlineType}, this is not supported yet`);
125
- }
126
- }
127
-
128
- return value;
129
- }
130
-
131
- OperatorsMap = {
132
- [AdminForthFilterOperators.EQ]: '=',
133
- [AdminForthFilterOperators.NE]: '!=',
134
- [AdminForthFilterOperators.GT]: '>',
135
- [AdminForthFilterOperators.LT]: '<',
136
- [AdminForthFilterOperators.GTE]: '>=',
137
- [AdminForthFilterOperators.LTE]: '<=',
138
- [AdminForthFilterOperators.LIKE]: 'LIKE',
139
- [AdminForthFilterOperators.ILIKE]: 'ILIKE',
140
- [AdminForthFilterOperators.IN]: 'IN',
141
- [AdminForthFilterOperators.NIN]: 'NOT IN',
142
- };
143
-
144
- SortDirectionsMap = {
145
- [AdminForthSortDirections.asc]: 'ASC',
146
- [AdminForthSortDirections.desc]: 'DESC',
147
- };
148
-
149
- whereClause(filters) {
150
- return filters.length ? `WHERE ${filters.map((f, i) => {
151
- let placeholder = '?';
152
- let field = f.field;
153
- let operator = this.OperatorsMap[f.operator];
154
- if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
155
- placeholder = `(${f.value.map(() => '?').join(', ')})`;
156
- } else if (f.operator == AdminForthFilterOperators.ILIKE) {
157
- placeholder = `LOWER(?)`;
158
- field = `LOWER(${f.field})`;
159
- operator = 'LIKE';
160
- }
161
-
162
- return `${field} ${operator} ${placeholder}`
163
- }).join(' AND ')}` : '';
164
- }
165
- whereParams(filters) {
166
- return filters.reduce((acc, f) => {
167
- if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
168
- acc.push(`%${f.value}%`);
169
- } else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
170
- acc.push(...f.value);
171
- } else {
172
- acc.push(f.value);
173
- }
174
- return acc;
175
- }, []);
176
- }
177
-
178
- async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }): Promise<any[]> {
179
- const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
180
- const tableName = resource.table;
181
-
182
- const where = this.whereClause(filters);
183
-
184
- const filterValues = this.whereParams(filters);
185
-
186
- const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
187
-
188
- const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`;
189
- const stmt = this.db.prepare(q);
190
- const d = [...filterValues, limit, offset];
191
-
192
- if (process.env.HEAVY_DEBUG) {
193
- console.log('🪲📜 SQLITE Q', q, 'params:', d);
194
- }
195
- const rows = await stmt.all(d);
196
-
197
- return rows.map((row) => {
198
- const newRow = {};
199
- for (const [key, value] of Object.entries(row)) {
200
- newRow[key] = value;
201
- }
202
- return newRow;
203
- })
204
- }
205
-
206
- async getCount({ resource, filters }) {
207
- const tableName = resource.table;
208
- const where = this.whereClause(filters);
209
- const filterValues = this.whereParams(filters);
210
- const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
211
- return totalStmt.get([...filterValues])['COUNT(*)'];
212
- }
213
-
214
- async getMinMaxForColumnsWithOriginalTypes({ resource, columns }: { resource: AdminForthResource, columns: AdminForthResourceColumn[] }): Promise<{ [key: string]: { min: any, max: any } }> {
215
- const tableName = resource.table;
216
- const result = {};
217
- await Promise.all(columns.map(async (col) => {
218
- const stmt = await this.db.prepare(`SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`);
219
- const { min, max } = stmt.get();
220
- result[col.name] = {
221
- min, max,
222
- };
223
- }))
224
- return result;
225
- }
226
-
227
- async createRecordOriginalValues({ resource, record }: { resource: AdminForthResource, record: any }) {
228
- const tableName = resource.table;
229
- const columns = Object.keys(record);
230
- const placeholders = columns.map(() => '?').join(', ');
231
- const values = columns.map((colName) => record[colName]);
232
- const q = this.db.prepare(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`)
233
- await q.run(values);
234
- }
235
-
236
- async updateRecordOriginalValues({ resource, recordId, newValues }: { resource: AdminForthResource, recordId: any, newValues: any }) {
237
- const columnsWithPlaceholders = Object.keys(newValues).map((col) => `${col} = ?`);
238
- const values = [...Object.values(newValues), recordId];
239
-
240
- const q = this.db.prepare(
241
- `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`
242
- )
243
- process.env.HEAVY_DEBUG && console.log('🪲 SQLITE Query', `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`, 'params:', values);
244
- await q.run(values);
245
- }
246
-
247
- async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }): Promise<boolean> {
248
- const q = this.db.prepare(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`);
249
- const res = await q.run(recordId);
250
- return res.changes > 0;
251
- }
252
-
253
- close() {
254
- this.db.close();
255
- }
256
- }
257
-
258
- export default SQLiteConnector;