adminforth 1.2.95 → 1.2.97

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 (115) hide show
  1. package/dataConnectors/baseConnector.ts +26 -14
  2. package/dataConnectors/clickhouse.ts +57 -37
  3. package/dataConnectors/mongo.ts +45 -14
  4. package/dataConnectors/postgres.ts +53 -36
  5. package/dataConnectors/sqlite.ts +37 -35
  6. package/dist/dataConnectors/baseConnector.js +16 -7
  7. package/dist/dataConnectors/clickhouse.js +58 -48
  8. package/dist/dataConnectors/mongo.js +29 -12
  9. package/dist/dataConnectors/postgres.js +62 -52
  10. package/dist/dataConnectors/sqlite.js +52 -45
  11. package/dist/index.js +5 -1
  12. package/dist/modules/operationalResource.js +88 -0
  13. package/dist/modules/restApi.js +27 -29
  14. package/dist/spa/index.html +4 -4
  15. package/dist/spa/package-lock.json +421 -6
  16. package/dist/spa/package.json +10 -2
  17. package/dist/spa/src/App.vue +236 -94
  18. package/dist/spa/src/assets/base.css +2 -0
  19. package/dist/spa/src/assets/logo.svg +19 -1
  20. package/dist/spa/src/components/AcceptModal.vue +3 -10
  21. package/dist/spa/src/components/Breadcrumbs.vue +3 -2
  22. package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
  23. package/dist/spa/src/components/CustomDatePicker.vue +25 -10
  24. package/dist/spa/src/components/CustomDateRangePicker.vue +14 -5
  25. package/dist/spa/src/components/Dropdown.vue +19 -5
  26. package/dist/spa/src/components/Filters.vue +103 -38
  27. package/dist/spa/src/components/MenuLink.vue +3 -3
  28. package/dist/spa/src/components/ResourceForm.vue +205 -116
  29. package/dist/spa/{spa/src → src}/components/ResourceListTable.vue +6 -3
  30. package/dist/spa/{spa/src → src}/components/Toast.vue +9 -3
  31. package/dist/spa/src/components/ValueRenderer.vue +30 -8
  32. package/dist/spa/src/index.scss +2 -1
  33. package/dist/spa/src/main.ts +2 -2
  34. package/dist/spa/src/router/index.ts +29 -19
  35. package/dist/spa/src/stores/core.ts +65 -59
  36. package/dist/spa/src/stores/modal.ts +13 -3
  37. package/dist/spa/src/types/AdminForthConfig.ts +1477 -0
  38. package/dist/spa/src/types/FrontendAPI.ts +121 -0
  39. package/dist/spa/src/utils.ts +69 -10
  40. package/dist/spa/src/views/CreateView.vue +69 -16
  41. package/dist/spa/src/views/EditView.vue +68 -14
  42. package/dist/spa/src/views/ListView.vue +100 -371
  43. package/dist/spa/src/views/LoginView.vue +67 -29
  44. package/dist/spa/src/views/ResourceParent.vue +1 -2
  45. package/dist/spa/src/views/ShowView.vue +116 -25
  46. package/dist/spa/tailwind.config.js +8 -3
  47. package/dist/spa/vite.config.ts +13 -0
  48. package/dist/types/AdminForthConfig.js +37 -0
  49. package/index.ts +12 -3
  50. package/modules/operationalResource.ts +97 -0
  51. package/modules/restApi.ts +31 -31
  52. package/package.json +1 -1
  53. package/types/AdminForthConfig.ts +91 -8
  54. package/dist/spa/.vscode/extensions.json +0 -6
  55. package/dist/spa/public/favicon.ico +0 -0
  56. package/dist/spa/spa/.eslintrc.cjs +0 -14
  57. package/dist/spa/spa/.vscode/extensions.json +0 -6
  58. package/dist/spa/spa/README.md +0 -39
  59. package/dist/spa/spa/env.d.ts +0 -1
  60. package/dist/spa/spa/index.html +0 -23
  61. package/dist/spa/spa/package-lock.json +0 -4573
  62. package/dist/spa/spa/package.json +0 -49
  63. package/dist/spa/spa/postcss.config.js +0 -6
  64. package/dist/spa/spa/public/favicon.ico +0 -0
  65. package/dist/spa/spa/src/App.vue +0 -314
  66. package/dist/spa/spa/src/assets/base.css +0 -0
  67. package/dist/spa/spa/src/assets/logo.svg +0 -19
  68. package/dist/spa/spa/src/components/AcceptModal.vue +0 -45
  69. package/dist/spa/spa/src/components/Breadcrumbs.vue +0 -40
  70. package/dist/spa/spa/src/components/BreadcrumbsWithButtons.vue +0 -26
  71. package/dist/spa/spa/src/components/CustomDatePicker.vue +0 -174
  72. package/dist/spa/spa/src/components/CustomDateRangePicker.vue +0 -218
  73. package/dist/spa/spa/src/components/Dropdown.vue +0 -168
  74. package/dist/spa/spa/src/components/Filters.vue +0 -222
  75. package/dist/spa/spa/src/components/HelloWorld.vue +0 -17
  76. package/dist/spa/spa/src/components/MenuLink.vue +0 -24
  77. package/dist/spa/spa/src/components/ResourceForm.vue +0 -289
  78. package/dist/spa/spa/src/components/SingleSkeletLoader.vue +0 -13
  79. package/dist/spa/spa/src/components/ValueRenderer.vue +0 -66
  80. package/dist/spa/spa/src/components/icons/IconCalendar.vue +0 -5
  81. package/dist/spa/spa/src/components/icons/IconCommunity.vue +0 -7
  82. package/dist/spa/spa/src/components/icons/IconDocumentation.vue +0 -7
  83. package/dist/spa/spa/src/components/icons/IconEcosystem.vue +0 -7
  84. package/dist/spa/spa/src/components/icons/IconSupport.vue +0 -7
  85. package/dist/spa/spa/src/components/icons/IconTime.vue +0 -5
  86. package/dist/spa/spa/src/components/icons/IconTooling.vue +0 -19
  87. package/dist/spa/spa/src/index.scss +0 -27
  88. package/dist/spa/spa/src/main.ts +0 -18
  89. package/dist/spa/spa/src/router/index.ts +0 -63
  90. package/dist/spa/spa/src/stores/core.ts +0 -144
  91. package/dist/spa/spa/src/stores/modal.ts +0 -48
  92. package/dist/spa/spa/src/utils.ts +0 -103
  93. package/dist/spa/spa/src/views/CreateView.vue +0 -156
  94. package/dist/spa/spa/src/views/EditView.vue +0 -157
  95. package/dist/spa/spa/src/views/HomeView.vue +0 -8
  96. package/dist/spa/spa/src/views/ListView.vue +0 -258
  97. package/dist/spa/spa/src/views/LoginView.vue +0 -143
  98. package/dist/spa/spa/src/views/ResourceParent.vue +0 -17
  99. package/dist/spa/spa/src/views/ShowView.vue +0 -184
  100. package/dist/spa/spa/tailwind.config.js +0 -17
  101. package/dist/spa/spa/tsconfig.app.json +0 -14
  102. package/dist/spa/spa/tsconfig.json +0 -11
  103. package/dist/spa/spa/tsconfig.node.json +0 -19
  104. package/dist/spa/spa/vite.config.ts +0 -56
  105. package/dist/spa/src/views/HomeView.vue +0 -8
  106. package/dist/types.js +0 -30
  107. /package/dist/spa/{spa/public → public}/assets/favicon.png +0 -0
  108. /package/dist/spa/{spa/src → src}/components/CustomRangePicker.vue +0 -0
  109. /package/dist/spa/{spa/src → src}/components/SkeleteLoader.vue +0 -0
  110. /package/dist/spa/{spa/src → src}/composables/useFrontendApi.ts +0 -0
  111. /package/dist/spa/{spa/src → src}/composables/useStores.ts +0 -0
  112. /package/dist/spa/{spa/src → src}/spa_types/core.ts +0 -0
  113. /package/dist/spa/{spa/src → src}/stores/filters.ts +0 -0
  114. /package/dist/spa/{spa/src → src}/stores/toast.ts +0 -0
  115. /package/dist/spa/{spa/src → src}/stores/user.ts +0 -0
