adminforth 1.2.98 → 1.2.100

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 (36) hide show
  1. package/auth.ts +6 -5
  2. package/dataConnectors/baseConnector.ts +91 -21
  3. package/dataConnectors/clickhouse.ts +58 -37
  4. package/dataConnectors/mongo.ts +44 -14
  5. package/dataConnectors/postgres.ts +53 -36
  6. package/dataConnectors/sqlite.ts +44 -35
  7. package/dist/auth.js +6 -6
  8. package/dist/dataConnectors/baseConnector.js +75 -17
  9. package/dist/dataConnectors/clickhouse.js +59 -48
  10. package/dist/dataConnectors/mongo.js +28 -12
  11. package/dist/dataConnectors/postgres.js +62 -52
  12. package/dist/dataConnectors/sqlite.js +62 -45
  13. package/dist/index.js +52 -33
  14. package/dist/modules/configValidator.js +25 -16
  15. package/dist/modules/operationalResource.js +88 -0
  16. package/dist/modules/restApi.js +106 -96
  17. package/dist/modules/utils.js +16 -0
  18. package/dist/types/AdminForthConfig.js +37 -0
  19. package/index.ts +76 -43
  20. package/modules/configValidator.ts +26 -21
  21. package/modules/operationalResource.ts +91 -0
  22. package/modules/restApi.ts +91 -80
  23. package/modules/utils.ts +20 -0
  24. package/package.json +3 -2
  25. package/spa/src/App.vue +12 -9
  26. package/spa/src/components/Filters.vue +1 -1
  27. package/spa/src/components/ResourceForm.vue +7 -4
  28. package/spa/src/components/ResourceListTable.vue +124 -112
  29. package/spa/src/components/SkeleteLoader.vue +4 -4
  30. package/spa/src/components/ValueRenderer.vue +1 -1
  31. package/spa/src/router/index.ts +0 -8
  32. package/spa/src/spa_types/core.ts +1 -0
  33. package/spa/src/stores/filters.ts +3 -2
  34. package/spa/src/views/ListView.vue +16 -25
  35. package/spa/src/views/LoginView.vue +26 -9
  36. package/types/AdminForthConfig.ts +140 -38
@@ -75,6 +75,10 @@ class SQLiteConnector extends AdminForthBaseConnector {
75
75
  field.type = AdminForthDataTypes.BOOLEAN;
76
76
  field._underlineType = 'boolean';
77
77
  }
78
+ else if (baseType == 'datetime') {
79
+ field.type = AdminForthDataTypes.DATETIME;
80
+ field._underlineType = 'datetime';
81
+ }
78
82
  else {
79
83
  field.type = 'unknown';
80
84
  }
@@ -98,6 +102,9 @@ class SQLiteConnector extends AdminForthBaseConnector {
98
102
  else if (field._underlineType == 'varchar') {
99
103
  return dayjs(value).toISOString();
100
104
  }
105
+ else if (field._underlineType == 'datetime') {
106
+ return dayjs(value).toISOString();
107
+ }
101
108
  else {
102
109
  throw new Error(`AdminForth does not support row type: ${field._underlineType} for timestamps, use VARCHAR (with iso strings) or TIMESTAMP/INT (with unix timestamps). Issue in field "${field.name}"`);
103
110
  }
@@ -134,6 +141,9 @@ class SQLiteConnector extends AdminForthBaseConnector {
134
141
  // value is iso string now, convert to unix timestamp
135
142
  return dayjs(value).toISOString();
136
143
  }
144
+ else {
145
+ return value;
146
+ }
137
147
  }
138
148
  else if (field.type == AdminForthDataTypes.BOOLEAN) {
139
149
  return value ? 1 : 0;
@@ -149,39 +159,44 @@ class SQLiteConnector extends AdminForthBaseConnector {
149
159
  }
150
160
  return value;
151
161
  }
