Skip to content

Commit ab3ade3

Browse files
committed
fix: enhance data type handling in MongoConnector and add support for Double type
1 parent 088d78e commit ab3ade3

File tree

1 file changed

+67
-46
lines changed

1 file changed

+67
-46
lines changed

adminforth/dataConnectors/mongo.ts

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import dayjs from 'dayjs';
22
import { MongoClient } from 'mongodb';
3-
import { Decimal128 } from 'bson';
3+
import { Decimal128, Double } from 'bson';
44
import { IAdminForthDataSourceConnector, IAdminForthSingleFilter, IAdminForthAndOrFilter, AdminForthResource } from '../types/Back.js';
55
import AdminForthBaseConnector from './baseConnector.js';
66

@@ -122,30 +122,30 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
122122
}
123123

124124
return Array.from(fieldTypes.entries()).map(([name, types]) => {
125-
const primaryKey = name === '_id';
126-
127-
const priority = ['datetime', 'date', 'integer', 'float', 'boolean', 'json', 'decimal', 'string'];
128-
129-
const matched = priority.find(t => types.has(t)) || 'string';
130-
131-
const typeMap: Record<string, string> = {
132-
string: 'STRING',
133-
integer: 'INTEGER',
134-
float: 'FLOAT',
135-
boolean: 'BOOLEAN',
136-
datetime: 'DATETIME',
137-
date: 'DATE',
138-
json: 'JSON',
139-
decimal: 'DECIMAL',
140-
};
141-
return {
142-
name,
143-
type: typeMap[matched] ?? 'STRING',
144-
...(primaryKey ? { isPrimaryKey: true } : {}),
145-
sampleValue: sampleValues.get(name),
146-
};
125+
const primaryKey = name === '_id';
126+
127+
const priority = ['datetime','date','decimal','integer','float','boolean','json','string'];
128+
129+
const matched = priority.find(t => types.has(t)) || 'string';
130+
131+
const typeMap: Record<string, AdminForthDataTypes> = {
132+
string: AdminForthDataTypes.STRING,
133+
integer: AdminForthDataTypes.INTEGER,
134+
float: AdminForthDataTypes.FLOAT,
135+
boolean: AdminForthDataTypes.BOOLEAN,
136+
datetime: AdminForthDataTypes.DATETIME,
137+
date: AdminForthDataTypes.DATE,
138+
json: AdminForthDataTypes.JSON,
139+
decimal: AdminForthDataTypes.DECIMAL,
140+
};
141+
return {
142+
name,
143+
type: typeMap[matched] ?? AdminForthDataTypes.STRING,
144+
...(primaryKey ? { isPrimaryKey: true } : {}),
145+
sampleValue: sampleValues.get(name),
146+
};
147147
});
148-
}
148+
}
149149

150150

151151
async discoverFields(resource) {
@@ -200,19 +200,34 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
200200

201201

202202
setFieldValue(field, value) {
203-
if (field.type == AdminForthDataTypes.DATETIME) {
204-
if (!value) {
205-
return null;
206-
}
207-
return dayjs(value).toDate();
208-
209-
} else if (field.type == AdminForthDataTypes.BOOLEAN) {
210-
return value === null ? null : (value ? true : false);
211-
} else if (field.type == AdminForthDataTypes.DECIMAL) {
212-
if (value === null || value === undefined) {
213-
return null;
214-
}
215-
return Decimal128.fromString(value?.toString());
203+
if (value === undefined) return undefined;
204+
if (value === null || value === "") return null;
205+
206+
if (field.type === AdminForthDataTypes.DATETIME) {
207+
return dayjs(value).isValid() ? dayjs(value).toDate() : null;
208+
}
209+
210+
if (field.type === AdminForthDataTypes.DATE) {
211+
const d = dayjs(value);
212+
return d.isValid() ? d.startOf("day").toDate() : null;
213+
}
214+
215+
if (field.type === AdminForthDataTypes.BOOLEAN) {
216+
return value === null ? null : !!value;
217+
}
218+
219+
if (field.type === AdminForthDataTypes.INTEGER) {
220+
const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
221+
return Number.isFinite(n) ? Math.trunc(n) : null;
222+
}
223+
224+
if (field.type === AdminForthDataTypes.FLOAT) {
225+
const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
226+
return Number.isFinite(n) ? new Double(n) : null;
227+
}
228+
229+
if (field.type === AdminForthDataTypes.DECIMAL) {
230+
return Decimal128.fromString(value.toString());
216231
}
217232
return value;
218233
}
@@ -251,7 +266,7 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
251266
return { $expr: { [mongoExprOp]: [left, right] } };
252267
}
253268
const column = resource.dataSourceColumns.find((col) => col.name === (filter as IAdminForthSingleFilter).field);
254-
if (['integer', 'decimal', 'float'].includes(column.type)) {
269+
if ([AdminForthDataTypes.INTEGER, AdminForthDataTypes.DECIMAL, AdminForthDataTypes.FLOAT].includes(column.type)) {
255270
return { [(filter as IAdminForthSingleFilter).field]: this.OperatorsMap[filter.operator](+(filter as IAdminForthSingleFilter).value) };
256271
}
257272
return { [(filter as IAdminForthSingleFilter).field]: this.OperatorsMap[filter.operator]((filter as IAdminForthSingleFilter).value) };
@@ -315,30 +330,36 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
315330
const collection = this.client.db().collection(tableName);
316331
const result = {};
317332
for (const column of columns) {
318-
result[column] = await collection
333+
result[column.name] = await collection
319334
.aggregate([
320-
{ $group: { _id: null, min: { $min: `$${column}` }, max: { $max: `$${column}` } } },
335+
{ $group: { _id: null, min: { $min: `$${column.name}` }, max: { $max: `$${column.name}` } } },
321336
])
322337
.toArray();
323338
}
324339
return result;
325340
}
326341

327342
async createRecordOriginalValues({ resource, record }): Promise<string> {
328-
const tableName = resource.table;
329-
const collection = this.client.db().collection(tableName);
330-
const columns = Object.keys(record);
343+
const collection = this.client.db().collection(resource.table);
344+
const colsByName = new Map(resource.dataSourceColumns.map((c) => [c.name, c]));
331345
const newRecord = {};
332-
for (const colName of columns) {
333-
newRecord[colName] = record[colName];
346+
for (const [key, raw] of Object.entries(record)) {
347+
const col = colsByName.get(key);
348+
newRecord[key] = col ? this.setFieldValue(col, raw) : raw;
334349
}
335350
const ret = await collection.insertOne(newRecord);
336351
return ret.insertedId;
337352
}
338353

339354
async updateRecordOriginalValues({ resource, recordId, newValues }) {
340355
const collection = this.client.db().collection(resource.table);
341-
await collection.updateOne({ [this.getPrimaryKey(resource)]: recordId }, { $set: newValues });
356+
const colsByName = new Map(resource.dataSourceColumns.map((c) => [c.name, c]));
357+
const updatedValues = {};
358+
for (const [key, raw] of Object.entries(newValues)) {
359+
const col = colsByName.get(key);
360+
updatedValues[key] = col ? this.setFieldValue(col, raw) : raw;
361+
}
362+
await collection.updateOne({ [this.getPrimaryKey(resource)]: recordId }, { $set: updatedValues });
342363
}
343364

344365
async deleteRecord({ resource, recordId }): Promise<boolean> {

0 commit comments

Comments
 (0)