@@ -184,36 +184,43 @@ class ClickhouseConnector extends AdminForthBaseConnector {
184
184
  }
185
185
  return value;
186
186
  }
187
+ whereClause(resource, filters) {
188
+ return filters.length ? `WHERE ${filters.map((f, i) => {
189
+ const column = resource.dataSourceColumns.find((col) => col.name == f.field);
190
+ let placeholder = `{f${i}:${column._underlineType}}`;
191
+ let field = f.field;
192
+ let operator = this.OperatorsMap[f.operator];
193
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
194
+ placeholder = `(${f.value.map((_, j) => `{p${i}_${j}:${column._underlineType}}`).join(', ')})`;
195
+ }
196
+ return `${field} ${operator} ${placeholder}`;
197
+ }).join(' AND ')}` : '';
198
+ }
199
+ whereParams(filters) {
200
+ const params = {};
201
+ filters.length ? filters.forEach((f, i) => {
202
+ // for arrays do set in map
203
+ const v = f.value;
204
+ if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
205
+ params[`f${i}`] = `%${v}%`;
206
+ }
207
+ else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
208
+ v.forEach((_, j) => {
209
+ params[`p${i}_${j}`] = v[j];
210
+ });
211
+ }
212
+ else {
213
+ params[`f${i}`] = v;
214
+ }
215
+ }) : [];
216
+ return params;
217
+ }
187
218
  getDataWithOriginalTypes(_a) {
188
- return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
219
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
189
220
  const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
190
221
  const tableName = resource.table;
191
- const where = filters.length ? `WHERE ${filters.map((f, i) => {
192
- const column = resource.dataSourceColumns.find((col) => col.name == f.field);
193
- let placeholder = `{f${i}:${column._underlineType}}`;
194
- let field = f.field;
195
- let operator = this.OperatorsMap[f.operator];
196
- if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
197
- placeholder = `(${f.value.map((_, j) => `{p${i}_${j}:${column._underlineType}}`).join(', ')})`;
198
- }
199
- return `${field} ${operator} ${placeholder}`;
200
- }).join(' AND ')}` : '';
201
- const params = {};
202
- filters.length ? filters.forEach((f, i) => {
203
- // for arrays do set in map
204
- const v = f.value;
205
- if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
206
- params[`f${i}`] = `%${v}%`;
207
- }
208
- else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
209
- v.forEach((_, j) => {
210
- params[`p${i}_${j}`] = v[j];
211
- });
212
- }
213
- else {
214
- params[`f${i}`] = v;
215
- }
216
- }) : [];
222
+ const where = this.whereClause(resource, filters);
223
+ const params = this.whereParams(filters);
217
224
  const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