162
+ whereClause(filters) {
163
+ return filters.length ? `WHERE ${filters.map((f, i) => {
164
+ let placeholder = '?';
165
+ let field = f.field;
166
+ let operator = this.OperatorsMap[f.operator];
167
+ if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
168
+ placeholder = `(${f.value.map(() => '?').join(', ')})`;
169
+ }
170
+ else if (f.operator == AdminForthFilterOperators.ILIKE) {
171
+ placeholder = `LOWER(?)`;
172
+ field = `LOWER(${f.field})`;
173
+ operator = 'LIKE';
174
+ }
175
+ return `${field} ${operator} ${placeholder}`;
176
+ }).join(' AND ')}` : '';
177
+ }
178
+ whereParams(filters) {
179
+ return filters.reduce((acc, f) => {
180
+ if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
181
+ acc.push(`%${f.value}%`);
182
+ }
183
+ else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
184
+ acc.push(...f.value);
185
+ }
186
+ else {
187
+ acc.push(f.value);
188
+ }
189
+ return acc;
190
+ }, []);
191
+ }
152
192
  getDataWithOriginalTypes(_a) {
153
- return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters, getTotals }) {
193
+ return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
154
194
  const columns = resource.dataSourceColumns.map((col) => col.name).join(', ');
155
195
  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
- }) : [];
196
+ const where = this.whereClause(filters);
197
+ const filterValues = this.whereParams(filters);
184
198
  const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `${s.field} ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
199
+ console.log('🪲 SQLITE Query', `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`, 'params:', [...filterValues, limit, offset]);
185
200
  const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT ? OFFSET ?`;
186
201
  const stmt = this.db.prepare(q);
187
202
  const d = [...filterValues, limit, offset];
@@ -189,21 +204,22 @@ class SQLiteConnector extends AdminForthBaseConnector {
189
204
  console.log('🪲 SQLITE Query', q, 'params:', d);
190
205
  }
191
206
  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
- };
207
+ return rows.map((row) => {
208
+ const newRow = {};
209
+ for (const [key, value] of Object.entries(row)) {
210
+ newRow[key] = value;
211
+ }
212
+ return newRow;
213
+ });
214
+ });
215
+ }
216
+ getCount(_a) {
217
+ return __awaiter(this, arguments, void 0, function* ({ resource, filters }) {
218
+ const tableName = resource.table;
219
+ const where = this.whereClause(filters);
220
+ const filterValues = this.whereParams(filters);
221
+ const totalStmt = this.db.prepare(`SELECT COUNT(*) FROM ${tableName} ${where}`);
222
+ return totalStmt.get([...filterValues])['COUNT(*)'];
207
223
  });
208
224
  }
209
225
  getMinMaxForColumnsWithOriginalTypes(_a) {
@@ -241,7 +257,8 @@ class SQLiteConnector extends AdminForthBaseConnector {
241
257
  deleteRecord(_a) {
242
258
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
243
259
  const q = this.db.prepare(`DELETE FROM ${resource.table} WHERE ${this.getPrimaryKey(resource)} = ?`);
244
- yield q.run(recordId);
260
+ const res = yield q.run(recordId);
261
+ return res.changes > 0;
245
262
  });
246
263
  }
