adminforth 1.2.98 → 1.3.1

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/auth.ts CHANGED
@@ -88,12 +88,13 @@ class AdminForthAuth {
88
88
  console.error(`Invalid token type during verification: ${t}, must be ${mustHaveType}`);
89
89
  return null;
90
90
  }
91
- if (pk === null) {
92
- decoded.isRoot = true;
93
- } else {
94
- const dbUser = await this.adminforth.getUserByPk(pk);
95
- decoded.dbUser = dbUser;
91
+ const dbUser = await this.adminforth.getUserByPk(pk);
92
+ if (!dbUser) {
93
+ console.error(`User with pk ${pk} not found in database`);
94
+ // will logout user which was deleted
95
+ return null;
96
96
  }
97
+ decoded.dbUser = dbUser;
97
98
  return decoded;
98
99
  }
99
100
 
@@ -1,4 +1,6 @@
1
- import { AdminForthResource, IAdminForthDataSourceConnectorBase, AdminForthSortDirections, AdminForthFilterOperators, AdminForthResourceColumn } from "../types/AdminForthConfig.js";
1
+ import { get } from "http";
2
+ import { AdminForthResource, IAdminForthDataSourceConnectorBase, AdminForthSortDirections, AdminForthFilterOperators, AdminForthResourceColumn, IAdminForthSort, IAdminForthFilter } from "../types/AdminForthConfig.js";
3
+ import { suggestIfTypo } from "../modules/utils.js";
2
4
 
3
5
 
4
6
  export default class AdminForthBaseConnector implements IAdminForthDataSourceConnectorBase {
@@ -17,19 +19,21 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
17
19
  offset: 0,
18
20
  sort: [],
19
21
  filters: [{ field: this.getPrimaryKey(resource), operator: AdminForthFilterOperators.EQ, value: id }],
20
- getTotals: false
21
22
  });
22
- return data.data.length > 0 ? data.data[0] : null;
23
+ return data.length > 0 ? data[0] : null;
23
24
  }
24
25
 
25
- getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals }: {
26
+ getDataWithOriginalTypes({ resource, limit, offset, sort, filters }: {
26
27
  resource: AdminForthResource,
27
28
  limit: number,
28
29
  offset: number,
29
- sort: { field: string, direction: AdminForthSortDirections }[],
30
- filters: { field: string, operator: AdminForthFilterOperators, value: any }[],
31
- getTotals?: boolean
32
- }): Promise<{ data: any[], total: number }> {
30
+ sort: IAdminForthSort[],
31
+ filters: IAdminForthFilter[],
32
+ }): Promise<any[]> {
33
+ throw new Error('Method not implemented.');
34
+ }
35
+
36
+ getCount({ resource, filters }: { resource: AdminForthResource; filters: { field: string; operator: AdminForthFilterOperators; value: any; }[]; }): Promise<number> {
33
37
  throw new Error('Method not implemented.');
34
38
  }
35
39
 
@@ -53,10 +57,21 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
53
57
  throw new Error('Method not implemented.');
54
58
  }
55
59
 