218
225
  const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT {limit:Int} OFFSET {offset:Int}`;
219
226
  const d = Object.assign(Object.assign({}, params), { limit,
@@ -224,26 +231,27 @@ class ClickhouseConnector extends AdminForthBaseConnector {
224
231
  query_params: d,
225
232
  });
226
233
  const rows = yield stmt.json();
227
- let total = 0;
228
- if (getTotals) {
229
- const countQ = yield this.client.query({
230
- query: `SELECT COUNT(*) FROM ${tableName} ${where}`,
231
- format: 'JSONEachRow',
232
- query_params: d,
233
- });
234
- const countResp = yield countQ.json();
235
- total = countResp[0]['COUNT()'];
236
- }
237
- return {
238
- data: rows.map((row) => {
239
- const newRow = {};
240
- for (const [key, value] of Object.entries(row)) {
241
- newRow[key] = value;
242
- }
243
- return newRow;
244
- }),
245
- total,
246
- };
234
+ return rows.map((row) => {
235
+ const newRow = {};
236
+ for (const [key, value] of Object.entries(row)) {
237
+ newRow[key] = value;
238
+ }
239
+ return newRow;
240
+ });
241
+ });
242
+ }
243
+ getCount(_a) {
244
+ return __awaiter(this, arguments, void 0, function* ({ resource, filters, }) {
245
+ const tableName = resource.table;
246
+ const where = this.whereClause(resource, filters);
247
+ const d = this.whereParams(filters);
248
+ const countQ = yield this.client.query({
249
+ query: `SELECT COUNT(*) FROM ${tableName} ${where}`,
250
+ format: 'JSONEachRow',
251
+ query_params: d,
252
+ });
253
+ const countResp = yield countQ.json();
254
+ return countResp[0]['COUNT()'];
247
255
  });
248
256
  }
249
257
  getMinMaxForColumnsWithOriginalTypes(_a) {
@@ -291,10 +299,12 @@ class ClickhouseConnector extends AdminForthBaseConnector {
291
299
  deleteRecord(_a) {
292
300
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
293
301
  const pkColumn = resource.dataSourceColumns.find((col) => col.primaryKey);
294
- yield this.client.command({
302
+ const res = yield this.client.command({
295
303
  query: `ALTER TABLE ${this.dbName}.${resource.table} DELETE WHERE ${pkColumn.name} = {recordId:${pkColumn._underlineType}}`,
296
304
  query_params: { recordId },
297
305
  });
306
+ // todo test what is in res
307
+ return res;
298
308
  });
299
309
  }
300
310
  close() {
@@ -108,25 +108,41 @@ class MongoConnector extends AdminForthBaseConnector {
108
108
  }
109
109
  return value;
110
110
  }
111
- getDataWithOriginalTypes(_a) {
112
- return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
113
- // const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
114
- const tableName = resource.table;
115
- const collection = this.db.db().collection(tableName);
111
+ genQuery(_a) {
112
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
113
+ const collection = this.db.db().collection(resource.table);
116
114
  const query = {};
117
115
  for (const filter of filters) {
118
116
  query[filter.field] = this.OperatorsMap[filter.operator](filter.value);
119
117
  }
120
- let total = 0;
121
- if (getTotals) {
122
- total = yield collection.countDocuments(query);
123
- }
118
+ return { collection, query };
119
+ });
120
+ }
121
+ getDataWithOriginalTypes(_a) {
122
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
123
+ // const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
124
+ const tableName = resource.table;
125
+ const collection = this.db.db().collection(tableName);
126
+ const query = this.genQuery({ resource, limit, offset, sort, filters });
127
+ const sortArray = sort.map((s) => {
128
+ return [s.field, this.SortDirectionsMap[s.direction]];
129
+ });
124
130
  const result = yield collection.find(query)
125
- .sort(sort)
131
+ .sort(sortArray)
126
132
  .skip(offset)
127
133
  .limit(limit)
128
134
  .toArray();
129
- return { data: result, total };
135
+ return result;
136
+ });
137
+ }
138
+ getCount(_a) {
139
+ return __awaiter(this, arguments, void 0, function* ({ resource, filters }) {
140
+ const collection = this.db.db().collection(resource.table);
141
+ const query = {};
142
+ for (const filter of filters) {
143
+ query[filter.field] = this.OperatorsMap[filter.operator](filter.value);
144
+ }
145
+ return yield collection.countDocuments(query);
130
146
  });
131
147
  }
132
148
  getMinMaxForColumnsWithOriginalTypes(_a) {
@@ -166,7 +182,8 @@ class MongoConnector extends AdminForthBaseConnector {
166
182
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
167
183
  const primaryKey = this.getPrimaryKey(resource);
168
184
  const collection = this.db.db().collection(resource.table);
169
- yield collection.deleteOne({ [primaryKey]: recordId });
185
+ const res = yield collection.deleteOne({ [primaryKey]: recordId });
186
+ return res.deletedCount > 0;
170
187
  });
171
188
  }
172
189
  close() {
@@ -184,46 +184,54 @@ class PostgresConnector extends AdminForthBaseConnector {
184
184
  }
185
185
  return value;
186
186
  }
187
+ whereClauseAndValues(resource, filters) {
188
+ let totalCounter = 1;
189
+ const where = filters.length ? `WHERE ${filters.map((f, i) => {
190
+ let placeholder = '$' + (totalCounter);
191
+ const fieldData = resource.dataSourceColumns.find((col) => col.name == f.field);
192
+ let field = f.field;
193
+ let operator = this.OperatorsMap[f.operator];
194
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
195
+ placeholder = `(${f.value.map((_, i) => `$${totalCounter + i}`).join(', ')})`;
196
+ totalCounter += f.value.length;
197
+ }
198
+ else {
199
+ totalCounter += 1;
200
+ }
201
+ if (fieldData._underlineType == 'uuid') {
202
+ field = `cast("${field}" as text)`;
203
+ }
204
+ else {
205
+ field = `"${field}"`;
206
+ }
207
+ return `${field} ${operator} ${placeholder}`;
208
+ }).join(' AND ')}` : '';
209
+ const filterValues = [];
210
+ filters.length ? filters.forEach((f) => {
211
+ // for arrays do set in map
212
+ let v = f.value;
213
+ if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
214
+ filterValues.push(`%${v}%`);
215
+ }
216
+ else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
217
+ filterValues.push(...v);
218
+ }
219
+ else {
220
+ filterValues.push(v);
221
+ }
222
+ }) : [];
223
+ return {
224
+ sql: where,
225
+ paramsCount: totalCounter,
226
+ values: filterValues,
227
+ };
228
+ }
187
229
  getDataWithOriginalTypes(_a) {
188
- return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
230
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
189
231
  const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
190
232
  const tableName = resource.table;
191
- let totalCounter = 1;
192
- const where = filters.length ? `WHERE ${filters.map((f, i) => {
193
- let placeholder = '$' + (totalCounter);
194
- const fieldData = resource.dataSourceColumns.find((col) => col.name == f.field);
195
- let field = f.field;
196
- let operator = this.OperatorsMap[f.operator];
197
- if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
198
- placeholder = `(${f.value.map((_, i) => `$${totalCounter + i}`).join(', ')})`;
199
- totalCounter += f.value.length;
200
- }
201
- else {
202
- totalCounter += 1;
203
- }
204
- if (fieldData._underlineType == 'uuid') {
205
- field = `cast("${field}" as text)`;
206
- }
207
- else {
208
- field = `"${field}"`;
209
- }
210
- return `${field} ${operator} ${placeholder}`;
211
- }).join(' AND ')}` : '';
212
- const filterValues = [];
213
- filters.length ? filters.forEach((f) => {
214
- // for arrays do set in map
215
- let v = f.value;
216
- if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
217
- filterValues.push(`%${v}%`);
218
- }
219
- else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
220
- filterValues.push(...v);
221
- }
222
- else {
223
- filterValues.push(v);
224
- }
225
- }) : [];
226
- const limitOffset = `LIMIT $${totalCounter} OFFSET $${totalCounter + 1}`;
233
+ const { sql: where, paramsCount, values: filterValues } = this.whereClauseAndValues(resource, filters);
234
+ const limitOffset = `LIMIT $${paramsCount} OFFSET $${paramsCount + 1}`;
227
235
  const d = [...filterValues, limit, offset];
228
236
  const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `"${s.field}" ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