247
264
  close() {
package/dist/index.js CHANGED
@@ -19,16 +19,18 @@ import PostgresConnector from './dataConnectors/postgres.js';
19
19
  import SQLiteConnector from './dataConnectors/sqlite.js';
20
20
  import CodeInjector from './modules/codeInjector.js';
21
21
  import ExpressServer from './servers/express.js';
22
- import { ADMINFORTH_VERSION, listify } from './modules/utils.js';
22
+ import { ADMINFORTH_VERSION, listify, suggestIfTypo } 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
26
  import AdminForthRestAPI, { interpretResource } from './modules/restApi.js';
27
27
  import ClickhouseConnector from './dataConnectors/clickhouse.js';
28
+ import OperationalResource from './modules/operationalResource.js';
28
29
  // exports
29
30
  export * from './types/AdminForthConfig.js';
30
31
  export { interpretResource };
31
32
  export { AdminForthPlugin };
33
+ export { suggestIfTypo };
32
34
  class AdminForth {
33
35
  constructor(config) {
34
36
  _AdminForth_defaultConfig.set(this, {
@@ -85,20 +87,22 @@ class AdminForth {
85
87
  this.config.dataSources.forEach((ds) => {
86
88
  const dbType = ds.url.split(':')[0];
87
89
  if (!this.config.databaseConnectors[dbType]) {
88
- throw new Error(`Database type ${dbType} is not supported, consider using databaseConnectors in AdminForth config`);
90
+ throw new Error(`Database type '${dbType}' is not supported, consider using one of ${Object.keys(this.connectorClasses).join(', ')} or create your own data-source connector`);
89
91
  }
90
92
  this.connectors[ds.id] = new this.config.databaseConnectors[dbType]({ url: ds.url });
91
93
  });
92
94
  yield Promise.all(this.config.resources.map((res) => __awaiter(this, void 0, void 0, function* () {
93
95
  if (!this.connectors[res.dataSource]) {
94
- throw new Error(`Resource '${res.table}' refers to unknown dataSource '${res.dataSource}'`);
96
+ const similar = suggestIfTypo(Object.keys(this.connectors), res.dataSource);
97
+ throw new Error(`Resource '${res.table}' refers to unknown dataSource '${res.dataSource}' ${similar
98
+ ? `. Did you mean '${similar}'?` : 'Available dataSources: ' + Object.keys(this.connectors).join(', ')}`);
95
99
  }
96
100
  const fieldTypes = yield this.connectors[res.dataSource].discoverFields(res);
97
101
  if (fieldTypes !== null && !Object.keys(fieldTypes).length) {
98
102
  throw new Error(`Table '${res.table}' (In resource '${res.resourceId}') has no fields or does not exist`);
99
103
  }
100
104
  if (fieldTypes === null) {
101
- console.error(`DataSource ${res.dataSource} was not able to perform field discovery. It will not work properly`);
105
+ console.error(`⛔ DataSource ${res.dataSource} was not able to perform field discovery. It will not work properly`);
102
106
  return;
103
107
  }
104
108
  if (!res.columns) {
@@ -106,7 +110,8 @@ class AdminForth {
106
110
  }
107
111
  res.columns.forEach((col, i) => {
108
112
  if (!fieldTypes[col.name] && !col.virtual) {
109
- throw new Error(`Resource '${res.table}' has no column '${col.name}'`);
113
+ const similar = suggestIfTypo(Object.keys(fieldTypes), col.name);
114
+ throw new Error(`Resource '${res.table}' has no column '${col.name}'. ${similar ? `Did you mean '${similar}'?` : ''}`);
110
115
  }
111
116
  // first find discovered values, but allow override
112
117
  res.columns[i] = Object.assign(Object.assign({}, fieldTypes[col.name]), col);
@@ -118,6 +123,10 @@ class AdminForth {
118
123
  }
119
124
  })));
120
125
  this.statuses.dbDiscover = 'done';
126
+ this.operationalResources = {};
127
+ this.config.resources.forEach((resource) => {
128
+ this.operationalResources[resource.resourceId] = new OperationalResource(this.connectors[resource.dataSource], resource);
129
+ });
121
130
  // console.log('⚙️⚙️⚙️ Database discovery done', JSON.stringify(this.config.resources, null, 2));
122
131
  });
123
132
  }
@@ -128,9 +137,11 @@ class AdminForth {
128
137
  }
129
138
  getUserByPk(pk) {
130
139
  return __awaiter(this, void 0, void 0, function* () {
131
- const resource = this.config.resources.find((res) => res.resourceId === this.config.auth.resourceId);
140
+ const resource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
132
141
  if (!resource) {
133
- throw new Error('No auth resource found');
142
+ const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId), this.config.auth.usersResourceId);
143
+ throw new Error(`No resource with ${this.config.auth.usersResourceId} found. ${similar ?
144
+ `Did you mean '${similar}' in config.auth.usersResourceId?` : 'Please set correct resource in config.auth.usersResourceId'}`);
134
145
  }
135
146
  const users = yield this.connectors[resource.dataSource].getData({
136
147
  resource,
@@ -148,39 +159,21 @@ class AdminForth {
148
159
  return __awaiter(this, arguments, void 0, function* ({ resource, record, adminUser }) {
149
160
  var _c, _d, _e, _f, _g;
150
161
  for (const column of resource.columns) {
151
- if (column.fillOnCreate) {
152
- if (record[column.name] === undefined) {
153
- record[column.name] = column.fillOnCreate({
154
- initialRecord: record, adminUser
155
- });
156
- }
157
- }
162
+ // TODO: assuming specifity for AdminForthResourcePages.create better to move it to api for this button
158
163
  if (((_c = column.required) === null || _c === void 0 ? void 0 : _c.create) &&
159
164
  record[column.name] === undefined &&
160
165
  column.showIn.includes(AdminForthResourcePages.create)) {
161
- return { error: `Column '${column.name}' is required` };
162
- }
163
- if (column.isUnique) {
164
- const existingRecord = yield this.connectors[resource.dataSource].getData({
165
- resource,
166
- filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value: record[column.name] }],
167
- limit: 1,
168
- sort: [],
169
- offset: 0
170
- });
171
- if (existingRecord.data.length > 0) {
172
- return { error: `Record with ${column.name} ${record[column.name]} already exists` };
173
- }
166
+ return { error: `Column '${column.name}' is required`, ok: false };
174
167
  }
175
168
  }
176
169
  // execute hook if needed
177
170
  for (const hook of listify((_e = (_d = resource.hooks) === null || _d === void 0 ? void 0 : _d.create) === null || _e === void 0 ? void 0 : _e.beforeSave)) {
178
- const resp = yield hook({ resource, record, adminUser });
171
+ const resp = yield hook({ recordId: undefined, resource, record, adminUser });
179
172
  if (!resp || (!resp.ok && !resp.error)) {
180
173
  throw new Error(`Hook beforeSave must return object with {ok: true} or { error: 'Error' } `);
181
174
  }
182
175
  if (resp.error) {
183
- return { error: resp.error };
176
+ return { error: resp.error, ok: false };
184
177
  }
185
178
  }
186
179
  // remove virtual columns from record
@@ -191,21 +184,47 @@ class AdminForth {
191
184
  }
192
185
  const connector = this.connectors[resource.dataSource];
193
186
  process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 creating record createResourceRecord', record);
194
- yield connector.createRecord({ resource, record });
187
+ const { ok, error, createdRecord } = yield connector.createRecord({ resource, record, adminUser });
188
+ if (!ok) {
189
+ return { ok, error };
190
+ }
191
+ const primaryKey = record[resource.columns.find((col) => col.primaryKey).name];
195
192
  // execute hook if needed
196
193
  for (const hook of listify((_g = (_f = resource.hooks) === null || _f === void 0 ? void 0 : _f.create) === null || _g === void 0 ? void 0 : _g.afterSave)) {
197
194
  console.log('Hook afterSave', hook);
198
- const resp = yield hook({ resource, record, adminUser });
195
+ const resp = yield hook({
196
+ recordId: primaryKey,
197
+ resource,
198
+ record: createdRecord,
199
+ adminUser
200
+ });
199
201
  if (!resp || (!resp.ok && !resp.error)) {
200
202
  throw new Error(`Hook afterSave must return object with {ok: true} or { error: 'Error' } `);
201
203
  }
202
204
  if (resp.error) {
203
- return { error: resp.error };
205
+ return { error: resp.error, ok: false };
204
206
  }
205
207
  }
206
- return { ok: true };
208
+ return { ok, error, createdRecord };
207
209
  });
208
210
  }
211
+ resource(resourceId) {
212
+ if (this.statuses.dbDiscover !== 'done') {
213
+ if (this.statuses.dbDiscover === 'running') {
214
+ throw new Error('Database discovery is running. You can\'t use data API while database discovery is not finished.\n' +
215
+ 'Consider moving your code to a place where it will be executed after database discovery is already done (after await admin.discoverDatabases())');
216
+ }
217
+ else {
218
+ throw new Error('Database discovery is not yet started. You can\'t use data API before database discovery is done. \n' +
219
+ 'Call admin.discoverDatabases() first and await it before using data API');
220
+ }
221
+ }
222
+ if (!this.operationalResources[resourceId]) {
223
+ const closeName = suggestIfTypo(Object.keys(this.operationalResources), resourceId);
224
+ throw new Error(`Resource with id '${resourceId}' not found${closeName ? `. Did you mean '${closeName}'?` : ''}`);
225
+ }
226
+ return this.operationalResources[resourceId];
227
+ }
209
228
  setupEndpoints(server) {
210
229
  this.restApi.registerEndpoints(server);
211
230
  }
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { AdminForthResourcePages, AllowedActionsEnum, } from "../types/AdminForthConfig.js";
11
11
  import fs from 'fs';
12
12
  import path from 'path';
13
- import { guessLabelFromName } from './utils.js';
13
+ import { guessLabelFromName, suggestIfTypo } from './utils.js';
14
14
  import crypto from 'crypto';
15
15
  export default class ConfigValidator {
16
16
  constructor(adminforth, config) {
@@ -47,15 +47,6 @@ export default class ConfigValidator {
47
47
  validateConfig() {
48
48
  var _a;
49
49
  const errors = [];
50
- if (this.config.rootUser) {
51
- if (!this.config.rootUser.username) {
52
- throw new Error('rootUser.username is required');
53
- }
54
- if (!this.config.rootUser.password) {
55
- throw new Error('rootUser.password is required');
56
- }
57
- console.log('\n ☝️☝️☝️ [INSECURE ALERT] config.rootUser is set, please create a new user to login in backoffice and remove config.rootUser from config ASAP when you are in production\n');
58
- }
59
50
  if (!this.config.customization.customComponentsDir) {
60
51
  this.config.customization.customComponentsDir = './custom';
61
52
  }
@@ -67,8 +58,12 @@ export default class ConfigValidator {
67
58
  this.config.customization.customComponentsDir = undefined;
68
59
  }
69
60
  if (this.config.auth) {
70
- if (!this.config.auth.resourceId) {
71
- throw new Error('No config.auth.resourceId defined');
61
+ // TODO: remove in future releases
62
+ if (!this.config.auth.usersResourceId && this.config.auth.resourceId) {
63
+ this.config.auth.usersResourceId = this.config.auth.resourceId;
64
+ }
65
+ if (!this.config.auth.usersResourceId) {
66
+ throw new Error('No config.auth.usersResourceId defined');
72
67
  }
73
68
  if (!this.config.auth.passwordHashField) {
74
69
  throw new Error('No config.auth.passwordHashField defined');
@@ -79,9 +74,10 @@ export default class ConfigValidator {
79
74
  if (this.config.auth.loginBackgroundImage) {
80
75
  errors.push(...this.checkCustomFileExists(this.config.auth.loginBackgroundImage));
81
76
  }
82
- const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.resourceId);
77
+ const userResource = this.config.resources.find((res) => res.resourceId === this.config.auth.usersResourceId);
83
78
  if (!userResource) {
84
- throw new Error(`Resource with id "${this.config.auth.resourceId}" not found`);
79
+ const similar = suggestIfTypo(this.config.resources.map((res) => res.resourceId || res.table), this.config.auth.usersResourceId);
80
+ throw new Error(`Resource with id "${this.config.auth.usersResourceId}" not found. ${similar ? `Did you mean "${similar}"?` : ''}`);
85
81
  }
86
82
  if (!this.config.auth.beforeLoginConfirmation) {
87
83
  this.config.auth.beforeLoginConfirmation = [];
@@ -126,6 +122,9 @@ export default class ConfigValidator {
126
122
  if (this.config.customization.brandLogo) {
127
123
  errors.push(...this.checkCustomFileExists(this.config.customization.brandLogo));
128
124
  }
125
+ if (this.config.customization.showBrandNameInSidebar === undefined) {
126
+ this.config.customization.showBrandNameInSidebar = true;
127
+ }
129
128
  if (this.config.customization.favicon) {
130
129
  errors.push(...this.checkCustomFileExists(this.config.customization.favicon));
131
130
  }
@@ -254,7 +253,12 @@ export default class ConfigValidator {
254
253
  yield Promise.all(selectedIds.map((recordId) => __awaiter(this, void 0, void 0, function* () {
255
254
  const record = yield connector.getRecordByPrimaryKey(res, recordId);
256
255
  yield Promise.all(res.hooks.delete.beforeSave.map((hook) => __awaiter(this, void 0, void 0, function* () {
257
- const resp = yield hook({ resource: res, record, adminUser });
256
+ const resp = yield hook({
257
+ recordId: recordId,
258
+ resource: res,
259
+ record,
260
+ adminUser,
261
+ });
258
262
  if (!error && resp.error) {
259
263
  error = resp.error;
260
264
  }
@@ -265,7 +269,12 @@ export default class ConfigValidator {
265
269
  yield connector.deleteRecord({ resource: res, recordId });
266
270
  // call afterDelete hook
267
271
  yield Promise.all(res.hooks.delete.afterSave.map((hook) => __awaiter(this, void 0, void 0, function* () {
268
- yield hook({ resource: res, record, adminUser });
272
+ yield hook({
273
+ resource: res,
274
+ record,
275
+ adminUser,
276
+ recordId: recordId
277
+ });
269
278
  })));
270
279
  })));
271
280
  if (error) {
@@ -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
+ function filtersIfFilter(filter) {
11
+ if (!filter) {
12
+ return [];
13
+ }
14
+ return (Array.isArray(filter) ? filter : [filter]);
15
+ }
16
+ function sortsIfSort(sort) {
17
+ return (Array.isArray(sort) ? sort : [sort]);
18
+ }
19
+ export default class OperationalResource {
20
+ constructor(dataConnector, resourceConfig) {
21
+ this.dataConnector = dataConnector;
22
+ this.resourceConfig = resourceConfig;
23
+ }
24
+ get(filter) {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ return (yield this.dataConnector.getData({
27
+ resource: this.resourceConfig,
28
+ filters: filtersIfFilter(filter),
29
+ limit: 1,
30
+ offset: 0,
31
+ sort: [],
32
+ })).data[0] || null;
33
+ });
34
+ }
35
+ list(filter, limit, offset, sort) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ let appliedLimit = limit;
38
+ if (limit === null) {
39
+ appliedLimit = 1000000000;
40
+ }
41
+ let appliedOffset = offset;
42
+ if (offset === null) {
43
+ appliedOffset = 0;
44
+ }
45
+ const { data } = yield this.dataConnector.getData({
46
+ resource: this.resourceConfig,
47
+ filters: filtersIfFilter(filter),
48
+ limit: appliedLimit,
49
+ offset: appliedOffset,
50
+ sort: sortsIfSort(sort),
51
+ getTotals: false,
52
+ });
53
+ return data;
54
+ });
55
+ }
56
+ count(filter) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ return yield this.dataConnector.getCount({
59
+ resource: this.resourceConfig,
60
+ filters: filtersIfFilter(filter),
61
+ });
62
+ });
63
+ }
64
+ create(recordValues) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const { ok, createdRecord, error } = yield this.dataConnector.createRecord({
67
+ resource: this.resourceConfig,
68
+ record: recordValues,
69
+ adminUser: null
70
+ });
71
+ return { ok, createdRecord, error };
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
+ }