adminforth 1.1.91 → 1.1.93
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 +2 -2
- package/dataConnectors/mongo.ts +2 -2
- package/dataConnectors/postgres.ts +2 -2
- package/dataConnectors/sqlite.ts +2 -2
- package/dist/plugins/TwoFactorsAuthPlugin/index.js +2 -3
- package/dist/spa/spa/src/components/Toast.vue +1 -1
- package/index.ts +5 -5
- package/modules/codeInjector.ts +2 -2
- package/package.json +2 -2
- package/plugins/AuditLogPlugin/index.ts +3 -3
- package/plugins/ForeignInlineListPlugin/index.ts +4 -4
- package/plugins/S3UploadPlugin/custom/s3uploader.vue +24 -4
- package/plugins/S3UploadPlugin/index.ts +4 -4
- package/plugins/S3UploadPlugin/package.json +1 -1
- package/plugins/TwoFactorsAuthPlugin/dist/auth.js +108 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/baseConnector.js +90 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/mongo.js +191 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/postgres.js +295 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/sqlite.js +246 -0
- package/plugins/TwoFactorsAuthPlugin/dist/index.js +1186 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/codeInjector.js +546 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/styleGenerator.js +43 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/styles.js +92 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/utils.js +301 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/TwoFactorsAuthPlugin/index.js +149 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/TwoFactorsAuthPlugin/types.js +1 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/base.js +34 -0
- package/plugins/TwoFactorsAuthPlugin/dist/servers/express.js +230 -0
- package/plugins/TwoFactorsAuthPlugin/dist/types/AdminForthConfig.js +105 -0
- package/plugins/TwoFactorsAuthPlugin/index.ts +10 -10
- package/plugins/TwoFactorsAuthPlugin/package-lock.json +2 -2
- package/plugins/TwoFactorsAuthPlugin/package.json +8 -6
- package/plugins/TwoFactorsAuthPlugin/tsconfig.json +112 -0
- package/plugins/base.ts +4 -4
- package/servers/express.ts +4 -4
- package/spa/src/components/Toast.vue +1 -1
- package/tsconfig.json +1 -1
- package/types/AdminForthConfig.ts +34 -28
- package/types/FrontendAPI.ts +3 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import dayjs from 'dayjs';
|
|
11
|
+
import { MongoClient } from 'mongodb';
|
|
12
|
+
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types/AdminForthConfig.js';
|
|
13
|
+
class MongoConnector {
|
|
14
|
+
constructor({ url }) {
|
|
15
|
+
this.OperatorsMap = {
|
|
16
|
+
[AdminForthFilterOperators.EQ]: (value) => value,
|
|
17
|
+
[AdminForthFilterOperators.NE]: (value) => ({ $ne: value }),
|
|
18
|
+
[AdminForthFilterOperators.GT]: (value) => ({ $gt: value }),
|
|
19
|
+
[AdminForthFilterOperators.LT]: (value) => ({ $lt: value }),
|
|
20
|
+
[AdminForthFilterOperators.GTE]: (value) => ({ $gte: value }),
|
|
21
|
+
[AdminForthFilterOperators.LTE]: (value) => ({ $lte: value }),
|
|
22
|
+
[AdminForthFilterOperators.LIKE]: (value) => ({ $regex: value }),
|
|
23
|
+
[AdminForthFilterOperators.ILIKE]: (value) => ({ $regex: value, $options: 'i' }),
|
|
24
|
+
[AdminForthFilterOperators.IN]: (value) => ({ $in: value }),
|
|
25
|
+
[AdminForthFilterOperators.NIN]: (value) => ({ $nin: value }),
|
|
26
|
+
};
|
|
27
|
+
this.SortDirectionsMap = {
|
|
28
|
+
[AdminForthSortDirections.asc]: 1,
|
|
29
|
+
[AdminForthSortDirections.desc]: -1,
|
|
30
|
+
};
|
|
31
|
+
this.db = new MongoClient(url);
|
|
32
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
try {
|
|
34
|
+
yield this.db.connect();
|
|
35
|
+
this.db.on('error', (err) => {
|
|
36
|
+
console.log('Mongo error: ', err.message);
|
|
37
|
+
});
|
|
38
|
+
console.log('Connected to Mongo');
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.error('ERROR: Failed to connect to Mongo', e);
|
|
42
|
+
}
|
|
43
|
+
}))();
|
|
44
|
+
}
|
|
45
|
+
discoverFields(resource) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
return resource.columns.reduce((acc, col) => {
|
|
48
|
+
if (!col.type) {
|
|
49
|
+
throw new Error(`Type is not defined for column ${col.name}`);
|
|
50
|
+
}
|
|
51
|
+
acc[col.name] = {
|
|
52
|
+
name: col.name,
|
|
53
|
+
type: col.type,
|
|
54
|
+
primaryKey: col.primaryKey,
|
|
55
|
+
virtual: col.virtual,
|
|
56
|
+
_underlineType: col._underlineType,
|
|
57
|
+
};
|
|
58
|
+
return acc;
|
|
59
|
+
}, {});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
getPrimaryKey(resource) {
|
|
63
|
+
for (const col of resource.dataSourceColumns) {
|
|
64
|
+
if (col.primaryKey) {
|
|
65
|
+
return col.name;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
getFieldValue(field, value) {
|
|
70
|
+
if (field.type == AdminForthDataTypes.DATETIME) {
|
|
71
|
+
if (!value) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return dayjs(Date.parse(value)).toISOString();
|
|
75
|
+
}
|
|
76
|
+
else if (field.type == AdminForthDataTypes.DATE) {
|
|
77
|
+
if (!value) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return dayjs(Date.parse(value)).toISOString().split('T')[0];
|
|
81
|
+
}
|
|
82
|
+
else if (field.type == AdminForthDataTypes.BOOLEAN) {
|
|
83
|
+
return !!value;
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
getRecordByPrimaryKeyWithOriginalTypes(resource, key) {
|
|
88
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
const tableName = resource.table;
|
|
90
|
+
const collection = this.db.db().collection(tableName);
|
|
91
|
+
const row = yield collection.findOne({ [this.getPrimaryKey(resource)]: key });
|
|
92
|
+
if (!row) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const newRow = {};
|
|
96
|
+
for (const [key_1, value] of Object.entries(row)) {
|
|
97
|
+
const dbKey = resource.dataSourceColumns.find((col) => col.name == key_1);
|
|
98
|
+
if (!dbKey) {
|
|
99
|
+
continue; // should I continue or throw an error?
|
|
100
|
+
throw new Error(`Resource '${resource.table}' has no column '${key_1}' defined`);
|
|
101
|
+
}
|
|
102
|
+
newRow[key_1] = value;
|
|
103
|
+
}
|
|
104
|
+
console.log('newRow', newRow);
|
|
105
|
+
return newRow;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
setFieldValue(field, value) {
|
|
109
|
+
if (field.type == AdminForthDataTypes.DATETIME) {
|
|
110
|
+
if (!value) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
|
|
114
|
+
// value is iso string now, convert to unix timestamp
|
|
115
|
+
return dayjs(value).unix();
|
|
116
|
+
}
|
|
117
|
+
else if (field._underlineType == 'varchar') {
|
|
118
|
+
// value is iso string now, convert to unix timestamp
|
|
119
|
+
return dayjs(value).toISOString();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (field.type == AdminForthDataTypes.BOOLEAN) {
|
|
123
|
+
return value ? 1 : 0;
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
getDataWithOriginalTypes(_a) {
|
|
128
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
|
|
129
|
+
// const columns = resource.dataSourceColumns.filter(c=> !c.virtual).map((col) => col.name).join(', ');
|
|
130
|
+
const tableName = resource.table;
|
|
131
|
+
const collection = this.db.db().collection(tableName);
|
|
132
|
+
const query = {};
|
|
133
|
+
for (const filter of filters) {
|
|
134
|
+
query[filter.field] = this.OperatorsMap[filter.operator](filter.value);
|
|
135
|
+
}
|
|
136
|
+
const total = yield collection.countDocuments(query);
|
|
137
|
+
const result = yield collection.find(query)
|
|
138
|
+
.sort(sort)
|
|
139
|
+
.skip(offset)
|
|
140
|
+
.limit(limit)
|
|
141
|
+
.toArray();
|
|
142
|
+
return { data: result, total };
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
getMinMaxForColumnsWithOriginalTypes(_a) {
|
|
146
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, columns }) {
|
|
147
|
+
const tableName = resource.table;
|
|
148
|
+
const collection = this.db.db().collection(tableName);
|
|
149
|
+
const result = {};
|
|
150
|
+
for (const column of columns) {
|
|
151
|
+
result[column] = yield collection
|
|
152
|
+
.aggregate([
|
|
153
|
+
{ $group: { _id: null, min: { $min: `$${column}` }, max: { $max: `$${column}` } } },
|
|
154
|
+
])
|
|
155
|
+
.toArray();
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
createRecord(_a) {
|
|
161
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, record }) {
|
|
162
|
+
const tableName = resource.table;
|
|
163
|
+
const collection = this.db.db().collection(tableName);
|
|
164
|
+
const columns = Object.keys(record);
|
|
165
|
+
const newRecord = {};
|
|
166
|
+
for (const colName of columns) {
|
|
167
|
+
newRecord[colName] = record[colName];
|
|
168
|
+
}
|
|
169
|
+
yield collection.insertOne(newRecord);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
updateRecord(_a) {
|
|
173
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, recordId, newValues }) {
|
|
174
|
+
const collection = this.db.db().collection(resource.table);
|
|
175
|
+
yield collection.updateOne({ [this.getPrimaryKey(resource)]: recordId }, { $set: newValues });
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
deleteRecord(_a) {
|
|
179
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
|
|
180
|
+
const primaryKey = this.getPrimaryKey(resource);
|
|
181
|
+
const collection = this.db.db().collection(resource.table);
|
|
182
|
+
yield collection.deleteOne({ [primaryKey]: recordId });
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
close() {
|
|
186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
yield this.db.close();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export default MongoConnector;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import dayjs from 'dayjs';
|
|
11
|
+
import pkg from 'pg';
|
|
12
|
+
import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types/AdminForthConfig.js';
|
|
13
|
+
import AdminForthBaseConnector from './baseConnector.js';
|
|
14
|
+
const { Client } = pkg;
|
|
15
|
+
class PostgresConnector extends AdminForthBaseConnector {
|
|
16
|
+
constructor({ url }) {
|
|
17
|
+
super();
|
|
18
|
+
this.OperatorsMap = {
|
|
19
|
+
[AdminForthFilterOperators.EQ]: '=',
|
|
20
|
+
[AdminForthFilterOperators.NE]: '!=',
|
|
21
|
+
[AdminForthFilterOperators.GT]: '>',
|
|
22
|
+
[AdminForthFilterOperators.LT]: '<',
|
|
23
|
+
[AdminForthFilterOperators.GTE]: '>=',
|
|
24
|
+
[AdminForthFilterOperators.LTE]: '<=',
|
|
25
|
+
[AdminForthFilterOperators.LIKE]: 'LIKE',
|
|
26
|
+
[AdminForthFilterOperators.ILIKE]: 'ILIKE',
|
|
27
|
+
[AdminForthFilterOperators.IN]: 'IN',
|
|
28
|
+
[AdminForthFilterOperators.NIN]: 'NOT IN',
|
|
29
|
+
};
|
|
30
|
+
this.SortDirectionsMap = {
|
|
31
|
+
[AdminForthSortDirections.asc]: 'ASC',
|
|
32
|
+
[AdminForthSortDirections.desc]: 'DESC',
|
|
33
|
+
};
|
|
34
|
+
this.db = new Client({
|
|
35
|
+
connectionString: url
|
|
36
|
+
});
|
|
37
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
yield this.db.connect();
|
|
39
|
+
this.db.on('error', (err) => {
|
|
40
|
+
console.log('Postgres error: ', err.message, err.stack);
|
|
41
|
+
this.db.end();
|
|
42
|
+
this.db = new PostgresConnector({ url }).db;
|
|
43
|
+
});
|
|
44
|
+
}))();
|
|
45
|
+
}
|
|
46
|
+
discoverFields(resource) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
const tableName = resource.table;
|
|
49
|
+
const stmt = yield this.db.query(`
|
|
50
|
+
SELECT
|
|
51
|
+
a.attname AS name,
|
|
52
|
+
pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
|
|
53
|
+
a.attnotnull AS notnull,
|
|
54
|
+
COALESCE(pg_get_expr(d.adbin, d.adrelid), '') AS dflt_value,
|
|
55
|
+
CASE
|
|
56
|
+
WHEN ct.contype = 'p' THEN 1
|
|
57
|
+
ELSE 0
|
|
58
|
+
END AS pk
|
|
59
|
+
FROM
|
|
60
|
+
pg_catalog.pg_attribute a
|
|
61
|
+
LEFT JOIN pg_catalog.pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
|
62
|
+
LEFT JOIN pg_catalog.pg_constraint ct ON a.attnum = ANY (ct.conkey) AND a.attrelid = ct.conrelid
|
|
63
|
+
LEFT JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
|
|
64
|
+
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
|
|
65
|
+
WHERE
|
|
66
|
+
c.relname = $1
|
|
67
|
+
AND a.attnum > 0
|
|
68
|
+
AND NOT a.attisdropped
|
|
69
|
+
ORDER BY
|
|
70
|
+
a.attnum;
|
|
71
|
+
`, [tableName]);
|
|
72
|
+
const rows = stmt.rows;
|
|
73
|
+
const fieldTypes = {};
|
|
74
|
+
rows.forEach((row) => {
|
|
75
|
+
const field = {};
|
|
76
|
+
const baseType = row.type.toLowerCase();
|
|
77
|
+
if (baseType == 'int') {
|
|
78
|
+
field.type = AdminForthDataTypes.INTEGER;
|
|
79
|
+
field._underlineType = 'int';
|
|
80
|
+
}
|
|
81
|
+
else if (baseType.includes('float') || baseType.includes('double')) {
|
|
82
|
+
field.type = AdminForthDataTypes.FLOAT;
|
|
83
|
+
field._underlineType = 'float';
|
|
84
|
+
}
|
|
85
|
+
else if (baseType.includes('bool')) {
|
|
86
|
+
field.type = AdminForthDataTypes.BOOLEAN;
|
|
87
|
+
field._underlineType = 'bool';
|
|
88
|
+
}
|
|
89
|
+
else if (baseType == 'uuid') {
|
|
90
|
+
field.type = AdminForthDataTypes.STRING;
|
|
91
|
+
field._underlineType = 'uuid';
|
|
92
|
+
}
|
|
93
|
+
else if (baseType.includes('character varying')) {
|
|
94
|
+
field.type = AdminForthDataTypes.STRING;
|
|
95
|
+
field._underlineType = 'varchar';
|
|
96
|
+
const length = baseType.match(/\d+/);
|
|
97
|
+
field.maxLength = length ? parseInt(length[0]) : null;
|
|
98
|
+
}
|
|
99
|
+
else if (baseType == 'text') {
|
|
100
|
+
field.type = AdminForthDataTypes.TEXT;
|
|
101
|
+
field._underlineType = 'text';
|
|
102
|
+
}
|
|
103
|
+
else if (baseType.includes('decimal(')) {
|
|
104
|
+
field.type = AdminForthDataTypes.DECIMAL;
|
|
105
|
+
field._underlineType = 'decimal';
|
|
106
|
+
const [precision, scale] = baseType.match(/\d+/g);
|
|
107
|
+
field.precision = parseInt(precision);
|
|
108
|
+
field.scale = parseInt(scale);
|
|
109
|
+
}
|
|
110
|
+
else if (baseType == 'real') {
|
|
111
|
+
field.type = AdminForthDataTypes.FLOAT;
|
|
112
|
+
field._underlineType = 'real';
|
|
113
|
+
}
|
|
114
|
+
else if (baseType == 'date') {
|
|
115
|
+
field.type = AdminForthDataTypes.DATE;
|
|
116
|
+
field._underlineType = 'timestamp';
|
|
117
|
+
}
|
|
118
|
+
else if (baseType.includes('date') || baseType.includes('time')) {
|
|
119
|
+
field.type = AdminForthDataTypes.DATETIME;
|
|
120
|
+
field._underlineType = 'timestamp';
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
field.type = 'unknown';
|
|
124
|
+
}
|
|
125
|
+
field._baseTypeDebug = baseType;
|
|
126
|
+
field.primaryKey = row.pk == 1;
|
|
127
|
+
field.default = row.dflt_value;
|
|
128
|
+
field.required = row.notnull && !row.dflt_value;
|
|
129
|
+
fieldTypes[row.name] = field;
|
|
130
|
+
});
|
|
131
|
+
return fieldTypes;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
getFieldValue(field, value) {
|
|
135
|
+
if (field.type == AdminForthDataTypes.DATETIME) {
|
|
136
|
+
if (!value) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
|
|
140
|
+
return dayjs(value).toISOString();
|
|
141
|
+
}
|
|
142
|
+
else if (field._underlineType == 'varchar') {
|
|
143
|
+
return dayjs(value).toISOString();
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
throw new Error(`AdminForth does not support row type: ${field._underlineType} for timestamps, use VARCHAR (with iso strings) or TIMESTAMP/INT (with unix timestamps)`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (field.type == AdminForthDataTypes.DATE) {
|
|
150
|
+
if (!value) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return dayjs(value).toISOString().split('T')[0];
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
getRecordByPrimaryKeyWithOriginalTypes(resource, key) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
const tableName = resource.table;
|
|
160
|
+
const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
|
|
161
|
+
const stmt = yield this.db.query(`SELECT ${columns} FROM ${tableName} WHERE ${this.getPrimaryKey(resource)} = $1`, [key]);
|
|
162
|
+
const row = stmt.rows[0];
|
|
163
|
+
if (!row) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const newRow = {};
|
|
167
|
+
for (const [key_1, value] of Object.entries(row)) {
|
|
168
|
+
newRow[key_1] = value;
|
|
169
|
+
}
|
|
170
|
+
return newRow;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
setFieldValue(field, value) {
|
|
174
|
+
if (field.type == AdminForthDataTypes.DATETIME) {
|
|
175
|
+
if (!value) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
if (field._underlineType == 'timestamp' || field._underlineType == 'int') {
|
|
179
|
+
return dayjs(value);
|
|
180
|
+
}
|
|
181
|
+
else if (field._underlineType == 'varchar') {
|
|
182
|
+
return dayjs(value).toISOString();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (field.type == AdminForthDataTypes.BOOLEAN) {
|
|
186
|
+
return value ? 1 : 0;
|
|
187
|
+
}
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
getDataWithOriginalTypes(_a) {
|
|
191
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, limit, offset, sort, filters }) {
|
|
192
|
+
const columns = resource.dataSourceColumns.map((col) => `"${col.name}"`).join(', ');
|
|
193
|
+
const tableName = resource.table;
|
|
194
|
+
let totalCounter = 1;
|
|
195
|
+
const where = filters.length ? `WHERE ${filters.map((f, i) => {
|
|
196
|
+
let placeholder = '$' + (totalCounter);
|
|
197
|
+
const fieldData = resource.dataSourceColumns.find((col) => col.name == f.field);
|
|
198
|
+
let field = f.field;
|
|
199
|
+
let operator = this.OperatorsMap[f.operator];
|
|
200
|
+
if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
|
|
201
|
+
placeholder = `(${f.value.map((_, i) => `$${totalCounter + i}`).join(', ')})`;
|
|
202
|
+
totalCounter += f.value.length;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
totalCounter += 1;
|
|
206
|
+
}
|
|
207
|
+
if (fieldData._underlineType == 'uuid') {
|
|
208
|
+
field = `cast("${field}" as text)`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
field = `"${field}"`;
|
|
212
|
+
}
|
|
213
|
+
return `${field} ${operator} ${placeholder}`;
|
|
214
|
+
}).join(' AND ')}` : '';
|
|
215
|
+
const filterValues = [];
|
|
216
|
+
filters.length ? filters.forEach((f) => {
|
|
217
|
+
// for arrays do set in map
|
|
218
|
+
let v = f.value;
|
|
219
|
+
if (f.operator == AdminForthFilterOperators.LIKE || f.operator == AdminForthFilterOperators.ILIKE) {
|
|
220
|
+
filterValues.push(`%${v}%`);
|
|
221
|
+
}
|
|
222
|
+
else if (f.operator == AdminForthFilterOperators.IN || f.operator == AdminForthFilterOperators.NIN) {
|
|
223
|
+
filterValues.push(...v);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
filterValues.push(v);
|
|
227
|
+
}
|
|
228
|
+
}) : [];
|
|
229
|
+
const limitOffset = `LIMIT $${totalCounter} OFFSET $${totalCounter + 1}`;
|
|
230
|
+
const d = [...filterValues, limit, offset];
|
|
231
|
+
const orderBy = sort.length ? `ORDER BY ${sort.map((s) => `"${s.field}" ${this.SortDirectionsMap[s.direction]}`).join(', ')}` : '';
|
|
232
|
+
const selectQuery = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} ${limitOffset}`;
|
|
233
|
+
if (process.env.HEAVY_DEBUG) {
|
|
234
|
+
console.log('🪲 PG selectQuery:', selectQuery, 'params:', d);
|
|
235
|
+
}
|
|
236
|
+
const stmt = yield this.db.query(selectQuery, d);
|
|
237
|
+
const rows = stmt.rows;
|
|
238
|
+
const total = (yield this.db.query(`SELECT COUNT(*) FROM ${tableName} ${where}`, filterValues)).rows[0].count;
|
|
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
|
+
};
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
getMinMaxForColumnsWithOriginalTypes(_a) {
|
|
252
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, columns }) {
|
|
253
|
+
const tableName = resource.table;
|
|
254
|
+
const result = {};
|
|
255
|
+
yield Promise.all(columns.map((col) => __awaiter(this, void 0, void 0, function* () {
|
|
256
|
+
const stmt = yield this.db.query(`SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`);
|
|
257
|
+
const { min, max } = stmt.rows[0];
|
|
258
|
+
result[col.name] = {
|
|
259
|
+
min, max,
|
|
260
|
+
};
|
|
261
|
+
})));
|
|
262
|
+
return result;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
createRecord(_a) {
|
|
266
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, record }) {
|
|
267
|
+
const tableName = resource.table;
|
|
268
|
+
const columns = Object.keys(record);
|
|
269
|
+
const placeholders = columns.map((_, i) => `$${i + 1}`).join(', ');
|
|
270
|
+
const values = columns.map((colName) => record[colName]);
|
|
271
|
+
for (let i = 0; i < columns.length; i++) {
|
|
272
|
+
columns[i] = `"${columns[i]}"`;
|
|
273
|
+
}
|
|
274
|
+
yield this.db.query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`, values);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
updateRecord(_a) {
|
|
278
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, recordId, newValues }) {
|
|
279
|
+
const values = [...Object.values(newValues), recordId];
|
|
280
|
+
const columnsWithPlaceholders = Object.keys(newValues).map((col, i) => `"${col}" = $${i + 1}`).join(', ');
|
|
281
|
+
yield this.db.query(`UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE "${this.getPrimaryKey(resource)}" = $${values.length}`, values);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
deleteRecord(_a) {
|
|
285
|
+
return __awaiter(this, arguments, void 0, function* ({ resource, recordId }) {
|
|
286
|
+
yield this.db.query(`DELETE FROM ${resource.table} WHERE "${this.getPrimaryKey(resource)}" = $1`, [recordId]);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
close() {
|
|
290
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
291
|
+
yield this.db.end();
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export default PostgresConnector;
|