229
237
  const selectQuery = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} ${limitOffset}`;
@@ -232,20 +240,21 @@ class PostgresConnector extends AdminForthBaseConnector {
232
240
  }
233
241
  const stmt = yield this.db.query(selectQuery, d);
234
242
  const rows = stmt.rows;
235
- let total = 0;
236
- if (getTotals) {
237
- total = (yield this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues)).rows[0].count;
238
- }
239
- return {
240
- data: rows.map((row) => {
241
- const newRow = {};
242
- for (const [key, value] of Object.entries(row)) {
243
- newRow[key] = value;
244
- }
245
- return newRow;
246
- }),
247
- total,
248
- };
243
+ return rows.map((row) => {
244
+ const newRow = {};
245
+ for (const [key, value] of Object.entries(row)) {
246
+ newRow[key] = value;
247
+ }
248
+ return newRow;
249
+ });
250
+ });
251
+ }
252
+ getCount(_a) {
253
+ return __awaiter(this, arguments, void 0, function* ({ resource, filters }) {
254
+ const tableName = resource.table;
255
+ const { sql: where, values: filterValues } = this.whereClauseAndValues(resource, filters);
256
+ const stmt = yield this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues);
257
+ return stmt.rows[0].count;
249
258
  });
250
259
  }
251
260
  getMinMaxForColumnsWithOriginalTypes(_a) {
@@ -283,7 +292,8 @@ class PostgresConnector extends AdminForthBaseConnector {
283
292
  }
284
293
  deleteRecord(_a) {
285
294
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
286
- yield this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
295
+ const res = yield this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
296
+ return res.rowCount > 0;
287
297
  });
288
298
  }
289
299
  close() {
@@ -149,39 +149,44 @@ class SQLiteConnector extends AdminForthBaseConnector {
149
149
  }
150
150
  return value;
151
151
  }
152
+ whereClause(filters) {
153
+ return filters.length ? `WHERE ${filters.map((f, i) => {
154
+ let placeholder = '?';
155
+ let field = f.field;
156
+ let operator = this.OperatorsMap[f.operator];
157
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
158
+ placeholder = `(${f.value.map(() => '?').join(', ')})`;
159
+ }
160
+ else if (f.operator == AdminForthFilterOperators.ILIKE) {
161
+ placeholder = `LOWER(?)`;
162
+ field = `LOWER(${f.field})`;
163
+ operator = 'LIKE';
164
+ }
165
+ return `${field} ${operator} ${placeholder}`;
166
+ }).join(' AND ')}` : '';
167
+ }
168
+ whereParams(filters) {
169
+ return filters.reduce((acc, f) => {
170
+ if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
171
+ acc.push(`%${f.value}%`);
172
+ }
173
+ else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
174
+ acc.push(...f.value);
175
+ }
176
+ else {
177
+ acc.push(f.value);
178
+ }
179
+ return acc;
180
+ }, []);
181
+ }
152
182
  getDataWithOriginalTypes(_a) {
153
- return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
183
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
154
184
  const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
155
185
  const tableName = resource.table;
156
- const where = filters.length ? `WHERE ${filters.map((f, i) => {
157
- let placeholder = '?';
158
- let field = f.field;
159
- let operator = this.OperatorsMap[f.operator];
160
- if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
161
- placeholder = `(${f.value.map(() => '?').join(', ')})`;
162
- }
163
- else if (f.operator == AdminForthFilterOperators.ILIKE) {
164
- placeholder = `LOWER(?)`;
165
- field = `LOWER(${f.field})`;
166
- operator = 'LIKE';
167
- }
168
- return `${field} ${operator} ${placeholder}`;
169
- }).join(' AND ')}` : '';
170
- const filterValues = [];
171
- filters.length ? filters.forEach((f) => {
172
- // for arrays do set in map
173
- const v = f.value;
174
- if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
175
- filterValues.push(`%${v}%`);
176
- }
177
- else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
178
- filterValues.push(...v);
179
- }
180
- else {
181
- filterValues.push(v);
182
- }
183
- }) : [];
186
+ const where = this.whereClause(filters);
187
+ const filterValues = this.whereParams(filters);
184
188
  const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
189
+ console.log('🪲 SQLITE Query', `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`, 'params:', [...filterValues, limit, offset]);
185
190
  const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`;
