adminforth 1.0.16 → 1.0.24

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 (35) hide show
  1. package/dataConnectors/{mongo.js → mongo.ts} +15 -10
  2. package/dataConnectors/{postgres.js → postgres.ts} +6 -2
  3. package/dataConnectors/{sqlite.js → sqlite.ts} +6 -2
  4. package/dist/auth.js +68 -0
  5. package/dist/dataConnectors/mongo.js +204 -0
  6. package/dist/dataConnectors/postgres.js +298 -0
  7. package/dist/dataConnectors/sqlite.js +261 -0
  8. package/dist/index.js +693 -0
  9. package/dist/modules/codeInjector.js +337 -0
  10. package/dist/modules/utils.js +12 -0
  11. package/dist/servers/express.js +210 -0
  12. package/dist/spa/src/main.js +16 -0
  13. package/dist/spa/src/router/index.js +79 -0
  14. package/dist/spa/src/stores/core.js +154 -0
  15. package/dist/spa/src/stores/modal.js +35 -0
  16. package/dist/spa/src/utils.js +59 -0
  17. package/dist/spa/vite.config.js +44 -0
  18. package/dist/spa_tmp/src/custom/custom/vueUses.js +10 -0
  19. package/dist/spa_tmp/src/main.js +29 -0
  20. package/dist/spa_tmp/src/router/index.js +83 -0
  21. package/dist/spa_tmp/src/stores/core.js +150 -0
  22. package/dist/spa_tmp/src/stores/modal.js +35 -0
  23. package/dist/spa_tmp/src/utils.js +59 -0
  24. package/dist/spa_tmp/vite.config.js +43 -0
  25. package/dist/types.js +30 -0
  26. package/{index.js → index.ts} +115 -6
  27. package/modules/{codeInjector.js → codeInjector.ts} +20 -16
  28. package/package.json +9 -3
  29. package/servers/{express.js → express.ts} +8 -2
  30. package/spa/package.json +2 -2
  31. package/spa/src/views/ListView.vue +1 -1
  32. package/tsconfig.json +112 -0
  33. package/{types.js → types.ts} +2 -0
  34. /package/{auth.js → auth.ts} +0 -0
  35. /package/modules/{utils.js → utils.ts} +0 -0