56
- createRecord({ resource, record }: { resource: AdminForthResource; record: any; }): Promise<void> {
60
+ createRecord({ resource, record, adminUser }: {
61
+ resource: AdminForthResource; record: any; adminUser: any;
62
+ }): Promise<void> {
57
63
  // transform value using setFieldValue and call createRecordOriginalValues
58
64
  const newRecord = {...record};
65
+
59
66
  for (const col of resource.dataSourceColumns) {
67
+ if (col.fillOnCreate) {
68
+ if (record[col.name] === undefined) {
69
+ record[col.name] = col.fillOnCreate({
70
+ initialRecord: record, adminUser
71
+ });
72
+ }
73
+ }
74
+
60
75
  newRecord[col.name] = this.setFieldValue(col, record[col.name]);
61
76
  }
62
77
  process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 creating record', newRecord);
@@ -67,37 +82,51 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
67
82
  throw new Error('Method not implemented.');
68
83
  }
69
84
 
70
- deleteRecord({ resource, recordId }: { resource: AdminForthResource; recordId: string; }): Promise<void> {
85
+ deleteRecord({ resource, recordId }: { resource: AdminForthResource; recordId: string; }): Promise<boolean> {
71
86
  throw new Error('Method not implemented.');
72
87
  }
73
88
 
74
89
 
75
- async getData({ resource, limit, offset, sort, filters }: {
90
+ async getData({ resource, limit, offset, sort, filters, getTotals }: {
76
91
  resource: AdminForthResource,
77
92
  limit: number,
78
93
  offset: number,
79
94
  sort: { field: string, direction: AdminForthSortDirections }[],
80
- filters: { field: string, operator: AdminForthFilterOperators, value: any }[]
95
+ filters: { field: string, operator: AdminForthFilterOperators, value: any }[],
96
+ getTotals: boolean,
81
97
  }): Promise<{ data: any[], total: number }> {
82
98
  if (filters) {
83
99
  filters.map((f) => {
100
+ const fieldObj = resource.dataSourceColumns.find((col) => col.name == f.field);
101
+ if (!fieldObj) {
102
+ const similar = suggestIfTypo(resource.dataSourceColumns.map((col) => col.name), f.field);
103
+ throw new Error(`Field '${f.field}' not found in resource '${resource.resourceId}'. ${similar ? `Did you mean '${similar}'?` : ''}`);
104
+ }
84
105
  if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
85
- f.value = f.value.map((val) => this.setFieldValue(resource.dataSourceColumns.find((col) => col.name == f.field), val));
106
+ f.value = f.value.map((val) => this.setFieldValue(fieldObj, val));
86
107
  } else {
87
- f.value = this.setFieldValue(resource.dataSourceColumns.find((col) => col.name == f.field), f.value);
108
+ f.value = this.setFieldValue(fieldObj, f.value);
88
109
  }
89
110
  });
90
111
  }
91
112
 
92
- const d = await this.getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals: true });
113
+ const promises: Promise<any>[] = [this.getDataWithOriginalTypes({ resource, limit, offset, sort, filters })];
114
+ if (getTotals) {
115
+ promises.push(this.getCount({ resource, filters }));
116
+ } else {
117
+ promises.push(Promise.resolve(undefined));
118
+ }
119
+
120
+ const [data, total] = await Promise.all(promises);
121
+
93
122
  // call getFieldValue for each field
94
- d.data.map((record) => {
123
+ data.map((record) => {
95
124
  for (const col of resource.dataSourceColumns) {
96
125
  record[col.name] = this.getFieldValue(col, record[col.name]);
97
126
  }
98
127
  });
99
128
 
100
- return d;
129
+ return { data, total };
101
130
  }
102
131
 
103
132
  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
- async getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals }: {
177
- resource: AdminForthResource,
178
- limit: number,
179
- offset: number,
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,24 @@ 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
+ console.log('getDataWithOriginalTypes', resource, limit, offset, sort, filters);
224
+ const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
225
+ const tableName = resource.table;
226
+
227
+ const where = this.whereClause(resource, filters);
228
+
229
+ const params = this.whereParams(filters);
230
+
218
231
  const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
219
232
 
220
233
 
@@ -233,27 +246,33 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
233
246
 
234
247
  const rows = await stmt.json();
235
248
 
236
- let total = 0;
237
- if (getTotals) {
238
- const countQ = await this.client.query({
239
- query: `SELECT COUNT(*) FROM ${tableName} ${where}`,
240
- format: 'JSONEachRow',
241
- query_params: d,
242
- });
243
- const countResp = await countQ.json()
244
- total = countResp[0]['COUNT()'];
245
- }
249
+ return rows.map((row) => {
250
+ const newRow = {};
251
+ for (const [key, value] of Object.entries(row)) {
252
+ newRow[key] = value;
253
+ }
254
+ return newRow;
255
+ });
256
+ }
246
257
 
247
- return {
248
- data: 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
- total,
256
- };
258
+ async getCount({
259
+ resource,
260
+ filters,
261
+ }: {
262
+ resource: AdminForthResource;
263
+ filters: { field: string, operator: AdminForthFilterOperators, value: any }[];
264
+ }): Promise<number> {
265
+ const tableName = resource.table;
266
+ const where = this.whereClause(resource, filters);
267
+ const d = this.whereParams(filters);
268
+
269
+ const countQ = await this.client.query({
270
+ query: `SELECT COUNT(*) FROM ${tableName} ${where}`,
271
+ format: 'JSONEachRow',
272
+ query_params: d,
273
+ });
274
+ const countResp = await countQ.json()
275
+ return countResp[0]['COUNT()'];
257
276
  }
258
277
 
259
278
  async getMinMaxForColumnsWithOriginalTypes({ resource, columns }: { resource: AdminForthResource, columns: AdminForthResourceColumn[] }): Promise<{ [key: string]: { min: any, max: any } }> {
@@ -298,16 +317,18 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
298
317
  );
299
318
  }
300
319
 
301
- async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }) {
320
+ async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }): Promise<boolean> {
302
321
  const pkColumn = resource.dataSourceColumns.find((col) => col.primaryKey);
303
- await this.client.command(
322
+ const res = await this.client.command(
304
323
  {
305
324
  query: `ALTER TABLE ${this.dbName}.${resource.table} DELETE WHERE ${
306
325
  pkColumn.name
307
326
  } = {recordId:${pkColumn._underlineType}}`,
308
327
  query_params: { recordId },
309
- }
328
+ }
310
329
  );
330
+ // todo test what is in res
331
+ return res;
311
332
  }
