@dyrected/db-mysql 2.17.0 → 2.18.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/dist/index.cjs +79 -22
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +80 -23
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -50,6 +50,24 @@ function parseMysqlDuplicateKey(message) {
|
|
|
50
50
|
}
|
|
51
51
|
return { field, value };
|
|
52
52
|
}
|
|
53
|
+
function jsonWhereExpr(field) {
|
|
54
|
+
const path = `JSON_EXTRACT(data, '$.${field}')`;
|
|
55
|
+
return `IF(JSON_TYPE(${path}) = 'NULL', NULL, IF(JSON_TYPE(${path}) = 'BOOLEAN', IF(${path} = TRUE, 1, 0), JSON_UNQUOTE(${path})))`;
|
|
56
|
+
}
|
|
57
|
+
var DATE_TYPES = /* @__PURE__ */ new Set(["date", "datetime"]);
|
|
58
|
+
var ISO_WITH_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/;
|
|
59
|
+
var MYSQL_DATETIME = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/;
|
|
60
|
+
function toDatetimeColumn(value) {
|
|
61
|
+
if (typeof value !== "string" || !ISO_WITH_TIME.test(value)) return value;
|
|
62
|
+
const date = new Date(value);
|
|
63
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
64
|
+
return date.toISOString().replace("T", " ").replace("Z", "");
|
|
65
|
+
}
|
|
66
|
+
function fromDatetimeColumn(value) {
|
|
67
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? value : value.toISOString();
|
|
68
|
+
if (typeof value === "string" && MYSQL_DATETIME.test(value)) return `${value.replace(" ", "T")}Z`;
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
53
71
|
function isNumericOp(val) {
|
|
54
72
|
return val !== null && typeof val === "object" && !Array.isArray(val) && ("increment" in val || "decrement" in val);
|
|
55
73
|
}
|
|
@@ -352,7 +370,15 @@ FIX INSTRUCTIONS:
|
|
|
352
370
|
console.log(`[dyrected/mysql] Promoting field "${field.name}" to column in ${tableName}`);
|
|
353
371
|
const isUniqueOrIndexed = field.unique || indexedFields.has(field.name);
|
|
354
372
|
let sqlType = isUniqueOrIndexed ? "VARCHAR(191)" : "TEXT";
|
|
373
|
+
if (!isUniqueOrIndexed) {
|
|
374
|
+
if ((field.type === "select" || field.type === "radio") && !field.hasMany) sqlType = "VARCHAR(100)";
|
|
375
|
+
else if (field.type === "relationship" && !field.hasMany) sqlType = "VARCHAR(191)";
|
|
376
|
+
else if (field.type === "email") sqlType = "VARCHAR(254)";
|
|
377
|
+
} else if (field.type === "email") {
|
|
378
|
+
sqlType = "VARCHAR(191)";
|
|
379
|
+
}
|
|
355
380
|
if (field.type === "number") sqlType = "DECIMAL(19,4)";
|
|
381
|
+
if (field.type === "money") sqlType = "BIGINT";
|
|
356
382
|
if (field.type === "boolean") sqlType = "TINYINT(1)";
|
|
357
383
|
if (field.type === "date" || field.type === "datetime") sqlType = "DATETIME(3)";
|
|
358
384
|
if (field.type === "textarea" || field.type === "richText" || field.type === "json") sqlType = "LONGTEXT";
|
|
@@ -370,6 +396,8 @@ FIX INSTRUCTIONS:
|
|
|
370
396
|
let castExpr = `JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}'))`;
|
|
371
397
|
if (field.type === "number") {
|
|
372
398
|
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) REGEXP '^-?[0-9]+(\\\\.[0-9]+)?([eE][+-]?[0-9]+)?$', CAST(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) AS DECIMAL(19,4)), NULL)`;
|
|
399
|
+
} else if (field.type === "money") {
|
|
400
|
+
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) REGEXP '^-?[0-9]+$', CAST(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) AS SIGNED), NULL)`;
|
|
373
401
|
} else if (field.type === "boolean") {
|
|
374
402
|
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) IN ('true', '1'), 1, 0)`;
|
|
375
403
|
} else if (field.type === "date" || field.type === "datetime") {
|
|
@@ -388,7 +416,7 @@ FIX INSTRUCTIONS:
|
|
|
388
416
|
const existingIndexNames = new Set(existingIndicesRows.map((r) => r?.Key_name).filter(Boolean));
|
|
389
417
|
for (const field of fields) {
|
|
390
418
|
if (field.unique) {
|
|
391
|
-
const idxName =
|
|
419
|
+
const idxName = (0, import_core.resolveIndexName)("uniq", tableName, [field.name]);
|
|
392
420
|
if (!existingIndexNames.has(idxName) && !existingIndexNames.has(field.name) && !this.failedIndexes.has(idxName)) {
|
|
393
421
|
try {
|
|
394
422
|
const [colInfoRows] = await this.query(`SHOW COLUMNS FROM \`${tableName}\` WHERE Field = ?`, [field.name]);
|
|
@@ -420,7 +448,7 @@ FIX INSTRUCTIONS:
|
|
|
420
448
|
for (const idx of indexes) {
|
|
421
449
|
if (!Array.isArray(idx.fields) || idx.fields.length === 0) continue;
|
|
422
450
|
const isUnique = Boolean(idx.unique);
|
|
423
|
-
const idxName = idx.name ||
|
|
451
|
+
const idxName = idx.name || (0, import_core.resolveIndexName)(isUnique ? "uniq" : "idx", tableName, idx.fields);
|
|
424
452
|
if (!existingIndexNames.has(idxName) && !this.failedIndexes.has(idxName)) {
|
|
425
453
|
for (const fName of idx.fields) {
|
|
426
454
|
try {
|
|
@@ -472,7 +500,7 @@ FIX INSTRUCTIONS:
|
|
|
472
500
|
let whereParams = [];
|
|
473
501
|
if (args.where && Object.keys(args.where).length > 0) {
|
|
474
502
|
const result = (0, import_core.parseSqlWhere)(
|
|
475
|
-
args.where,
|
|
503
|
+
this.coerceBooleanWhere(args.collection, args.where),
|
|
476
504
|
(field) => {
|
|
477
505
|
if (field === "id") return "`id`";
|
|
478
506
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -480,7 +508,7 @@ FIX INSTRUCTIONS:
|
|
|
480
508
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
481
509
|
return `\`${field}\``;
|
|
482
510
|
}
|
|
483
|
-
return
|
|
511
|
+
return jsonWhereExpr(field);
|
|
484
512
|
},
|
|
485
513
|
"?"
|
|
486
514
|
);
|
|
@@ -498,12 +526,13 @@ FIX INSTRUCTIONS:
|
|
|
498
526
|
`SELECT * FROM \`${tableName}\` ${whereSql} ORDER BY ${sort} LIMIT ? OFFSET ?${lock}`,
|
|
499
527
|
[...whereParams, limit, offset]
|
|
500
528
|
);
|
|
529
|
+
const dateCols = this.dateColumns(args.collection);
|
|
501
530
|
const docs = rows.map((r) => {
|
|
502
531
|
const parsedData = JSON.parse(typeof r.data === "string" ? r.data : JSON.stringify(r.data));
|
|
503
532
|
const promotedOverlay = {};
|
|
504
533
|
for (const col of existingCols) {
|
|
505
534
|
if (!["id", "data", "created_at", "updated_at"].includes(col) && r[col] !== void 0 && r[col] !== null) {
|
|
506
|
-
promotedOverlay[col] = r[col];
|
|
535
|
+
promotedOverlay[col] = dateCols.has(col) ? fromDatetimeColumn(r[col]) : r[col];
|
|
507
536
|
}
|
|
508
537
|
}
|
|
509
538
|
return {
|
|
@@ -526,6 +555,11 @@ FIX INSTRUCTIONS:
|
|
|
526
555
|
};
|
|
527
556
|
}
|
|
528
557
|
async findOne(params) {
|
|
558
|
+
if (params.id === void 0 && params.where) {
|
|
559
|
+
const found = await this.find({ collection: params.collection, where: params.where, limit: 1, lock: params.lock });
|
|
560
|
+
return found.docs[0] ?? null;
|
|
561
|
+
}
|
|
562
|
+
if (params.id === void 0) throw new Error("findOne requires either id or where");
|
|
529
563
|
if (!this.inTransaction) await this.ensureTable(params.collection);
|
|
530
564
|
const tableName = this.getTableName(params.collection);
|
|
531
565
|
const lock = this.inTransaction || params.lock === "for-update" ? " FOR UPDATE" : "";
|
|
@@ -534,10 +568,11 @@ FIX INSTRUCTIONS:
|
|
|
534
568
|
if (!row) return null;
|
|
535
569
|
const parsedData = JSON.parse(typeof row.data === "string" ? row.data : JSON.stringify(row.data));
|
|
536
570
|
const existingCols = await this.getTableColumns(tableName);
|
|
571
|
+
const dateCols = this.dateColumns(params.collection);
|
|
537
572
|
const promotedOverlay = {};
|
|
538
573
|
for (const col of existingCols) {
|
|
539
574
|
if (!["id", "data", "created_at", "updated_at"].includes(col) && row[col] !== void 0 && row[col] !== null) {
|
|
540
|
-
promotedOverlay[col] = row[col];
|
|
575
|
+
promotedOverlay[col] = dateCols.has(col) ? fromDatetimeColumn(row[col]) : row[col];
|
|
541
576
|
}
|
|
542
577
|
}
|
|
543
578
|
return {
|
|
@@ -559,18 +594,19 @@ FIX INSTRUCTIONS:
|
|
|
559
594
|
delete data.id;
|
|
560
595
|
delete data.createdAt;
|
|
561
596
|
delete data.updatedAt;
|
|
597
|
+
const dateCols = this.dateColumns(params.collection);
|
|
562
598
|
const promotedValues = {};
|
|
563
599
|
for (const col of existingCols) {
|
|
564
600
|
if (["id", "data", "created_at", "updated_at"].includes(col)) continue;
|
|
565
601
|
if (data[col] !== void 0) {
|
|
566
|
-
promotedValues[col] = data[col];
|
|
602
|
+
promotedValues[col] = dateCols.has(col) ? toDatetimeColumn(data[col]) : data[col];
|
|
567
603
|
}
|
|
568
604
|
}
|
|
569
605
|
const colNames = ["id", "data", "created_at", "updated_at", ...Object.keys(promotedValues).map((k) => `\`${k}\``)];
|
|
570
606
|
const placeholders = colNames.map(() => "?").join(", ");
|
|
571
607
|
const values = [id, JSON.stringify(data), now, now, ...Object.values(promotedValues)];
|
|
572
608
|
await this.query(`INSERT INTO \`${tableName}\` (${colNames.join(", ")}) VALUES (${placeholders})`, values);
|
|
573
|
-
return { id, ...data, ...promotedValues, createdAt: now, updatedAt: now };
|
|
609
|
+
return { id, ...data, ...promotedValues, ...this.isoDates(dateCols, promotedValues), createdAt: now, updatedAt: now };
|
|
574
610
|
}
|
|
575
611
|
async update(params) {
|
|
576
612
|
if (!this.inTransaction) await this.ensureTable(params.collection);
|
|
@@ -584,7 +620,7 @@ FIX INSTRUCTIONS:
|
|
|
584
620
|
whereParams = [params.id];
|
|
585
621
|
if (params.where && Object.keys(params.where).length > 0) {
|
|
586
622
|
const parsed = (0, import_core.parseSqlWhere)(
|
|
587
|
-
params.where,
|
|
623
|
+
this.coerceBooleanWhere(params.collection, params.where),
|
|
588
624
|
(field) => {
|
|
589
625
|
if (field === "id") return "`id`";
|
|
590
626
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -592,7 +628,7 @@ FIX INSTRUCTIONS:
|
|
|
592
628
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
593
629
|
return `\`${field}\``;
|
|
594
630
|
}
|
|
595
|
-
return
|
|
631
|
+
return jsonWhereExpr(field);
|
|
596
632
|
},
|
|
597
633
|
"?"
|
|
598
634
|
);
|
|
@@ -601,7 +637,7 @@ FIX INSTRUCTIONS:
|
|
|
601
637
|
}
|
|
602
638
|
} else if (params.where && Object.keys(params.where).length > 0) {
|
|
603
639
|
const parsed = (0, import_core.parseSqlWhere)(
|
|
604
|
-
params.where,
|
|
640
|
+
this.coerceBooleanWhere(params.collection, params.where),
|
|
605
641
|
(field) => {
|
|
606
642
|
if (field === "id") return "`id`";
|
|
607
643
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -609,7 +645,7 @@ FIX INSTRUCTIONS:
|
|
|
609
645
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
610
646
|
return `\`${field}\``;
|
|
611
647
|
}
|
|
612
|
-
return
|
|
648
|
+
return jsonWhereExpr(field);
|
|
613
649
|
},
|
|
614
650
|
"?"
|
|
615
651
|
);
|
|
@@ -622,6 +658,7 @@ FIX INSTRUCTIONS:
|
|
|
622
658
|
const setParams = [];
|
|
623
659
|
const jsonPaths = [];
|
|
624
660
|
const jsonParams = [];
|
|
661
|
+
const dateColsForUpdate = this.dateColumns(params.collection);
|
|
625
662
|
for (const [key, val] of Object.entries(params.data)) {
|
|
626
663
|
if (["id", "createdAt", "updatedAt"].includes(key)) continue;
|
|
627
664
|
const isPromoted = existingCols.includes(key) && !["id", "data", "created_at", "updated_at"].includes(key);
|
|
@@ -640,7 +677,7 @@ FIX INSTRUCTIONS:
|
|
|
640
677
|
if (isPromoted) {
|
|
641
678
|
const escapedCol = escapeMysqlIdentifier(key);
|
|
642
679
|
setClauses.push(`${escapedCol} = ?`);
|
|
643
|
-
setParams.push(val);
|
|
680
|
+
setParams.push(dateColsForUpdate.has(key) ? toDatetimeColumn(val) : val);
|
|
644
681
|
jsonPaths.push(`'$.${key}', ${escapedCol}`);
|
|
645
682
|
} else if (val === null) {
|
|
646
683
|
jsonPaths.push(`'$.${key}', CAST('null' AS JSON)`);
|
|
@@ -675,6 +712,21 @@ FIX INSTRUCTIONS:
|
|
|
675
712
|
}
|
|
676
713
|
return { id: targetId, ...params.data, affectedRows: res?.affectedRows ?? 0, updatedAt: now };
|
|
677
714
|
}
|
|
715
|
+
/** Re-expresses bound date values as ISO strings for the document returned from a write. */
|
|
716
|
+
isoDates(dateCols, values) {
|
|
717
|
+
const out = {};
|
|
718
|
+
for (const col of dateCols) if (col in values) out[col] = fromDatetimeColumn(values[col]);
|
|
719
|
+
return out;
|
|
720
|
+
}
|
|
721
|
+
dateColumns(collection) {
|
|
722
|
+
return new Set(
|
|
723
|
+
(this.collectionConfigs.get(collection)?.fields ?? []).filter((f) => DATE_TYPES.has(f.type) && f.name).map((f) => f.name)
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
/** Applies {@link coerceBooleanWhere} using the collection's declared field types. */
|
|
727
|
+
coerceBooleanWhere(collection, where) {
|
|
728
|
+
return (0, import_core.coerceBooleanWhere)(where, this.collectionConfigs.get(collection)?.fields);
|
|
729
|
+
}
|
|
678
730
|
async sync(collections) {
|
|
679
731
|
for (const col of collections) {
|
|
680
732
|
this.collectionConfigs.set(col.slug, col);
|
|
@@ -739,7 +791,7 @@ FIX INSTRUCTIONS:
|
|
|
739
791
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
740
792
|
return `\`${field}\``;
|
|
741
793
|
}
|
|
742
|
-
return
|
|
794
|
+
return jsonWhereExpr(field);
|
|
743
795
|
};
|
|
744
796
|
const toCastExpr = (rawField, cast) => {
|
|
745
797
|
const base = toFieldExpr(rawField);
|
|
@@ -749,13 +801,20 @@ FIX INSTRUCTIONS:
|
|
|
749
801
|
const sqlType = cast === "integer" ? "SIGNED" : "DECIMAL(20,6)";
|
|
750
802
|
return `IF(${base} REGEXP '^-?[0-9]+(\\\\.[0-9]+)?([eE][+-]?[0-9]+)?$', CAST(${base} AS ${sqlType}), NULL)`;
|
|
751
803
|
};
|
|
804
|
+
const toDistinctValues = (raw) => {
|
|
805
|
+
const parsed = Array.isArray(raw) ? raw : typeof raw === "string" ? JSON.parse(raw) : raw ?? [];
|
|
806
|
+
if (!Array.isArray(parsed)) return [];
|
|
807
|
+
return Array.from(new Set(parsed.filter((v) => v !== null && v !== void 0)));
|
|
808
|
+
};
|
|
809
|
+
const groupFieldType = args.groupBy ? (this.collectionConfigs.get(args.collection)?.fields ?? []).find((f) => f.name === args.groupBy)?.type : void 0;
|
|
810
|
+
const groupKeyOf = (raw) => (0, import_core.normalizeGroupKey)(raw, groupFieldType);
|
|
752
811
|
const selectParts = [];
|
|
753
812
|
const allParams = [];
|
|
754
813
|
const isDistinctMap = {};
|
|
755
814
|
for (const [name, op] of Object.entries(args.aggregates)) {
|
|
756
815
|
let whereSql = null;
|
|
757
816
|
if (op.where && Object.keys(op.where).length > 0) {
|
|
758
|
-
const parsed = (0, import_core.parseSqlWhere)(op.where, toFieldExpr, "?");
|
|
817
|
+
const parsed = (0, import_core.parseSqlWhere)(this.coerceBooleanWhere(args.collection, op.where), toFieldExpr, "?");
|
|
759
818
|
whereSql = parsed.sql;
|
|
760
819
|
allParams.push(...parsed.params);
|
|
761
820
|
}
|
|
@@ -766,7 +825,7 @@ FIX INSTRUCTIONS:
|
|
|
766
825
|
} else if ("distinct" in op && typeof op.distinct === "string") {
|
|
767
826
|
isDistinctMap[name] = true;
|
|
768
827
|
const fieldExpr = toFieldExpr(op.distinct);
|
|
769
|
-
aggExpr = whereSql ? `COALESCE(JSON_ARRAYAGG(
|
|
828
|
+
aggExpr = whereSql ? `COALESCE(JSON_ARRAYAGG(IF(${whereSql}, ${fieldExpr}, NULL)), JSON_ARRAY())` : `COALESCE(JSON_ARRAYAGG(${fieldExpr}), JSON_ARRAY())`;
|
|
770
829
|
} else if ("count" in op) {
|
|
771
830
|
aggExpr = whereSql ? `COUNT(IF(${whereSql}, 1, NULL))` : `COUNT(*)`;
|
|
772
831
|
} else if (op.sum) {
|
|
@@ -774,7 +833,7 @@ FIX INSTRUCTIONS:
|
|
|
774
833
|
aggExpr = whereSql ? `SUM(IF(${whereSql}, ${val}, NULL))` : `SUM(${val})`;
|
|
775
834
|
} else if (op.avg) {
|
|
776
835
|
const val = toCastExpr(op.avg, op.cast);
|
|
777
|
-
aggExpr = whereSql ? `AVG(IF(${whereSql}, ${val}, NULL))` : `AVG(${val})`;
|
|
836
|
+
aggExpr = whereSql ? `CAST(AVG(IF(${whereSql}, ${val}, NULL)) AS DOUBLE)` : `CAST(AVG(${val}) AS DOUBLE)`;
|
|
778
837
|
} else if (op.min) {
|
|
779
838
|
const val = toCastExpr(op.min, op.cast);
|
|
780
839
|
aggExpr = whereSql ? `MIN(IF(${whereSql}, ${val}, NULL))` : `MIN(${val})`;
|
|
@@ -794,13 +853,12 @@ FIX INSTRUCTIONS:
|
|
|
794
853
|
const [rows2] = await this.query(query2, allParams);
|
|
795
854
|
const groups = {};
|
|
796
855
|
for (const row2 of rows2 ?? []) {
|
|
797
|
-
const key =
|
|
856
|
+
const key = groupKeyOf(row2.__group_key);
|
|
798
857
|
const groupResult = {};
|
|
799
858
|
for (const name of Object.keys(args.aggregates)) {
|
|
800
859
|
const raw = row2[name];
|
|
801
860
|
if (isDistinctMap[name]) {
|
|
802
|
-
|
|
803
|
-
groupResult[name] = Array.isArray(parsed) ? parsed.filter((v) => v !== null && v !== void 0) : [];
|
|
861
|
+
groupResult[name] = toDistinctValues(raw);
|
|
804
862
|
} else {
|
|
805
863
|
groupResult[name] = raw === null || raw === void 0 ? null : Number(raw);
|
|
806
864
|
}
|
|
@@ -817,8 +875,7 @@ FIX INSTRUCTIONS:
|
|
|
817
875
|
const raw = row[name];
|
|
818
876
|
const op = args.aggregates[name];
|
|
819
877
|
if (isDistinctMap[name]) {
|
|
820
|
-
|
|
821
|
-
result[name] = Array.isArray(parsed) ? parsed.filter((v) => v !== null && v !== void 0) : [];
|
|
878
|
+
result[name] = toDistinctValues(raw);
|
|
822
879
|
} else if (raw instanceof Date) {
|
|
823
880
|
result[name] = raw.toISOString();
|
|
824
881
|
} else if (op?.cast === "date") {
|
package/dist/index.d.cts
CHANGED
|
@@ -44,7 +44,8 @@ declare class MysqlAdapter implements DatabaseAdapter {
|
|
|
44
44
|
}): Promise<PaginatedResult>;
|
|
45
45
|
findOne(params: {
|
|
46
46
|
collection: string;
|
|
47
|
-
id
|
|
47
|
+
id?: string;
|
|
48
|
+
where?: Record<string, unknown>;
|
|
48
49
|
lock?: "for-update";
|
|
49
50
|
}): Promise<any>;
|
|
50
51
|
create(params: {
|
|
@@ -57,6 +58,11 @@ declare class MysqlAdapter implements DatabaseAdapter {
|
|
|
57
58
|
where?: any;
|
|
58
59
|
data: any;
|
|
59
60
|
}): Promise<any>;
|
|
61
|
+
/** Re-expresses bound date values as ISO strings for the document returned from a write. */
|
|
62
|
+
private isoDates;
|
|
63
|
+
private dateColumns;
|
|
64
|
+
/** Applies {@link coerceBooleanWhere} using the collection's declared field types. */
|
|
65
|
+
private coerceBooleanWhere;
|
|
60
66
|
sync(collections: any[]): Promise<void>;
|
|
61
67
|
delete(params: {
|
|
62
68
|
collection: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -44,7 +44,8 @@ declare class MysqlAdapter implements DatabaseAdapter {
|
|
|
44
44
|
}): Promise<PaginatedResult>;
|
|
45
45
|
findOne(params: {
|
|
46
46
|
collection: string;
|
|
47
|
-
id
|
|
47
|
+
id?: string;
|
|
48
|
+
where?: Record<string, unknown>;
|
|
48
49
|
lock?: "for-update";
|
|
49
50
|
}): Promise<any>;
|
|
50
51
|
create(params: {
|
|
@@ -57,6 +58,11 @@ declare class MysqlAdapter implements DatabaseAdapter {
|
|
|
57
58
|
where?: any;
|
|
58
59
|
data: any;
|
|
59
60
|
}): Promise<any>;
|
|
61
|
+
/** Re-expresses bound date values as ISO strings for the document returned from a write. */
|
|
62
|
+
private isoDates;
|
|
63
|
+
private dateColumns;
|
|
64
|
+
/** Applies {@link coerceBooleanWhere} using the collection's declared field types. */
|
|
65
|
+
private coerceBooleanWhere;
|
|
60
66
|
sync(collections: any[]): Promise<void>;
|
|
61
67
|
delete(params: {
|
|
62
68
|
collection: string;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { parseSort, parseSqlWhere, DuplicateKeyError, generateDocumentId } from "@dyrected/core";
|
|
2
|
+
import { parseSort, parseSqlWhere, DuplicateKeyError, generateDocumentId, resolveIndexName, coerceBooleanWhere, normalizeGroupKey } from "@dyrected/core";
|
|
3
3
|
import mysql from "mysql2/promise";
|
|
4
4
|
function parseMysqlDuplicateKey(message) {
|
|
5
5
|
const match = message.match(/Duplicate entry '(.*)' for key '(?:[^.]*\.)?(.*)'/);
|
|
@@ -14,6 +14,24 @@ function parseMysqlDuplicateKey(message) {
|
|
|
14
14
|
}
|
|
15
15
|
return { field, value };
|
|
16
16
|
}
|
|
17
|
+
function jsonWhereExpr(field) {
|
|
18
|
+
const path = `JSON_EXTRACT(data, '$.${field}')`;
|
|
19
|
+
return `IF(JSON_TYPE(${path}) = 'NULL', NULL, IF(JSON_TYPE(${path}) = 'BOOLEAN', IF(${path} = TRUE, 1, 0), JSON_UNQUOTE(${path})))`;
|
|
20
|
+
}
|
|
21
|
+
var DATE_TYPES = /* @__PURE__ */ new Set(["date", "datetime"]);
|
|
22
|
+
var ISO_WITH_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/;
|
|
23
|
+
var MYSQL_DATETIME = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/;
|
|
24
|
+
function toDatetimeColumn(value) {
|
|
25
|
+
if (typeof value !== "string" || !ISO_WITH_TIME.test(value)) return value;
|
|
26
|
+
const date = new Date(value);
|
|
27
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
28
|
+
return date.toISOString().replace("T", " ").replace("Z", "");
|
|
29
|
+
}
|
|
30
|
+
function fromDatetimeColumn(value) {
|
|
31
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? value : value.toISOString();
|
|
32
|
+
if (typeof value === "string" && MYSQL_DATETIME.test(value)) return `${value.replace(" ", "T")}Z`;
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
17
35
|
function isNumericOp(val) {
|
|
18
36
|
return val !== null && typeof val === "object" && !Array.isArray(val) && ("increment" in val || "decrement" in val);
|
|
19
37
|
}
|
|
@@ -316,7 +334,15 @@ FIX INSTRUCTIONS:
|
|
|
316
334
|
console.log(`[dyrected/mysql] Promoting field "${field.name}" to column in ${tableName}`);
|
|
317
335
|
const isUniqueOrIndexed = field.unique || indexedFields.has(field.name);
|
|
318
336
|
let sqlType = isUniqueOrIndexed ? "VARCHAR(191)" : "TEXT";
|
|
337
|
+
if (!isUniqueOrIndexed) {
|
|
338
|
+
if ((field.type === "select" || field.type === "radio") && !field.hasMany) sqlType = "VARCHAR(100)";
|
|
339
|
+
else if (field.type === "relationship" && !field.hasMany) sqlType = "VARCHAR(191)";
|
|
340
|
+
else if (field.type === "email") sqlType = "VARCHAR(254)";
|
|
341
|
+
} else if (field.type === "email") {
|
|
342
|
+
sqlType = "VARCHAR(191)";
|
|
343
|
+
}
|
|
319
344
|
if (field.type === "number") sqlType = "DECIMAL(19,4)";
|
|
345
|
+
if (field.type === "money") sqlType = "BIGINT";
|
|
320
346
|
if (field.type === "boolean") sqlType = "TINYINT(1)";
|
|
321
347
|
if (field.type === "date" || field.type === "datetime") sqlType = "DATETIME(3)";
|
|
322
348
|
if (field.type === "textarea" || field.type === "richText" || field.type === "json") sqlType = "LONGTEXT";
|
|
@@ -334,6 +360,8 @@ FIX INSTRUCTIONS:
|
|
|
334
360
|
let castExpr = `JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}'))`;
|
|
335
361
|
if (field.type === "number") {
|
|
336
362
|
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) REGEXP '^-?[0-9]+(\\\\.[0-9]+)?([eE][+-]?[0-9]+)?$', CAST(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) AS DECIMAL(19,4)), NULL)`;
|
|
363
|
+
} else if (field.type === "money") {
|
|
364
|
+
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) REGEXP '^-?[0-9]+$', CAST(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) AS SIGNED), NULL)`;
|
|
337
365
|
} else if (field.type === "boolean") {
|
|
338
366
|
castExpr = `IF(JSON_UNQUOTE(JSON_EXTRACT(data, '$.${field.name}')) IN ('true', '1'), 1, 0)`;
|
|
339
367
|
} else if (field.type === "date" || field.type === "datetime") {
|
|
@@ -352,7 +380,7 @@ FIX INSTRUCTIONS:
|
|
|
352
380
|
const existingIndexNames = new Set(existingIndicesRows.map((r) => r?.Key_name).filter(Boolean));
|
|
353
381
|
for (const field of fields) {
|
|
354
382
|
if (field.unique) {
|
|
355
|
-
const idxName =
|
|
383
|
+
const idxName = resolveIndexName("uniq", tableName, [field.name]);
|
|
356
384
|
if (!existingIndexNames.has(idxName) && !existingIndexNames.has(field.name) && !this.failedIndexes.has(idxName)) {
|
|
357
385
|
try {
|
|
358
386
|
const [colInfoRows] = await this.query(`SHOW COLUMNS FROM \`${tableName}\` WHERE Field = ?`, [field.name]);
|
|
@@ -384,7 +412,7 @@ FIX INSTRUCTIONS:
|
|
|
384
412
|
for (const idx of indexes) {
|
|
385
413
|
if (!Array.isArray(idx.fields) || idx.fields.length === 0) continue;
|
|
386
414
|
const isUnique = Boolean(idx.unique);
|
|
387
|
-
const idxName = idx.name ||
|
|
415
|
+
const idxName = idx.name || resolveIndexName(isUnique ? "uniq" : "idx", tableName, idx.fields);
|
|
388
416
|
if (!existingIndexNames.has(idxName) && !this.failedIndexes.has(idxName)) {
|
|
389
417
|
for (const fName of idx.fields) {
|
|
390
418
|
try {
|
|
@@ -436,7 +464,7 @@ FIX INSTRUCTIONS:
|
|
|
436
464
|
let whereParams = [];
|
|
437
465
|
if (args.where && Object.keys(args.where).length > 0) {
|
|
438
466
|
const result = parseSqlWhere(
|
|
439
|
-
args.where,
|
|
467
|
+
this.coerceBooleanWhere(args.collection, args.where),
|
|
440
468
|
(field) => {
|
|
441
469
|
if (field === "id") return "`id`";
|
|
442
470
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -444,7 +472,7 @@ FIX INSTRUCTIONS:
|
|
|
444
472
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
445
473
|
return `\`${field}\``;
|
|
446
474
|
}
|
|
447
|
-
return
|
|
475
|
+
return jsonWhereExpr(field);
|
|
448
476
|
},
|
|
449
477
|
"?"
|
|
450
478
|
);
|
|
@@ -462,12 +490,13 @@ FIX INSTRUCTIONS:
|
|
|
462
490
|
`SELECT * FROM \`${tableName}\` ${whereSql} ORDER BY ${sort} LIMIT ? OFFSET ?${lock}`,
|
|
463
491
|
[...whereParams, limit, offset]
|
|
464
492
|
);
|
|
493
|
+
const dateCols = this.dateColumns(args.collection);
|
|
465
494
|
const docs = rows.map((r) => {
|
|
466
495
|
const parsedData = JSON.parse(typeof r.data === "string" ? r.data : JSON.stringify(r.data));
|
|
467
496
|
const promotedOverlay = {};
|
|
468
497
|
for (const col of existingCols) {
|
|
469
498
|
if (!["id", "data", "created_at", "updated_at"].includes(col) && r[col] !== void 0 && r[col] !== null) {
|
|
470
|
-
promotedOverlay[col] = r[col];
|
|
499
|
+
promotedOverlay[col] = dateCols.has(col) ? fromDatetimeColumn(r[col]) : r[col];
|
|
471
500
|
}
|
|
472
501
|
}
|
|
473
502
|
return {
|
|
@@ -490,6 +519,11 @@ FIX INSTRUCTIONS:
|
|
|
490
519
|
};
|
|
491
520
|
}
|
|
492
521
|
async findOne(params) {
|
|
522
|
+
if (params.id === void 0 && params.where) {
|
|
523
|
+
const found = await this.find({ collection: params.collection, where: params.where, limit: 1, lock: params.lock });
|
|
524
|
+
return found.docs[0] ?? null;
|
|
525
|
+
}
|
|
526
|
+
if (params.id === void 0) throw new Error("findOne requires either id or where");
|
|
493
527
|
if (!this.inTransaction) await this.ensureTable(params.collection);
|
|
494
528
|
const tableName = this.getTableName(params.collection);
|
|
495
529
|
const lock = this.inTransaction || params.lock === "for-update" ? " FOR UPDATE" : "";
|
|
@@ -498,10 +532,11 @@ FIX INSTRUCTIONS:
|
|
|
498
532
|
if (!row) return null;
|
|
499
533
|
const parsedData = JSON.parse(typeof row.data === "string" ? row.data : JSON.stringify(row.data));
|
|
500
534
|
const existingCols = await this.getTableColumns(tableName);
|
|
535
|
+
const dateCols = this.dateColumns(params.collection);
|
|
501
536
|
const promotedOverlay = {};
|
|
502
537
|
for (const col of existingCols) {
|
|
503
538
|
if (!["id", "data", "created_at", "updated_at"].includes(col) && row[col] !== void 0 && row[col] !== null) {
|
|
504
|
-
promotedOverlay[col] = row[col];
|
|
539
|
+
promotedOverlay[col] = dateCols.has(col) ? fromDatetimeColumn(row[col]) : row[col];
|
|
505
540
|
}
|
|
506
541
|
}
|
|
507
542
|
return {
|
|
@@ -523,18 +558,19 @@ FIX INSTRUCTIONS:
|
|
|
523
558
|
delete data.id;
|
|
524
559
|
delete data.createdAt;
|
|
525
560
|
delete data.updatedAt;
|
|
561
|
+
const dateCols = this.dateColumns(params.collection);
|
|
526
562
|
const promotedValues = {};
|
|
527
563
|
for (const col of existingCols) {
|
|
528
564
|
if (["id", "data", "created_at", "updated_at"].includes(col)) continue;
|
|
529
565
|
if (data[col] !== void 0) {
|
|
530
|
-
promotedValues[col] = data[col];
|
|
566
|
+
promotedValues[col] = dateCols.has(col) ? toDatetimeColumn(data[col]) : data[col];
|
|
531
567
|
}
|
|
532
568
|
}
|
|
533
569
|
const colNames = ["id", "data", "created_at", "updated_at", ...Object.keys(promotedValues).map((k) => `\`${k}\``)];
|
|
534
570
|
const placeholders = colNames.map(() => "?").join(", ");
|
|
535
571
|
const values = [id, JSON.stringify(data), now, now, ...Object.values(promotedValues)];
|
|
536
572
|
await this.query(`INSERT INTO \`${tableName}\` (${colNames.join(", ")}) VALUES (${placeholders})`, values);
|
|
537
|
-
return { id, ...data, ...promotedValues, createdAt: now, updatedAt: now };
|
|
573
|
+
return { id, ...data, ...promotedValues, ...this.isoDates(dateCols, promotedValues), createdAt: now, updatedAt: now };
|
|
538
574
|
}
|
|
539
575
|
async update(params) {
|
|
540
576
|
if (!this.inTransaction) await this.ensureTable(params.collection);
|
|
@@ -548,7 +584,7 @@ FIX INSTRUCTIONS:
|
|
|
548
584
|
whereParams = [params.id];
|
|
549
585
|
if (params.where && Object.keys(params.where).length > 0) {
|
|
550
586
|
const parsed = parseSqlWhere(
|
|
551
|
-
params.where,
|
|
587
|
+
this.coerceBooleanWhere(params.collection, params.where),
|
|
552
588
|
(field) => {
|
|
553
589
|
if (field === "id") return "`id`";
|
|
554
590
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -556,7 +592,7 @@ FIX INSTRUCTIONS:
|
|
|
556
592
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
557
593
|
return `\`${field}\``;
|
|
558
594
|
}
|
|
559
|
-
return
|
|
595
|
+
return jsonWhereExpr(field);
|
|
560
596
|
},
|
|
561
597
|
"?"
|
|
562
598
|
);
|
|
@@ -565,7 +601,7 @@ FIX INSTRUCTIONS:
|
|
|
565
601
|
}
|
|
566
602
|
} else if (params.where && Object.keys(params.where).length > 0) {
|
|
567
603
|
const parsed = parseSqlWhere(
|
|
568
|
-
params.where,
|
|
604
|
+
this.coerceBooleanWhere(params.collection, params.where),
|
|
569
605
|
(field) => {
|
|
570
606
|
if (field === "id") return "`id`";
|
|
571
607
|
if (field === "createdAt" || field === "created_at") return "`created_at`";
|
|
@@ -573,7 +609,7 @@ FIX INSTRUCTIONS:
|
|
|
573
609
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
574
610
|
return `\`${field}\``;
|
|
575
611
|
}
|
|
576
|
-
return
|
|
612
|
+
return jsonWhereExpr(field);
|
|
577
613
|
},
|
|
578
614
|
"?"
|
|
579
615
|
);
|
|
@@ -586,6 +622,7 @@ FIX INSTRUCTIONS:
|
|
|
586
622
|
const setParams = [];
|
|
587
623
|
const jsonPaths = [];
|
|
588
624
|
const jsonParams = [];
|
|
625
|
+
const dateColsForUpdate = this.dateColumns(params.collection);
|
|
589
626
|
for (const [key, val] of Object.entries(params.data)) {
|
|
590
627
|
if (["id", "createdAt", "updatedAt"].includes(key)) continue;
|
|
591
628
|
const isPromoted = existingCols.includes(key) && !["id", "data", "created_at", "updated_at"].includes(key);
|
|
@@ -604,7 +641,7 @@ FIX INSTRUCTIONS:
|
|
|
604
641
|
if (isPromoted) {
|
|
605
642
|
const escapedCol = escapeMysqlIdentifier(key);
|
|
606
643
|
setClauses.push(`${escapedCol} = ?`);
|
|
607
|
-
setParams.push(val);
|
|
644
|
+
setParams.push(dateColsForUpdate.has(key) ? toDatetimeColumn(val) : val);
|
|
608
645
|
jsonPaths.push(`'$.${key}', ${escapedCol}`);
|
|
609
646
|
} else if (val === null) {
|
|
610
647
|
jsonPaths.push(`'$.${key}', CAST('null' AS JSON)`);
|
|
@@ -639,6 +676,21 @@ FIX INSTRUCTIONS:
|
|
|
639
676
|
}
|
|
640
677
|
return { id: targetId, ...params.data, affectedRows: res?.affectedRows ?? 0, updatedAt: now };
|
|
641
678
|
}
|
|
679
|
+
/** Re-expresses bound date values as ISO strings for the document returned from a write. */
|
|
680
|
+
isoDates(dateCols, values) {
|
|
681
|
+
const out = {};
|
|
682
|
+
for (const col of dateCols) if (col in values) out[col] = fromDatetimeColumn(values[col]);
|
|
683
|
+
return out;
|
|
684
|
+
}
|
|
685
|
+
dateColumns(collection) {
|
|
686
|
+
return new Set(
|
|
687
|
+
(this.collectionConfigs.get(collection)?.fields ?? []).filter((f) => DATE_TYPES.has(f.type) && f.name).map((f) => f.name)
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
/** Applies {@link coerceBooleanWhere} using the collection's declared field types. */
|
|
691
|
+
coerceBooleanWhere(collection, where) {
|
|
692
|
+
return coerceBooleanWhere(where, this.collectionConfigs.get(collection)?.fields);
|
|
693
|
+
}
|
|
642
694
|
async sync(collections) {
|
|
643
695
|
for (const col of collections) {
|
|
644
696
|
this.collectionConfigs.set(col.slug, col);
|
|
@@ -703,7 +755,7 @@ FIX INSTRUCTIONS:
|
|
|
703
755
|
if (existingCols.includes(field) && !["id", "data"].includes(field)) {
|
|
704
756
|
return `\`${field}\``;
|
|
705
757
|
}
|
|
706
|
-
return
|
|
758
|
+
return jsonWhereExpr(field);
|
|
707
759
|
};
|
|
708
760
|
const toCastExpr = (rawField, cast) => {
|
|
709
761
|
const base = toFieldExpr(rawField);
|
|
@@ -713,13 +765,20 @@ FIX INSTRUCTIONS:
|
|
|
713
765
|
const sqlType = cast === "integer" ? "SIGNED" : "DECIMAL(20,6)";
|
|
714
766
|
return `IF(${base} REGEXP '^-?[0-9]+(\\\\.[0-9]+)?([eE][+-]?[0-9]+)?$', CAST(${base} AS ${sqlType}), NULL)`;
|
|
715
767
|
};
|
|
768
|
+
const toDistinctValues = (raw) => {
|
|
769
|
+
const parsed = Array.isArray(raw) ? raw : typeof raw === "string" ? JSON.parse(raw) : raw ?? [];
|
|
770
|
+
if (!Array.isArray(parsed)) return [];
|
|
771
|
+
return Array.from(new Set(parsed.filter((v) => v !== null && v !== void 0)));
|
|
772
|
+
};
|
|
773
|
+
const groupFieldType = args.groupBy ? (this.collectionConfigs.get(args.collection)?.fields ?? []).find((f) => f.name === args.groupBy)?.type : void 0;
|
|
774
|
+
const groupKeyOf = (raw) => normalizeGroupKey(raw, groupFieldType);
|
|
716
775
|
const selectParts = [];
|
|
717
776
|
const allParams = [];
|
|
718
777
|
const isDistinctMap = {};
|
|
719
778
|
for (const [name, op] of Object.entries(args.aggregates)) {
|
|
720
779
|
let whereSql = null;
|
|
721
780
|
if (op.where && Object.keys(op.where).length > 0) {
|
|
722
|
-
const parsed = parseSqlWhere(op.where, toFieldExpr, "?");
|
|
781
|
+
const parsed = parseSqlWhere(this.coerceBooleanWhere(args.collection, op.where), toFieldExpr, "?");
|
|
723
782
|
whereSql = parsed.sql;
|
|
724
783
|
allParams.push(...parsed.params);
|
|
725
784
|
}
|
|
@@ -730,7 +789,7 @@ FIX INSTRUCTIONS:
|
|
|
730
789
|
} else if ("distinct" in op && typeof op.distinct === "string") {
|
|
731
790
|
isDistinctMap[name] = true;
|
|
732
791
|
const fieldExpr = toFieldExpr(op.distinct);
|
|
733
|
-
aggExpr = whereSql ? `COALESCE(JSON_ARRAYAGG(
|
|
792
|
+
aggExpr = whereSql ? `COALESCE(JSON_ARRAYAGG(IF(${whereSql}, ${fieldExpr}, NULL)), JSON_ARRAY())` : `COALESCE(JSON_ARRAYAGG(${fieldExpr}), JSON_ARRAY())`;
|
|
734
793
|
} else if ("count" in op) {
|
|
735
794
|
aggExpr = whereSql ? `COUNT(IF(${whereSql}, 1, NULL))` : `COUNT(*)`;
|
|
736
795
|
} else if (op.sum) {
|
|
@@ -738,7 +797,7 @@ FIX INSTRUCTIONS:
|
|
|
738
797
|
aggExpr = whereSql ? `SUM(IF(${whereSql}, ${val}, NULL))` : `SUM(${val})`;
|
|
739
798
|
} else if (op.avg) {
|
|
740
799
|
const val = toCastExpr(op.avg, op.cast);
|
|
741
|
-
aggExpr = whereSql ? `AVG(IF(${whereSql}, ${val}, NULL))` : `AVG(${val})`;
|
|
800
|
+
aggExpr = whereSql ? `CAST(AVG(IF(${whereSql}, ${val}, NULL)) AS DOUBLE)` : `CAST(AVG(${val}) AS DOUBLE)`;
|
|
742
801
|
} else if (op.min) {
|
|
743
802
|
const val = toCastExpr(op.min, op.cast);
|
|
744
803
|
aggExpr = whereSql ? `MIN(IF(${whereSql}, ${val}, NULL))` : `MIN(${val})`;
|
|
@@ -758,13 +817,12 @@ FIX INSTRUCTIONS:
|
|
|
758
817
|
const [rows2] = await this.query(query2, allParams);
|
|
759
818
|
const groups = {};
|
|
760
819
|
for (const row2 of rows2 ?? []) {
|
|
761
|
-
const key =
|
|
820
|
+
const key = groupKeyOf(row2.__group_key);
|
|
762
821
|
const groupResult = {};
|
|
763
822
|
for (const name of Object.keys(args.aggregates)) {
|
|
764
823
|
const raw = row2[name];
|
|
765
824
|
if (isDistinctMap[name]) {
|
|
766
|
-
|
|
767
|
-
groupResult[name] = Array.isArray(parsed) ? parsed.filter((v) => v !== null && v !== void 0) : [];
|
|
825
|
+
groupResult[name] = toDistinctValues(raw);
|
|
768
826
|
} else {
|
|
769
827
|
groupResult[name] = raw === null || raw === void 0 ? null : Number(raw);
|
|
770
828
|
}
|
|
@@ -781,8 +839,7 @@ FIX INSTRUCTIONS:
|
|
|
781
839
|
const raw = row[name];
|
|
782
840
|
const op = args.aggregates[name];
|
|
783
841
|
if (isDistinctMap[name]) {
|
|
784
|
-
|
|
785
|
-
result[name] = Array.isArray(parsed) ? parsed.filter((v) => v !== null && v !== void 0) : [];
|
|
842
|
+
result[name] = toDistinctValues(raw);
|
|
786
843
|
} else if (raw instanceof Date) {
|
|
787
844
|
result[name] = raw.toISOString();
|
|
788
845
|
} else if (op?.cast === "date") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dyrected/db-mysql",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.1",
|
|
4
4
|
"description": "MySQL adapter for Dyrected CMS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"mysql2": "^3.22.3",
|
|
21
|
-
"@dyrected/core": "^2.
|
|
21
|
+
"@dyrected/core": "^2.18.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"tsup": "^8.0.0",
|