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.
- package/dataConnectors/baseConnector.ts +26 -14
- package/dataConnectors/clickhouse.ts +57 -37
- package/dataConnectors/mongo.ts +45 -14
- package/dataConnectors/postgres.ts +53 -36
- package/dataConnectors/sqlite.ts +37 -35
- package/dist/dataConnectors/baseConnector.js +16 -7
- package/dist/dataConnectors/clickhouse.js +58 -48
- package/dist/dataConnectors/mongo.js +29 -12
- package/dist/dataConnectors/postgres.js +62 -52
- package/dist/dataConnectors/sqlite.js +52 -45
- package/dist/index.js +5 -1
- package/dist/modules/operationalResource.js +88 -0
- package/dist/modules/restApi.js +27 -29
- package/dist/spa/index.html +4 -4
- package/dist/spa/package-lock.json +421 -6
- package/dist/spa/package.json +10 -2
- package/dist/spa/src/App.vue +236 -94
- package/dist/spa/src/assets/base.css +2 -0
- package/dist/spa/src/assets/logo.svg +19 -1
- package/dist/spa/src/components/AcceptModal.vue +3 -10
- package/dist/spa/src/components/Breadcrumbs.vue +3 -2
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
- package/dist/spa/src/components/CustomDatePicker.vue +25 -10
- package/dist/spa/src/components/CustomDateRangePicker.vue +14 -5
- package/dist/spa/src/components/Dropdown.vue +19 -5
- package/dist/spa/src/components/Filters.vue +103 -38
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +205 -116
- package/dist/spa/{spa/src → src}/components/ResourceListTable.vue +6 -3
- package/dist/spa/{spa/src → src}/components/Toast.vue +9 -3
- package/dist/spa/src/components/ValueRenderer.vue +30 -8
- package/dist/spa/src/index.scss +2 -1
- package/dist/spa/src/main.ts +2 -2
- package/dist/spa/src/router/index.ts +29 -19
- package/dist/spa/src/stores/core.ts +65 -59
- package/dist/spa/src/stores/modal.ts +13 -3
- package/dist/spa/src/types/AdminForthConfig.ts +1477 -0
- package/dist/spa/src/types/FrontendAPI.ts +121 -0
- package/dist/spa/src/utils.ts +69 -10
- package/dist/spa/src/views/CreateView.vue +69 -16
- package/dist/spa/src/views/EditView.vue +68 -14
- package/dist/spa/src/views/ListView.vue +100 -371
- package/dist/spa/src/views/LoginView.vue +67 -29
- package/dist/spa/src/views/ResourceParent.vue +1 -2
- package/dist/spa/src/views/ShowView.vue +116 -25
- package/dist/spa/tailwind.config.js +8 -3
- package/dist/spa/vite.config.ts +13 -0
- package/dist/types/AdminForthConfig.js +37 -0
- package/index.ts +12 -3
- package/modules/operationalResource.ts +97 -0
- package/modules/restApi.ts +31 -31
- package/package.json +1 -1
- package/types/AdminForthConfig.ts +91 -8
- package/dist/spa/.vscode/extensions.json +0 -6
- package/dist/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/.eslintrc.cjs +0 -14
- package/dist/spa/spa/.vscode/extensions.json +0 -6
- package/dist/spa/spa/README.md +0 -39
- package/dist/spa/spa/env.d.ts +0 -1
- package/dist/spa/spa/index.html +0 -23
- package/dist/spa/spa/package-lock.json +0 -4573
- package/dist/spa/spa/package.json +0 -49
- package/dist/spa/spa/postcss.config.js +0 -6
- package/dist/spa/spa/public/favicon.ico +0 -0
- package/dist/spa/spa/src/App.vue +0 -314
- package/dist/spa/spa/src/assets/base.css +0 -0
- package/dist/spa/spa/src/assets/logo.svg +0 -19
- package/dist/spa/spa/src/components/AcceptModal.vue +0 -45
- package/dist/spa/spa/src/components/Breadcrumbs.vue +0 -40
- package/dist/spa/spa/src/components/BreadcrumbsWithButtons.vue +0 -26
- package/dist/spa/spa/src/components/CustomDatePicker.vue +0 -174
- package/dist/spa/spa/src/components/CustomDateRangePicker.vue +0 -218
- package/dist/spa/spa/src/components/Dropdown.vue +0 -168
- package/dist/spa/spa/src/components/Filters.vue +0 -222
- package/dist/spa/spa/src/components/HelloWorld.vue +0 -17
- package/dist/spa/spa/src/components/MenuLink.vue +0 -24
- package/dist/spa/spa/src/components/ResourceForm.vue +0 -289
- package/dist/spa/spa/src/components/SingleSkeletLoader.vue +0 -13
- package/dist/spa/spa/src/components/ValueRenderer.vue +0 -66
- package/dist/spa/spa/src/components/icons/IconCalendar.vue +0 -5
- package/dist/spa/spa/src/components/icons/IconCommunity.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconDocumentation.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconEcosystem.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconSupport.vue +0 -7
- package/dist/spa/spa/src/components/icons/IconTime.vue +0 -5
- package/dist/spa/spa/src/components/icons/IconTooling.vue +0 -19
- package/dist/spa/spa/src/index.scss +0 -27
- package/dist/spa/spa/src/main.ts +0 -18
- package/dist/spa/spa/src/router/index.ts +0 -63
- package/dist/spa/spa/src/stores/core.ts +0 -144
- package/dist/spa/spa/src/stores/modal.ts +0 -48
- package/dist/spa/spa/src/utils.ts +0 -103
- package/dist/spa/spa/src/views/CreateView.vue +0 -156
- package/dist/spa/spa/src/views/EditView.vue +0 -157
- package/dist/spa/spa/src/views/HomeView.vue +0 -8
- package/dist/spa/spa/src/views/ListView.vue +0 -258
- package/dist/spa/spa/src/views/LoginView.vue +0 -143
- package/dist/spa/spa/src/views/ResourceParent.vue +0 -17
- package/dist/spa/spa/src/views/ShowView.vue +0 -184
- package/dist/spa/spa/tailwind.config.js +0 -17
- package/dist/spa/spa/tsconfig.app.json +0 -14
- package/dist/spa/spa/tsconfig.json +0 -11
- package/dist/spa/spa/tsconfig.node.json +0 -19
- package/dist/spa/spa/vite.config.ts +0 -56
- package/dist/spa/src/views/HomeView.vue +0 -8
- package/dist/types.js +0 -30
- /package/dist/spa/{spa/public → public}/assets/favicon.png +0 -0
- /package/dist/spa/{spa/src → src}/components/CustomRangePicker.vue +0 -0
- /package/dist/spa/{spa/src → src}/components/SkeleteLoader.vue +0 -0
- /package/dist/spa/{spa/src → src}/composables/useFrontendApi.ts +0 -0
- /package/dist/spa/{spa/src → src}/composables/useStores.ts +0 -0
- /package/dist/spa/{spa/src → src}/spa_types/core.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/filters.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/toast.ts +0 -0
- /package/dist/spa/{spa/src → src}/stores/user.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { get } from "http";
|
|
2
|
+
import { AdminForthResource, IAdminForthDataSourceConnectorBase, AdminForthSortDirections, AdminForthFilterOperators, AdminForthResourceColumn, IAdminForthSort, IAdminForthFilter } from "../types/AdminForthConfig.js";
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export default class AdminForthBaseConnector implements IAdminForthDataSourceConnectorBase {
|
|
@@ -17,19 +18,21 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
|
|
|
17
18
|
offset: 0,
|
|
18
19
|
sort: [],
|
|
19
20
|
filters: [{ field: this.getPrimaryKey(resource), operator: AdminForthFilterOperators.EQ, value: id }],
|
|
20
|
-
getTotals: false
|
|
21
21
|
});
|
|
22
|
-
return data.
|
|
22
|
+
return data.length > 0 ? data[0] : null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
getDataWithOriginalTypes({ resource, limit, offset, sort, filters
|
|
25
|
+
getDataWithOriginalTypes({ resource, limit, offset, sort, filters }: {
|
|
26
26
|
resource: AdminForthResource,
|
|
27
27
|
limit: number,
|
|
28
28
|
offset: number,
|
|
29
|
-
sort:
|
|
30
|
-
filters:
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
sort: IAdminForthSort[],
|
|
30
|
+
filters: IAdminForthFilter[],
|
|
31
|
+
}): Promise<any[]> {
|
|
32
|
+
throw new Error('Method not implemented.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getCount({ resource, filters }: { resource: AdminForthResource; filters: { field: string; operator: AdminForthFilterOperators; value: any; }[]; }): Promise<number> {
|
|
33
36
|
throw new Error('Method not implemented.');
|
|
34
37
|
}
|
|
35
38
|
|
|
@@ -67,17 +70,18 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
|
|
|
67
70
|
throw new Error('Method not implemented.');
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
deleteRecord({ resource, recordId }: { resource: AdminForthResource; recordId: string; }): Promise<
|
|
73
|
+
deleteRecord({ resource, recordId }: { resource: AdminForthResource; recordId: string; }): Promise<boolean> {
|
|
71
74
|
throw new Error('Method not implemented.');
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
|
|
75
|
-
async getData({ resource, limit, offset, sort, filters }: {
|
|
78
|
+
async getData({ resource, limit, offset, sort, filters, getTotals }: {
|
|
76
79
|
resource: AdminForthResource,
|
|
77
80
|
limit: number,
|
|
78
81
|
offset: number,
|
|
79
82
|
sort: { field: string, direction: AdminForthSortDirections }[],
|
|
80
|
-
filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
|
|
83
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[],
|
|
84
|
+
getTotals: boolean,
|
|
81
85
|
}): Promise<{ data: any[], total: number }> {
|
|
82
86
|
if (filters) {
|
|
83
87
|
filters.map((f) => {
|
|
@@ -89,15 +93,23 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
|
|
|
89
93
|
});
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
const
|
|
96
|
+
const promises: Promise<any>[] = [this.getDataWithOriginalTypes({ resource, limit, offset, sort, filters })];
|
|
97
|
+
if (getTotals) {
|
|
98
|
+
promises.push(this.getCount({ resource, filters }));
|
|
99
|
+
} else {
|
|
100
|
+
promises.push(Promise.resolve(undefined));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const [data, total] = await Promise.all(promises);
|
|
104
|
+
|
|
93
105
|
// call getFieldValue for each field
|
|
94
|
-
|
|
106
|
+
data.map((record) => {
|
|
95
107
|
for (const col of resource.dataSourceColumns) {
|
|
96
108
|
record[col.name] = this.getFieldValue(col, record[col.name]);
|
|
97
109
|
}
|
|
98
110
|
});
|
|
99
111
|
|
|
100
|
-
return
|
|
112
|
+
return { data, total };
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
async getMinMaxForColumns({ resource, columns }: { resource: AdminForthResource; columns: AdminForthResourceColumn[]; }): Promise<{ [key: string]: { min: any; max: any; }; }> {
|
|
@@ -172,19 +172,11 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
|
|
|
172
172
|
[AdminForthSortDirections.desc]: 'DESC',
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
sort: { field: string, direction: AdminForthSortDirections }[],
|
|
181
|
-
filters: { field: string, operator: AdminForthFilterOperators, value: any }[],
|
|
182
|
-
getTotals?: boolean,
|
|
183
|
-
}): Promise<{ data: any[], total: number }> {
|
|
184
|
-
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
185
|
-
const tableName = resource.table;
|
|
186
|
-
|
|
187
|
-
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
175
|
+
whereClause(
|
|
176
|
+
resource: AdminForthResource,
|
|
177
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
|
|
178
|
+
): string {
|
|
179
|
+
return filters.length ? `WHERE ${filters.map((f, i) => {
|
|
188
180
|
const column = resource.dataSourceColumns.find((col) => col.name == f.field);
|
|
189
181
|
let placeholder = `{f${i}:${column._underlineType}}`;
|
|
190
182
|
let field = f.field;
|
|
@@ -197,9 +189,12 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
|
|
|
197
189
|
|
|
198
190
|
return `${field} ${operator} ${placeholder}`
|
|
199
191
|
}).join(' AND ')}` : '';
|
|
192
|
+
}
|
|
200
193
|
|
|
194
|
+
whereParams(
|
|
195
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
|
|
196
|
+
): any {
|
|
201
197
|
const params = {};
|
|
202
|
-
|
|
203
198
|
filters.length ? filters.forEach((f, i) => {
|
|
204
199
|
// for arrays do set in map
|
|
205
200
|
const v = f.value;
|
|
@@ -215,6 +210,23 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
|
|
|
215
210
|
}
|
|
216
211
|
}) : [];
|
|
217
212
|
|
|
213
|
+
return params;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }: {
|
|
217
|
+
resource: AdminForthResource,
|
|
218
|
+
limit: number,
|
|
219
|
+
offset: number,
|
|
220
|
+
sort: { field: string, direction: AdminForthSortDirections }[],
|
|
221
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[],
|
|
222
|
+
}): Promise<any[]> {
|
|
223
|
+
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
224
|
+
const tableName = resource.table;
|
|
225
|
+
|
|
226
|
+
const where = this.whereClause(resource, filters);
|
|
227
|
+
|
|
228
|
+
const params = this.whereParams(filters);
|
|
229
|
+
|
|
218
230
|
const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
|
|
219
231
|
|
|
220
232
|
|
|
@@ -233,27 +245,33 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
|
|
|
233
245
|
|
|
234
246
|
const rows = await stmt.json();
|
|
235
247
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
total = countResp[0]['COUNT()'];
|
|
245
|
-
}
|
|
248
|
+
return rows.map((row) => {
|
|
249
|
+
const newRow = {};
|
|
250
|
+
for (const [key, value] of Object.entries(row)) {
|
|
251
|
+
newRow[key] = value;
|
|
252
|
+
}
|
|
253
|
+
return newRow;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
246
256
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
+
async getCount({
|
|
258
|
+
resource,
|
|
259
|
+
filters,
|
|
260
|
+
}: {
|
|
261
|
+
resource: AdminForthResource;
|
|
262
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[];
|
|
263
|
+
}): Promise<number> {
|
|
264
|
+
const tableName = resource.table;
|
|
265
|
+
const where = this.whereClause(resource, filters);
|
|
266
|
+
const d = this.whereParams(filters);
|
|
267
|
+
|
|
268
|
+
const countQ = await this.client.query({
|
|
269
|
+
query: `SELECT COUNT(*) FROM ${tableName} ${where}`,
|
|
270
|
+
format: 'JSONEachRow',
|
|
271
|
+
query_params: d,
|
|
272
|
+
});
|
|
273
|
+
const countResp = await countQ.json()
|
|
274
|
+
return countResp[0]['COUNT()'];
|
|
257
275
|
}
|
|
258
276
|
|
|
259
277
|
async getMinMaxForColumnsWithOriginalTypes({ resource, columns }: { resource: AdminForthResource, columns: AdminForthResourceColumn[] }): Promise<{ [key: string]: { min: any, max: any } }> {
|
|
@@ -298,16 +316,18 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
|
|
|
298
316
|
);
|
|
299
317
|
}
|
|
300
318
|
|
|
301
|
-
async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }) {
|
|
319
|
+
async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }): Promise<boolean> {
|
|
302
320
|
const pkColumn = resource.dataSourceColumns.find((col) => col.primaryKey);
|
|
303
|
-
await this.client.command(
|
|
321
|
+
const res = await this.client.command(
|
|
304
322
|
{
|
|
305
323
|
query: `ALTER TABLE ${this.dbName}.${resource.table} DELETE WHERE ${
|
|
306
324
|
pkColumn.name
|
|
307
325
|
} = {recordId:${pkColumn._underlineType}}`,
|
|
308
326
|
query_params: { recordId },
|
|
309
|
-
|
|
327
|
+
}
|
|
310
328
|
);
|
|
329
|
+
// todo test what is in res
|
|
330
|
+
return res;
|
|
311
331
|
}
|
|
312
332
|
|
|
313
333
|
close() {
|
package/dataConnectors/mongo.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
import { MongoClient } from 'mongodb';
|
|
3
|
-
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections,
|
|
3
|
+
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections,
|
|
4
|
+
IAdminForthDataSourceConnector, AdminForthResource } from '../types/AdminForthConfig.js';
|
|
4
5
|
import AdminForthBaseConnector from './baseConnector.js';
|
|
5
6
|
|
|
6
7
|
class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataSourceConnector {
|
|
@@ -104,28 +105,57 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
|
|
|
104
105
|
return value ? 1 : 0;
|
|
105
106
|
}
|
|
106
107
|
return value;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
async getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals }) {
|
|
110
|
-
// const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
|
|
111
|
-
const tableName = resource.table;
|
|
108
|
+
}
|
|
112
109
|
|
|
113
|
-
|
|
110
|
+
async genQuery({ resource, limit, offset, sort, filters }) {
|
|
111
|
+
const collection = this.db.db().collection(resource.table);
|
|
114
112
|
const query = {};
|
|
115
113
|
for (const filter of filters) {
|
|
116
114
|
query[filter.field] = this.OperatorsMap[filter.operator](filter.value);
|
|
117
115
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
return { collection, query };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }:
|
|
120
|
+
{
|
|
121
|
+
resource: AdminForthResource,
|
|
122
|
+
limit: number,
|
|
123
|
+
offset: number,
|
|
124
|
+
sort: { field: string, direction: AdminForthSortDirections }[],
|
|
125
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
|
|
121
126
|
}
|
|
127
|
+
): Promise<any[]> {
|
|
128
|
+
|
|
129
|
+
// const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
|
|
130
|
+
const tableName = resource.table;
|
|
131
|
+
|
|
132
|
+
const collection = this.db.db().collection(tableName);
|
|
133
|
+
const query = this.genQuery({ resource, limit, offset, sort, filters });
|
|
134
|
+
|
|
135
|
+
const sortArray: any[] = sort.map((s) => {
|
|
136
|
+
return [s.field, this.SortDirectionsMap[s.direction]];
|
|
137
|
+
});
|
|
138
|
+
|
|
122
139
|
const result = await collection.find(query)
|
|
123
|
-
.sort(
|
|
140
|
+
.sort(sortArray)
|
|
124
141
|
.skip(offset)
|
|
125
142
|
.limit(limit)
|
|
126
143
|
.toArray();
|
|
127
144
|
|
|
128
|
-
return
|
|
145
|
+
return result
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getCount({ resource, filters }: {
|
|
149
|
+
resource: AdminForthResource,
|
|
150
|
+
filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
|
|
151
|
+
}): Promise<number> {
|
|
152
|
+
|
|
153
|
+
const collection = this.db.db().collection(resource.table);
|
|
154
|
+
const query = {};
|
|
155
|
+
for (const filter of filters) {
|
|
156
|
+
query[filter.field] = this.OperatorsMap[filter.operator](filter.value);
|
|
157
|
+
}
|
|
158
|
+
return await collection.countDocuments(query);
|
|
129
159
|
}
|
|
130
160
|
|
|
131
161
|
async getMinMaxForColumnsWithOriginalTypes({ resource, columns }) {
|
|
@@ -158,10 +188,11 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
|
|
|
158
188
|
await collection.updateOne({ [this.getPrimaryKey(resource)]: recordId }, { $set: newValues });
|
|
159
189
|
}
|
|
160
190
|
|
|
161
|
-
async deleteRecord({ resource, recordId }) {
|
|
191
|
+
async deleteRecord({ resource, recordId }): Promise<boolean> {
|
|
162
192
|
const primaryKey = this.getPrimaryKey(resource);
|
|
163
193
|
const collection = this.db.db().collection(resource.table);
|
|
164
|
-
await collection.deleteOne({ [primaryKey]: recordId });
|
|
194
|
+
const res = await collection.deleteOne({ [primaryKey]: recordId });
|
|
195
|
+
return res.deletedCount > 0;
|
|
165
196
|
}
|
|
166
197
|
|
|
167
198
|
async close() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
import pkg from 'pg';
|
|
3
|
-
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, IAdminForthDataSourceConnector } from '../types/AdminForthConfig.js';
|
|
3
|
+
import { AdminForthDataTypes, AdminForthResource, AdminForthFilterOperators, AdminForthSortDirections, IAdminForthDataSourceConnector } from '../types/AdminForthConfig.js';
|
|
4
4
|
import AdminForthBaseConnector from './baseConnector.js';
|
|
5
5
|
const { Client } = pkg;
|
|
6
6
|
|
|
@@ -168,24 +168,26 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
|
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
setFieldValue(field, value) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
|
|
176
|
-
return dayjs(value);
|
|
177
|
-
} else if (field._underlineType == 'varchar') {
|
|
178
|
-
return dayjs(value).toISOString();
|
|
179
|
-
}
|
|
180
|
-
} else if (field.type == AdminForthDataTypes.BOOLEAN) {
|
|
181
|
-
return value ? 1 : 0;
|
|
171
|
+
if (field.type == AdminForthDataTypes.DATETIME) {
|
|
172
|
+
if (!value) {
|
|
173
|
+
return null;
|
|
182
174
|
}
|
|
183
|
-
|
|
175
|
+
if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
|
|
176
|
+
return dayjs(value);
|
|
177
|
+
} else if (field._underlineType == 'varchar') {
|
|
178
|
+
return dayjs(value).toISOString();
|
|
179
|
+
}
|
|
180
|
+
} else if (field.type == AdminForthDataTypes.BOOLEAN) {
|
|
181
|
+
return value ? 1 : 0;
|
|
184
182
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
whereClauseAndValues(resource: AdminForthResource, filters: { field: string, operator: AdminForthFilterOperators, value: any }[]) : {
|
|
187
|
+
sql: string,
|
|
188
|
+
paramsCount: number,
|
|
189
|
+
values: any[],
|
|
190
|
+
} {
|
|
189
191
|
|
|
190
192
|
let totalCounter = 1;
|
|
191
193
|
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
@@ -201,9 +203,9 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
if (fieldData._underlineType == 'uuid') {
|
|
204
|
-
|
|
206
|
+
field = `cast("${field}" as text)`
|
|
205
207
|
} else {
|
|
206
|
-
|
|
208
|
+
field = `"${field}"`
|
|
207
209
|
}
|
|
208
210
|
return `${field} ${operator} ${placeholder}`;
|
|
209
211
|
}).join(' AND ')}` : '';
|
|
@@ -221,8 +223,22 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
|
|
|
221
223
|
filterValues.push(v);
|
|
222
224
|
}
|
|
223
225
|
}) : [];
|
|
226
|
+
return {
|
|
227
|
+
sql: where,
|
|
228
|
+
paramsCount: totalCounter,
|
|
229
|
+
values: filterValues,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
}
|
|
224
233
|
|
|
225
|
-
|
|
234
|
+
|
|
235
|
+
async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }): Promise<any[]> {
|
|
236
|
+
const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
|
|
237
|
+
const tableName = resource.table;
|
|
238
|
+
|
|
239
|
+
const { sql: where, paramsCount, values: filterValues } = this.whereClauseAndValues(resource, filters);
|
|
240
|
+
|
|
241
|
+
const limitOffset = `LIMIT $${paramsCount} OFFSET $${paramsCount + 1}`;
|
|
226
242
|
const d = [...filterValues, limit, offset];
|
|
227
243
|
const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `"${s.field}" ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
|
|
228
244
|
const selectQuery = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} ${limitOffset}`;
|
|
@@ -231,20 +247,20 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
|
|
|
231
247
|
}
|
|
232
248
|
const stmt = await this.db.query(selectQuery, d);
|
|
233
249
|
const rows = stmt.rows;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
|
|
250
|
+
return rows.map((row) => {
|
|
251
|
+
const newRow = {};
|
|
252
|
+
for (const [key, value] of Object.entries(row)) {
|
|
253
|
+
newRow[key] = value;
|
|
254
|
+
}
|
|
255
|
+
return newRow;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async getCount({ resource, filters }: { resource: AdminForthResource; filters: { field: string, operator: AdminForthFilterOperators, value: any }[]; }): Promise<number> {
|
|
260
|
+
const tableName = resource.table;
|
|
261
|
+
const { sql: where, values: filterValues } = this.whereClauseAndValues(resource, filters);
|
|
262
|
+
const stmt = await this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues);
|
|
263
|
+
return stmt.rows[0].count;
|
|
248
264
|
}
|
|
249
265
|
|
|
250
266
|
async getMinMaxForColumnsWithOriginalTypes({ resource, columns }) {
|
|
@@ -277,8 +293,9 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
|
|
|
277
293
|
await this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`, values);
|
|
278
294
|
}
|
|
279
295
|
|
|
280
|
-
async deleteRecord({ resource, recordId }) {
|
|
281
|
-
|
|
296
|
+
async deleteRecord({ resource, recordId }): Promise<boolean> {
|
|
297
|
+
const res = await this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
|
|
298
|
+
return res.rowCount > 0;
|
|
282
299
|
}
|
|
283
300
|
|
|
284
301
|
async close() {
|
package/dataConnectors/sqlite.ts
CHANGED
|
@@ -135,12 +135,8 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
|
|
|
135
135
|
[AdminForthSortDirections.desc]: 'DESC',
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
141
|
-
const tableName = resource.table;
|
|
142
|
-
|
|
143
|
-
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
138
|
+
whereClause(filters) {
|
|
139
|
+
return filters.length ? `WHERE ${filters.map((f, i) => {
|
|
144
140
|
let placeholder = '?';
|
|
145
141
|
let field = f.field;
|
|
146
142
|
let operator = this.OperatorsMap[f.operator];
|
|
@@ -154,25 +150,31 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
|
|
|
154
150
|
|
|
155
151
|
return `${field} ${operator} ${placeholder}`
|
|
156
152
|
}).join(' AND ')}` : '';
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
filters.length ? filters.forEach((f) => {
|
|
161
|
-
// for arrays do set in map
|
|
162
|
-
const v = f.value;
|
|
163
|
-
|
|
153
|
+
}
|
|
154
|
+
whereParams(filters) {
|
|
155
|
+
return filters.reduce((acc, f) => {
|
|
164
156
|
if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
|
|
165
|
-
|
|
157
|
+
acc.push(`%${f.value}%`);
|
|
166
158
|
} else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
|
|
167
|
-
|
|
159
|
+
acc.push(...f.value);
|
|
168
160
|
} else {
|
|
169
|
-
|
|
161
|
+
acc.push(f.value);
|
|
170
162
|
}
|
|
171
|
-
|
|
163
|
+
return acc;
|
|
164
|
+
}, []);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async getDataWithOriginalTypes({ resource, limit, offset, sort, filters }): Promise<any[]> {
|
|
168
|
+
const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
|
|
169
|
+
const tableName = resource.table;
|
|
170
|
+
|
|
171
|
+
const where = this.whereClause(filters);
|
|
172
|
+
|
|
173
|
+
const filterValues = this.whereParams(filters);
|
|
172
174
|
|
|
173
175
|
const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
|
|
174
176
|
|
|
175
|
-
|
|
177
|
+
console.log('🪲 SQLITE Query', `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`, 'params:', [...filterValues, limit, offset]);
|
|
176
178
|
const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`;
|
|
177
179
|
const stmt = this.db.prepare(q);
|
|
178
180
|
const d = [...filterValues, limit, offset];
|
|
@@ -182,22 +184,21 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
|
|
|
182
184
|
}
|
|
183
185
|
const rows = await stmt.all(d);
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
return rows.map((row) => {
|
|
188
|
+
const newRow = {};
|
|
189
|
+
for (const [key, value] of Object.entries(row)) {
|
|
190
|
+
newRow[key] = value;
|
|
191
|
+
}
|
|
192
|
+
return newRow;
|
|
193
|
+
})
|
|
194
|
+
}
|
|
190
195
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return newRow;
|
|
198
|
-
}),
|
|
199
|
-
total,
|
|
200
|
-
};
|
|
196
|
+
async getCount({ resource, filters }) {
|
|
197
|
+
const tableName = resource.table;
|
|
198
|
+
const where = this.whereClause(filters);
|
|
199
|
+
const filterValues = this.whereParams(filters);
|
|
200
|
+
const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
|
|
201
|
+
return totalStmt.get([...filterValues])['COUNT(*)'];
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
async getMinMaxForColumnsWithOriginalTypes({ resource, columns }: { resource: AdminForthResource, columns: AdminForthResourceColumn[] }): Promise<{ [key: string]: { min: any, max: any } }> {
|
|
@@ -232,9 +233,10 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
|
|
|
232
233
|
await q.run(values);
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }) {
|
|
236
|
+
async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }): Promise<boolean> {
|
|
236
237
|
const q = this.db.prepare(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`);
|
|
237
|
-
await q.run(recordId);
|
|
238
|
+
const res = await q.run(recordId);
|
|
239
|
+
return res.changes > 0;
|
|
238
240
|
}
|
|
239
241
|
|
|
240
242
|
close() {
|
|
@@ -24,12 +24,14 @@ export default class AdminForthBaseConnector {
|
|
|
24
24
|
offset: 0,
|
|
25
25
|
sort: [],
|
|
26
26
|
filters: [{ field: this.getPrimaryKey(resource), operator: AdminForthFilterOperators.EQ, value: id }],
|
|
27
|
-
getTotals: false
|
|
28
27
|
});
|
|
29
|
-
return data.
|
|
28
|
+
return data.length > 0 ? data[0] : null;
|
|
30
29
|
});
|
|
31
30
|
}
|
|
32
|
-
getDataWithOriginalTypes({ resource, limit, offset, sort, filters
|
|
31
|
+
getDataWithOriginalTypes({ resource, limit, offset, sort, filters }) {
|
|
32
|
+
throw new Error('Method not implemented.');
|
|
33
|
+
}
|
|
34
|
+
getCount({ resource, filters }) {
|
|
33
35
|
throw new Error('Method not implemented.');
|
|
34
36
|
}
|
|
35
37
|
discoverFields(resource) {
|
|
@@ -63,7 +65,7 @@ export default class AdminForthBaseConnector {
|
|
|
63
65
|
throw new Error('Method not implemented.');
|
|
64
66
|
}
|
|
65
67
|
getData(_a) {
|
|
66
|
-
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
|
|
68
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
|
|
67
69
|
if (filters) {
|
|
68
70
|
filters.map((f) => {
|
|
69
71
|
if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
|
|
@@ -74,14 +76,21 @@ export default class AdminForthBaseConnector {
|
|
|
74
76
|
}
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
|
-
const
|
|
79
|
+
const promises = [this.getDataWithOriginalTypes({ resource, limit, offset, sort, filters })];
|
|
80
|
+
if (getTotals) {
|
|
81
|
+
promises.push(this.getCount({ resource, filters }));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
promises.push(Promise.resolve(undefined));
|
|
85
|
+
}
|
|
86
|
+
const [data, total] = yield Promise.all(promises);
|
|
78
87
|
// call getFieldValue for each field
|
|
79
|
-
|
|
88
|
+
data.map((record) => {
|
|
80
89
|
for (const col of resource.dataSourceColumns) {
|
|
81
90
|
record[col.name] = this.getFieldValue(col, record[col.name]);
|
|
82
91
|
}
|
|
83
92
|
});
|
|
84
|
-
return
|
|
93
|
+
return { data, total };
|
|
85
94
|
});
|
|
86
95
|
}
|
|
87
96
|
getMinMaxForColumns(_a) {
|