186
191
  const stmt = this.db.prepare(q);
187
192
  const d = [...filterValues, limit, offset];
@@ -189,21 +194,22 @@ class SQLiteConnector extends AdminForthBaseConnector {
189
194
  console.log('🪲 SQLITE Query', q, 'params:', d);
190
195
  }
191
196
  const rows = yield stmt.all(d);
192
- let total = 0;
193
- if (getTotals) {
194
- const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
195
- total = totalStmt.get([...filterValues])['COUNT(*)'];
196
- }
197
- return {
198
- data: rows.map((row) => {
199
- const newRow = {};
200
- for (const [key, value] of Object.entries(row)) {
201
- newRow[key] = value;
202
- }
203
- return newRow;
204
- }),
205
- total,
206
- };
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
+ getCount(_a) {
207
+ return __awaiter(this, arguments, void 0, function* ({ resource, filters }) {
208
+ const tableName = resource.table;
209
+ const where = this.whereClause(filters);
210
+ const filterValues = this.whereParams(filters);
211
+ const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
212
+ return totalStmt.get([...filterValues])['COUNT(*)'];
207
213
  });
208
214
  }
209
215
  getMinMaxForColumnsWithOriginalTypes(_a) {
@@ -241,7 +247,8 @@ class SQLiteConnector extends AdminForthBaseConnector {
241
247
  deleteRecord(_a) {
242
248
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
243
249
  const q = this.db.prepare(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`);
244
- yield q.run(recordId);
250
+ const res = yield q.run(recordId);
251
+ return res.changes > 0;
245
252
  });
246
253
  }
247
254
  close() {
package/dist/index.js CHANGED
@@ -23,10 +23,11 @@ import { ADMINFORTH_VERSION, listify } from './modules/utils.js';
23
23
  import { AdminForthFilterOperators, AdminForthDataTypes, AdminForthResourcePages, } from './types/AdminForthConfig.js';
24
24
  import AdminForthPlugin from './basePlugin.js';
25
25
  import ConfigValidator from './modules/configValidator.js';
26
- import AdminForthRestAPI from './modules/restApi.js';
26
+ import AdminForthRestAPI, { interpretResource } from './modules/restApi.js';
27
27
  import ClickhouseConnector from './dataConnectors/clickhouse.js';
28
28
  // exports
29
29
  export * from './types/AdminForthConfig.js';
30
+ export { interpretResource };
30
31
  export { AdminForthPlugin };
31
32
  class AdminForth {
32
33
  constructor(config) {
@@ -205,6 +206,9 @@ class AdminForth {
205
206
  return { ok: true };
206
207
  });
207
208
  }
209
+ resource(resourceId) {
210
+ return this.config.resources.find((res) => res.resourceId === resourceId);
211
+ }
208
212
  setupEndpoints(server) {
209
213
  this.restApi.registerEndpoints(server);
210
214
  }
@@ -0,0 +1,88 @@
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
+ // export interface IOperationalResource {
11
+ // get: (filters: IAdminForthFilter | IAdminForthFilter[]) => Promise<any[]>;
12
+ // list: (filters: IAdminForthFilter | IAdminForthFilter[], limit: number, offset: number, sort: IAdminForthSort | IAdminForthSort[]) => Promise<any[]>;
13
+ // count: (filters: IAdminForthFilter | IAdminForthFilter[]) => Promise<number>;
14
+ // create: (record: any) => Promise<any>;
15
+ // update: (primaryKey: any, record: any) => Promise<any>;
16
+ // delete: (primaryKey: any) => Promise<boolean>;
17
+ // deleteMany: (primaryKeys: any[]) => Promise<boolean>;
18
+ // }
19
+ // async getData({ resource, limit, offset, sort, filters }: {
20
+ // resource: AdminForthResource,
21
+ // limit: number,
22
+ // offset: number,
23
+ // sort: { field: string, direction: AdminForthSortDirections }[],
24
+ // filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
25
+ // }): Promise<{ data: any[], total: number }> {
26
+ function filtersIfFilter(filter) {
27
+ return (typeof filter === 'object' ? [filter] : filter);
28
+ }
29
+ function sortsIfSort(sort) {
30
+ return (typeof sort === 'object' ? [sort] : sort);
31
+ }
32
+ export class OperationalResource {
33
+ constructor(dataConnector, resourceConfig) {
34
+ this.dataConnector = dataConnector;
35
+ this.resourceConfig = resourceConfig;
36
+ }
37
+ get(filter) {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ return yield this.dataConnector.getData({
40
+ resource: this.resourceConfig,
41
+ filters: filtersIfFilter(filter),
42
+ limit: 1,
43
+ offset: 0,
44
+ sort: [],
45
+ })[0];
46
+ });
47
+ }
48
+ list(filter, limit, offset, sort) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ const { data } = yield this.dataConnector.getData({
51
+ resource: this.resourceConfig,
52
+ filters: filtersIfFilter(filter),
53
+ limit,
54
+ offset,
55
+ sort: sortsIfSort(sort),
56
+ getTotals: false,
57
+ });
58
+ return data;
59
+ });
60
+ }
61
+ count(filter) {
62
+ return __awaiter(this, void 0, void 0, function* () {
63
+ return yield this.dataConnector.getCount({
64
+ resource: this.resourceConfig,
65
+ filters: filtersIfFilter(filter),
66
+ });
67
+ });
68
+ }
69
+ create(record) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ return yield this.dataConnector.createRecord({ resource: this.resourceConfig, record });
72
+ });
73
+ }
74
+ update(primaryKey, record) {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ return yield this.dataConnector.updateRecord({
77
+ resource: this.resourceConfig,
78
+ recordId: primaryKey,
79
+ newValues: record
80
+ });
81
+ });
82
+ }
83
+ delete(primaryKey) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ return yield this.dataConnector.deleteRecord({ resource: this.resourceConfig, recordId: primaryKey });
86
+ });
87
+ }
88
+ }
@@ -10,6 +10,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { AdminForthFilterOperators, AdminForthDataTypes, AllowedActionsEnum, ActionCheckSource } from "../types/AdminForthConfig.js";
11
11
  import { ADMINFORTH_VERSION, listify } from './utils.js';
12
12
  import AdminForthAuth from "../auth.js";
13
+ export function interpretResource(adminUser, resource, meta, source) {
14
+ return __awaiter(this, void 0, void 0, function* () {
15
+ var _a;
16
+ // if (process.env.HEAVY_DEBUG) {
17
+ // console.log('🪲Interpreting resource', resource.resourceId, source, 'adminUser', adminUser);
18
+ // }
19
+ const allowedActions = {};
20
+ yield Promise.all(Object.entries(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.allowedActions) || {}).map((_b) => __awaiter(this, [_b], void 0, function* ([key, value]) {
21
+ if (process.env.HEAVY_DEBUG) {
22
+ console.log('🪲checking for allowed call', key, 'value:', value, 'typeof', typeof value);
23
+ }
24
+ // if callable then call
25
+ if (typeof value === 'function') {
26
+ allowedActions[key] = yield value({ adminUser, resource, meta, source });
27
+ }
28
+ else {
29
+ allowedActions[key] = value;
30
+ }
31
+ })));
32
+ return { allowedActions };
33
+ });
34
+ }
13
35
  export default class AdminForthRestAPI {
14
36
  constructor(adminforth) {
15
37
  this.adminforth = adminforth;
@@ -159,12 +181,10 @@ export default class AdminForthRestAPI {
159
181
  };
160
182
  function processMenuItem(menuItem) {
161
183
  return __awaiter(this, void 0, void 0, function* () {
162
- console.log('super hueta');
163
184
  if (menuItem.badge) {
164
- console.log('hueta');
165
- // if (typeof menuItem.badge !== 'string') {
166
- menuItem.badge = yield menuItem.badge(adminUser);
167
- // }
185
+ if (typeof menuItem.badge === 'function') {
186
+ menuItem.badge = yield menuItem.badge(adminUser);
187
+ }
168
188
  }
169
189
  });
170
190
  }
@@ -185,12 +205,12 @@ export default class AdminForthRestAPI {
185
205
  continue;
186
206
  }
187
207
  }
188
- processMenuItem(newChild);
208
+ yield processMenuItem(newChild);
189
209
  newChildren.push(newChild);
190
210
  }
191
211
  newMenuItem = Object.assign(Object.assign({}, newMenuItem), { children: newChildren });
192
212
  }
193
- processMenuItem(newMenuItem);
213
+ yield processMenuItem(newMenuItem);
194
214
  newMenu.push(newMenuItem);
195
215
  }
196
216
  const announcementBadge = (_o = (_m = this.adminforth.config.customization).announcementBadge) === null || _o === void 0 ? void 0 : _o.call(_m, adminUser);
@@ -217,28 +237,6 @@ export default class AdminForthRestAPI {
217
237
  };
218
238
  }),
219
239
  });
220
- function interpretResource(adminUser, resource, meta, source) {
221
- return __awaiter(this, void 0, void 0, function* () {
222
- var _a;
223
- // if (process.env.HEAVY_DEBUG) {
224
- // console.log('🪲Interpreting resource', resource.resourceId, source, 'adminUser', adminUser);
225
- // }
226
- const allowedActions = {};
227
- yield Promise.all(Object.entries(((_a = resource.options) === null || _a === void 0 ? void 0 : _a.allowedActions) || {}).map((_b) => __awaiter(this, [_b], void 0, function* ([key, value]) {
228
- if (process.env.HEAVY_DEBUG) {
229
- console.log('🪲checking for allowed call', key, 'value:', value, 'typeof', typeof value);
230
- }
231
- // if callable then call
232
- if (typeof value === 'function') {
233
- allowedActions[key] = yield value({ adminUser, resource, meta, source });
234
- }
235
- else {
236
- allowedActions[key] = value;
237
- }
238
- })));
239
- return { allowedActions };
240
- });
241
- }
242
240
  function checkAccess(action, allowedActions) {
243
241
  const allowed = allowedActions[action];
244
242
  if (allowed !== true) {