312
333
 
313
334
  close() {
@@ -1,6 +1,7 @@
1
1
  import dayjs from 'dayjs';
2
2
  import { MongoClient } from 'mongodb';
3
- import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections, IAdminForthDataSourceConnector } from '../types/AdminForthConfig.js';
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
- const collection = this.db.db().collection(tableName);
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
- let total = 0;
119
- if (getTotals) {
120
- total = await collection.countDocuments(query);
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(sort)
140
+ .sort(sortArray)
124
141
  .skip(offset)
125
142
  .limit(limit)
126
143
  .toArray();
127
144
 
128
- return { data: result, total }
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
- if (field.type == AdminForthDataTypes.DATETIME) {
172
- if (!value) {
173
- return null;
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
- return value;
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
- async getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals }) {
187
- const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
188
- const tableName = resource.table;
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
- field = `cast("${field}" as text)`
206
+ field = `cast("${field}" as text)`
205
207
  } else {
206
- field = `"${field}"`
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
- const limitOffset = `LIMIT $${totalCounter} OFFSET $${totalCounter + 1}`;
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
- let total = 0;
235
- if (getTotals) {
236
- total = (await this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues)).rows[0].count;
237
- }
238
- return {
239
- data: rows.map((row) => {
240
- const newRow = {};
241
- for (const [key, value] of Object.entries(row)) {
242
- newRow[key] = value;
243
- }
244
- return newRow;
245
- }),
246
- total,
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
- await this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
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() {
@@ -135,12 +135,8 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData
135
135
  [AdminForthSortDirections.desc]: 'DESC',
136
136
  };
137
137
 
138
-
139
- async getDataWithOriginalTypes({ resource, limit, offset, sort, filters, getTotals }): Promise<{ data: any[], total: number }> {
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
- const filterValues = [];
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
- filterValues.push(`%${v}%`);
157
+ acc.push(`%${f.value}%`);
166
158
  } else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
167
- filterValues.push(...v);
159
+ acc.push(...f.value);
168
160
  } else {
169
- filterValues.push(v);
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
- let total = 0;
186
- if (getTotals) {
187
- const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
188
- total = totalStmt.get([...filterValues])['COUNT(*)'];
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
- return {
192
- data: rows.map((row) => {
193
- const newRow = {};
194
- for (const [key, value] of Object.entries(row)) {
195
- newRow[key] = value;
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() {
package/dist/auth.js CHANGED
@@ -80,13 +80,13 @@ class AdminForthAuth {
80
80
  console.error(`Invalid token type during verification: ${t}, must be ${mustHaveType}`);
81
81
  return null;
82
82
  }
83
- if (pk === null) {
84
- decoded.isRoot = true;
85
- }
86
- else {
87
- const dbUser = yield this.adminforth.getUserByPk(pk);
88
- decoded.dbUser = dbUser;
83
+ const dbUser = yield this.adminforth.getUserByPk(pk);
84
+ if (!dbUser) {
85
+ console.error(`User with pk ${pk} not found in database`);
86
+ // will logout user which was deleted
87
+ return null;
89
88
  }
89
+ decoded.dbUser = dbUser;
90
90
  return decoded;
91
91
  });
92
92
  }