@@ -0,0 +1,261 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import betterSqlite3 from 'better-sqlite3';
11
+ import { AdminForthTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types.js';
12
+ import dayjs from 'dayjs';
13
+ class SQLiteConnector {
14
+ constructor({ url }) {
15
+ // create connection here
16
+ this.OperatorsMap = {
17
+ [AdminForthFilterOperators.EQ]: '=',
18
+ [AdminForthFilterOperators.NE]: '!=',
19
+ [AdminForthFilterOperators.GT]: '>',
20
+ [AdminForthFilterOperators.LT]: '<',
21
+ [AdminForthFilterOperators.GTE]: '>=',
22
+ [AdminForthFilterOperators.LTE]: '<=',
23
+ [AdminForthFilterOperators.LIKE]: 'LIKE',
24
+ [AdminForthFilterOperators.ILIKE]: 'ILIKE',
25
+ [AdminForthFilterOperators.IN]: 'IN',
26
+ [AdminForthFilterOperators.NIN]: 'NOT IN',
27
+ };
28
+ this.SortDirectionsMap = {
29
+ [AdminForthSortDirections.ASC]: 'ASC',
30
+ [AdminForthSortDirections.DESC]: 'DESC',
31
+ };
32
+ this.db = betterSqlite3(url.replace('sqlite://', ''));
33
+ }
34
+ discoverFields(resource) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const tableName = resource.table;
37
+ const stmt = this.db.prepare(`PRAGMA table_info(${tableName})`);
38
+ const rows = yield stmt.all();
39
+ const fieldTypes = {};
40
+ rows.forEach((row) => {
41
+ const field = {};
42
+ const baseType = row.type.toLowerCase();
43
+ if (baseType == 'int') {
44
+ field.type = AdminForthTypes.INTEGER;
45
+ field._underlineType = 'int';
46
+ }
47
+ else if (baseType.includes('varchar(')) {
48
+ field.type = AdminForthTypes.STRING;
49
+ field._underlineType = 'varchar';
50
+ const length = baseType.match(/\d+/);
51
+ field.maxLength = length ? parseInt(length[0]) : null;
52
+ }
53
+ else if (baseType == 'text') {
54
+ field.type = AdminForthTypes.TEXT;
55
+ field._underlineType = 'text';
56
+ }
57
+ else if (baseType.includes('decimal(')) {
58
+ field.type = AdminForthTypes.DECIMAL;
59
+ field._underlineType = 'decimal';
60
+ const [precision, scale] = baseType.match(/\d+/g);
61
+ field.precision = parseInt(precision);
62
+ field.scale = parseInt(scale);
63
+ }
64
+ else if (baseType == 'real') {
65
+ field.type = AdminForthTypes.FLOAT; //8-byte IEEE floating point number. It
66
+ field._underlineType = 'real';
67
+ }
68
+ else if (baseType == 'timestamp') {
69
+ field.type = AdminForthTypes.DATETIME;
70
+ field._underlineType = 'timestamp';
71
+ }
72
+ else if (baseType == 'boolean') {
73
+ field.type = AdminForthTypes.BOOLEAN;
74
+ field._underlineType = 'boolean';
75
+ }
76
+ else {
77
+ field.type = 'unknown';
78
+ }
79
+ field._baseTypeDebug = baseType;
80
+ field.required = row.notnull == 1;
81
+ field.primaryKey = row.pk == 1;
82
+ field.default = row.dflt_value;
83
+ fieldTypes[row.name] = field;
84
+ });
85
+ return fieldTypes;
86
+ });
87
+ }
88
+ getPrimaryKey(resource) {
89
+ for (const col of resource.dataSourceColumns) {
90
+ if (col.primaryKey) {
91
+ return col.name;
92
+ }
93
+ }
94
+ }
95
+ getFieldValue(field, value) {
96
+ if (field.type == AdminForthTypes.DATETIME) {
97
+ if (!value) {
98
+ return null;
99
+ }
100
+ if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
101
+ return dayjs.unix(+value).toISOString();
102
+ }
103
+ else if (field._underlineType == 'varchar') {
104
+ return dayjs(value).toISOString();
105
+ }
106
+ else {
107
+ 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}"`);
108
+ }
109
+ }
110
+ else if (field.type == AdminForthTypes.BOOLEAN) {
111
+ return !!value;
112
+ }
113
+ return value;
114
+ }
115
+ getRecordByPrimaryKey(resource, key) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
118
+ const tableName = resource.table;
119
+ const stmt = this.db.prepare(`SELECT ${columns} FROM ${tableName} WHERE ${this.getPrimaryKey(resource)} = ?`);
120
+ const row = stmt.get(key);
121
+ if (!row) {
122
+ return null;
123
+ }
124
+ const newRow = {};
125
+ for (const [key, value] of Object.entries(row)) {
126
+ newRow[key] = this.getFieldValue(resource.dataSourceColumns.find((col) => col.name == key), value);
127
+ }
128
+ return newRow;
129
+ });
130
+ }
131
+ setFieldValue(field, value) {
132
+ if (field.type == AdminForthTypes.DATETIME) {
133
+ if (!value) {
134
+ return null;
135
+ }
136
+ if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
137
+ // value is iso string now, convert to unix timestamp
138
+ return dayjs(value).unix();
139
+ }
140
+ else if (field._underlineType == 'varchar') {
141
+ // value is iso string now, convert to unix timestamp
142
+ return dayjs(value).toISOString();
143
+ }
144
+ }
145
+ else if (field.type == AdminForthTypes.BOOLEAN) {
146
+ return value ? 1 : 0;
147
+ }
148
+ return value;
149
+ }
150
+ getData({ resource, limit, offset, sort, filters }) {
151
+ const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
152
+ const tableName = resource.table;
153
+ for (const filter of filters) {
154
+ if (!this.OperatorsMap[filter.operator]) {
155
+ throw new Error(`Operator ${filter.operator} is not allowed`);
156
+ }
157
+ if (!resource.dataSourceColumns.some((col) => col.name == filter.field)) {
158
+ throw new Error(`Field "${filter.field}" is not in resource ${resource.resourceId}, available fields: ${resource.dataSourceColumns.map((col) => '"' + col.name + '"').join(', ')}`);
159
+ }
160
+ }
161
+ const where = filters.length ? `WHERE ${filters.map((f, i) => {
162
+ let placeholder = '?';
163
+ let field = f.field;
164
+ let operator = this.OperatorsMap[f.operator];
165
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
166
+ placeholder = `(${f.value.map(() => '?').join(', ')})`;
167
+ }
168
+ else if (f.operator == AdminForthFilterOperators.ILIKE) {
169
+ placeholder = `LOWER(?)`;
170
+ field = `LOWER(${f.field})`;
171
+ operator = 'LIKE';
172
+ }
173
+ return `${field} ${operator} ${placeholder}`;
174
+ }).join(' AND ')}` : '';
175
+ const filterValues = [];
176
+ filters.length ? filters.forEach((f) => {
177
+ // for arrays do set in map
178
+ let v;
179
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
180
+ v = f.value.map((val) => this.setFieldValue(resource.dataSourceColumns.find((col) => col.name == f.field), val));
181
+ }
182
+ else {
183
+ v = this.setFieldValue(resource.dataSourceColumns.find((col) => col.name == f.field), f.value);
184
+ }
185
+ if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
186
+ filterValues.push(`%${v}%`);
187
+ }
188
+ else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
189
+ filterValues.push(...v);
190
+ }
191
+ else {
192
+ filterValues.push(v);
193
+ }
194
+ }) : [];
195
+ const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
196
+ const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`;
197
+ const stmt = this.db.prepare(q);
198
+ const d = [...filterValues, limit, offset];
199
+ const rows = stmt.all(d);
200
+ const total = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`).get([...filterValues])['COUNT(*)'];
201
+ // run all fields via getFieldValue
202
+ return {
203
+ data: rows.map((row) => {
204
+ const newRow = {};
205
+ for (const [key, value] of Object.entries(row)) {
206
+ newRow[key] = this.getFieldValue(resource.dataSourceColumns.find((col) => col.name == key), value);
207
+ }
208
+ return newRow;
209
+ }),
210
+ total,
211
+ };
212
+ }
213
+ getMinMaxForColumns(_a) {
214
+ return __awaiter(this, arguments, void 0, function* ({ resource, columns }) {
215
+ const tableName = resource.table;
216
+ const result = {};
217
+ yield Promise.all(columns.map((col) => __awaiter(this, void 0, void 0, function* () {
218
+ const stmt = yield 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: this.getFieldValue(col, min),
222
+ max: this.getFieldValue(col, max),
223
+ };
224
+ })));
225
+ return result;
226
+ });
227
+ }
228
+ createRecord(_a) {
229
+ return __awaiter(this, arguments, void 0, function* ({ resource, record }) {
230
+ const tableName = resource.table;
231
+ const columns = Object.keys(record);
232
+ const placeholders = columns.map(() => '?').join(', ');
233
+ const values = columns.map((colName) => {
234
+ const col = resource.dataSourceColumns.find((col) => col.name == colName);
235
+ if (col) {
236
+ return this.setFieldValue(col, record[colName]);
237
+ }
238
+ else {
239
+ return record[colName];
240
+ }
241
+ });
242
+ this.db.prepare(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`).run(values);
243
+ });
244
+ }
245
+ updateRecord(_a) {
246
+ return __awaiter(this, arguments, void 0, function* ({ resource, recordId, record, newValues }) {
247
+ const columnsWithPlaceholders = Object.keys(newValues).map((col) => `${col} = ?`);
248
+ const values = [...Object.values(newValues), recordId];
249
+ this.db.prepare(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`).run(values);
250
+ });
251
+ }
252
+ deleteRecord(_a) {
253
+ return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
254
+ this.db.prepare(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`).run(recordId);
255
+ });
256
+ }
257
+ close() {
258
+ this.db.close();
259
+ }
260
+ }
261
+ export default SQLiteConnector;