@jskit-ai/crud-server-generator 0.1.59 → 0.1.60
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/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/crud-server-generator",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.60",
|
|
5
5
|
kind: "generator",
|
|
6
6
|
description: "CRUD server generator with routes, actions, and persistence scaffolding.",
|
|
7
7
|
options: {
|
|
@@ -151,13 +151,13 @@ export default Object.freeze({
|
|
|
151
151
|
mutations: {
|
|
152
152
|
dependencies: {
|
|
153
153
|
runtime: {
|
|
154
|
-
"@jskit-ai/auth-core": "0.1.
|
|
155
|
-
"@jskit-ai/crud-core": "0.1.
|
|
156
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
157
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
158
|
-
"@jskit-ai/kernel": "0.1.
|
|
159
|
-
"@jskit-ai/realtime": "0.1.
|
|
160
|
-
"@jskit-ai/users-core": "0.1.
|
|
154
|
+
"@jskit-ai/auth-core": "0.1.51",
|
|
155
|
+
"@jskit-ai/crud-core": "0.1.60",
|
|
156
|
+
"@jskit-ai/database-runtime": "0.1.52",
|
|
157
|
+
"@jskit-ai/http-runtime": "0.1.51",
|
|
158
|
+
"@jskit-ai/kernel": "0.1.52",
|
|
159
|
+
"@jskit-ai/realtime": "0.1.51",
|
|
160
|
+
"@jskit-ai/users-core": "0.1.62",
|
|
161
161
|
"@local/${option:namespace|kebab}": "file:packages/${option:namespace|kebab}",
|
|
162
162
|
"typebox": "^1.0.81"
|
|
163
163
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/crud-server-generator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.60",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@babel/parser": "^7.29.2",
|
|
16
|
-
"@jskit-ai/crud-core": "0.1.
|
|
17
|
-
"@jskit-ai/database-runtime": "0.1.
|
|
18
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
19
|
-
"@jskit-ai/kernel": "0.1.
|
|
20
|
-
"@jskit-ai/users-core": "0.1.
|
|
16
|
+
"@jskit-ai/crud-core": "0.1.60",
|
|
17
|
+
"@jskit-ai/database-runtime": "0.1.52",
|
|
18
|
+
"@jskit-ai/http-runtime": "0.1.51",
|
|
19
|
+
"@jskit-ai/kernel": "0.1.52",
|
|
20
|
+
"@jskit-ai/users-core": "0.1.62",
|
|
21
21
|
"recast": "^0.23.11",
|
|
22
22
|
"typebox": "^1.0.81"
|
|
23
23
|
}
|
|
@@ -392,6 +392,7 @@ function resolveColumnKey(column, idColumn) {
|
|
|
392
392
|
}
|
|
393
393
|
|
|
394
394
|
const NUMERIC_CHECK_CONSTRAINT_PATTERN = /(?:`([^`]+)`|([A-Za-z_][A-Za-z0-9_]*))\s*(>=|>|<=|<)\s*(-?\d+(?:\.\d+)?)/g;
|
|
395
|
+
const NUMERIC_CHECK_CONSTRAINT_BETWEEN_PATTERN = /(?:`([^`]+)`|([A-Za-z_][A-Za-z0-9_]*))\s+between\s+(-?\d+(?:\.\d+)?)\s+and\s+(-?\d+(?:\.\d+)?)/gi;
|
|
395
396
|
|
|
396
397
|
function normalizeNumericBoundValue(value, scale = null) {
|
|
397
398
|
const parsed = Number(value);
|
|
@@ -452,6 +453,83 @@ function applyUpperBound(current = null, candidate = null) {
|
|
|
452
453
|
return current;
|
|
453
454
|
}
|
|
454
455
|
|
|
456
|
+
function applyNumericConstraintBound(target = {}, column = null, operator = "", rawValue = null) {
|
|
457
|
+
if (!column || !Number.isFinite(rawValue)) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (operator === ">=" || operator === ">") {
|
|
462
|
+
let candidate = null;
|
|
463
|
+
if (operator === ">=") {
|
|
464
|
+
candidate = {
|
|
465
|
+
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
466
|
+
exclusive: false
|
|
467
|
+
};
|
|
468
|
+
} else {
|
|
469
|
+
const exclusiveStep = resolveNumericExclusiveStep(column);
|
|
470
|
+
if (exclusiveStep != null) {
|
|
471
|
+
candidate = {
|
|
472
|
+
value: normalizeNumericBoundValue(rawValue + exclusiveStep, column.numericScale),
|
|
473
|
+
exclusive: false
|
|
474
|
+
};
|
|
475
|
+
} else {
|
|
476
|
+
candidate = {
|
|
477
|
+
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
478
|
+
exclusive: true
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const nextBound = applyLowerBound(
|
|
484
|
+
target.minimum != null || target.exclusiveMinimum != null
|
|
485
|
+
? {
|
|
486
|
+
value: target.minimum ?? target.exclusiveMinimum,
|
|
487
|
+
exclusive: target.exclusiveMinimum != null
|
|
488
|
+
}
|
|
489
|
+
: null,
|
|
490
|
+
candidate
|
|
491
|
+
);
|
|
492
|
+
target.minimum = nextBound?.exclusive === true ? null : nextBound?.value ?? null;
|
|
493
|
+
target.exclusiveMinimum = nextBound?.exclusive === true ? nextBound?.value ?? null : null;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (operator === "<=" || operator === "<") {
|
|
498
|
+
let candidate = null;
|
|
499
|
+
if (operator === "<=") {
|
|
500
|
+
candidate = {
|
|
501
|
+
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
502
|
+
exclusive: false
|
|
503
|
+
};
|
|
504
|
+
} else {
|
|
505
|
+
const exclusiveStep = resolveNumericExclusiveStep(column);
|
|
506
|
+
if (exclusiveStep != null) {
|
|
507
|
+
candidate = {
|
|
508
|
+
value: normalizeNumericBoundValue(rawValue - exclusiveStep, column.numericScale),
|
|
509
|
+
exclusive: false
|
|
510
|
+
};
|
|
511
|
+
} else {
|
|
512
|
+
candidate = {
|
|
513
|
+
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
514
|
+
exclusive: true
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const nextBound = applyUpperBound(
|
|
520
|
+
target.maximum != null || target.exclusiveMaximum != null
|
|
521
|
+
? {
|
|
522
|
+
value: target.maximum ?? target.exclusiveMaximum,
|
|
523
|
+
exclusive: target.exclusiveMaximum != null
|
|
524
|
+
}
|
|
525
|
+
: null,
|
|
526
|
+
candidate
|
|
527
|
+
);
|
|
528
|
+
target.maximum = nextBound?.exclusive === true ? null : nextBound?.value ?? null;
|
|
529
|
+
target.exclusiveMaximum = nextBound?.exclusive === true ? nextBound?.value ?? null : null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
455
533
|
function resolveColumnNumericBounds(snapshot = {}) {
|
|
456
534
|
const byColumnName = new Map();
|
|
457
535
|
const columns = Array.isArray(snapshot.columns) ? snapshot.columns : [];
|
|
@@ -487,6 +565,22 @@ function resolveColumnNumericBounds(snapshot = {}) {
|
|
|
487
565
|
continue;
|
|
488
566
|
}
|
|
489
567
|
|
|
568
|
+
let betweenMatch = null;
|
|
569
|
+
while ((betweenMatch = NUMERIC_CHECK_CONSTRAINT_BETWEEN_PATTERN.exec(clause)) != null) {
|
|
570
|
+
const columnName = String(betweenMatch[1] || betweenMatch[2] || "");
|
|
571
|
+
const lowerValue = Number(betweenMatch[3]);
|
|
572
|
+
const upperValue = Number(betweenMatch[4]);
|
|
573
|
+
const column = numericColumnsByName.get(columnName) || null;
|
|
574
|
+
if (!column || !Number.isFinite(lowerValue) || !Number.isFinite(upperValue)) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const target = getColumnBounds(columnName);
|
|
579
|
+
applyNumericConstraintBound(target, column, ">=", lowerValue);
|
|
580
|
+
applyNumericConstraintBound(target, column, "<=", upperValue);
|
|
581
|
+
}
|
|
582
|
+
NUMERIC_CHECK_CONSTRAINT_BETWEEN_PATTERN.lastIndex = 0;
|
|
583
|
+
|
|
490
584
|
let match = null;
|
|
491
585
|
while ((match = NUMERIC_CHECK_CONSTRAINT_PATTERN.exec(clause)) != null) {
|
|
492
586
|
const columnName = String(match[1] || match[2] || "");
|
|
@@ -498,76 +592,7 @@ function resolveColumnNumericBounds(snapshot = {}) {
|
|
|
498
592
|
}
|
|
499
593
|
|
|
500
594
|
const target = getColumnBounds(columnName);
|
|
501
|
-
|
|
502
|
-
let candidate = null;
|
|
503
|
-
if (operator === ">=") {
|
|
504
|
-
candidate = {
|
|
505
|
-
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
506
|
-
exclusive: false
|
|
507
|
-
};
|
|
508
|
-
} else {
|
|
509
|
-
const exclusiveStep = resolveNumericExclusiveStep(column);
|
|
510
|
-
if (exclusiveStep != null) {
|
|
511
|
-
candidate = {
|
|
512
|
-
value: normalizeNumericBoundValue(rawValue + exclusiveStep, column.numericScale),
|
|
513
|
-
exclusive: false
|
|
514
|
-
};
|
|
515
|
-
} else {
|
|
516
|
-
candidate = {
|
|
517
|
-
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
518
|
-
exclusive: true
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
const nextBound = applyLowerBound(
|
|
524
|
-
target.minimum != null || target.exclusiveMinimum != null
|
|
525
|
-
? {
|
|
526
|
-
value: target.minimum ?? target.exclusiveMinimum,
|
|
527
|
-
exclusive: target.exclusiveMinimum != null
|
|
528
|
-
}
|
|
529
|
-
: null,
|
|
530
|
-
candidate
|
|
531
|
-
);
|
|
532
|
-
target.minimum = nextBound?.exclusive === true ? null : nextBound?.value ?? null;
|
|
533
|
-
target.exclusiveMinimum = nextBound?.exclusive === true ? nextBound?.value ?? null : null;
|
|
534
|
-
continue;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (operator === "<=" || operator === "<") {
|
|
538
|
-
let candidate = null;
|
|
539
|
-
if (operator === "<=") {
|
|
540
|
-
candidate = {
|
|
541
|
-
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
542
|
-
exclusive: false
|
|
543
|
-
};
|
|
544
|
-
} else {
|
|
545
|
-
const exclusiveStep = resolveNumericExclusiveStep(column);
|
|
546
|
-
if (exclusiveStep != null) {
|
|
547
|
-
candidate = {
|
|
548
|
-
value: normalizeNumericBoundValue(rawValue - exclusiveStep, column.numericScale),
|
|
549
|
-
exclusive: false
|
|
550
|
-
};
|
|
551
|
-
} else {
|
|
552
|
-
candidate = {
|
|
553
|
-
value: normalizeNumericBoundValue(rawValue, column.numericScale),
|
|
554
|
-
exclusive: true
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
const nextBound = applyUpperBound(
|
|
560
|
-
target.maximum != null || target.exclusiveMaximum != null
|
|
561
|
-
? {
|
|
562
|
-
value: target.maximum ?? target.exclusiveMaximum,
|
|
563
|
-
exclusive: target.exclusiveMaximum != null
|
|
564
|
-
}
|
|
565
|
-
: null,
|
|
566
|
-
candidate
|
|
567
|
-
);
|
|
568
|
-
target.maximum = nextBound?.exclusive === true ? null : nextBound?.value ?? null;
|
|
569
|
-
target.exclusiveMaximum = nextBound?.exclusive === true ? nextBound?.value ?? null : null;
|
|
570
|
-
}
|
|
595
|
+
applyNumericConstraintBound(target, column, operator, rawValue);
|
|
571
596
|
}
|
|
572
597
|
NUMERIC_CHECK_CONSTRAINT_PATTERN.lastIndex = 0;
|
|
573
598
|
}
|
|
@@ -808,13 +808,35 @@ test("resolveScaffoldColumns derives resource numeric bounds from check constrai
|
|
|
808
808
|
enumValues: Object.freeze([])
|
|
809
809
|
});
|
|
810
810
|
|
|
811
|
+
const severityColumn = Object.freeze({
|
|
812
|
+
name: "severity",
|
|
813
|
+
key: "severity",
|
|
814
|
+
dataType: "tinyint",
|
|
815
|
+
columnType: "tinyint unsigned",
|
|
816
|
+
typeKind: "integer",
|
|
817
|
+
nullable: true,
|
|
818
|
+
hasDefault: false,
|
|
819
|
+
defaultValue: null,
|
|
820
|
+
autoIncrement: false,
|
|
821
|
+
unsigned: true,
|
|
822
|
+
extra: "",
|
|
823
|
+
maxLength: null,
|
|
824
|
+
numericPrecision: 3,
|
|
825
|
+
numericScale: 0,
|
|
826
|
+
datetimePrecision: null,
|
|
827
|
+
characterSetName: "",
|
|
828
|
+
collationName: "",
|
|
829
|
+
enumValues: Object.freeze([])
|
|
830
|
+
});
|
|
831
|
+
|
|
811
832
|
const scaffoldColumns = __testables.resolveScaffoldColumns({
|
|
812
833
|
...snapshot,
|
|
813
834
|
columns: Object.freeze([
|
|
814
835
|
snapshot.columns[0],
|
|
815
836
|
inputWeightColumn,
|
|
816
837
|
batchedDailySequenceColumn,
|
|
817
|
-
moistureLevelColumn
|
|
838
|
+
moistureLevelColumn,
|
|
839
|
+
severityColumn
|
|
818
840
|
]),
|
|
819
841
|
checkConstraints: Object.freeze([
|
|
820
842
|
Object.freeze({
|
|
@@ -828,6 +850,10 @@ test("resolveScaffoldColumns derives resource numeric bounds from check constrai
|
|
|
828
850
|
Object.freeze({
|
|
829
851
|
name: "chk_batches_moisture_level",
|
|
830
852
|
clause: "`moisture_level` is null or `moisture_level` >= 0 and `moisture_level` <= 100"
|
|
853
|
+
}),
|
|
854
|
+
Object.freeze({
|
|
855
|
+
name: "chk_pet_notes_severity",
|
|
856
|
+
clause: "`severity` is null or `severity` between 1 and 10"
|
|
831
857
|
})
|
|
832
858
|
])
|
|
833
859
|
});
|
|
@@ -835,6 +861,7 @@ test("resolveScaffoldColumns derives resource numeric bounds from check constrai
|
|
|
835
861
|
const inputWeight = scaffoldColumns.find((column) => column.name === "input_weight");
|
|
836
862
|
const batchedDailySequence = scaffoldColumns.find((column) => column.name === "batched_daily_sequence");
|
|
837
863
|
const moistureLevel = scaffoldColumns.find((column) => column.name === "moisture_level");
|
|
864
|
+
const severity = scaffoldColumns.find((column) => column.name === "severity");
|
|
838
865
|
|
|
839
866
|
assert.equal(
|
|
840
867
|
__testables.renderResourceFieldSchema(inputWeight),
|
|
@@ -848,6 +875,10 @@ test("resolveScaffoldColumns derives resource numeric bounds from check constrai
|
|
|
848
875
|
__testables.renderResourceFieldSchema(moistureLevel),
|
|
849
876
|
"Type.Union([Type.Number({ minimum: 0, maximum: 100 }), Type.Null()])"
|
|
850
877
|
);
|
|
878
|
+
assert.equal(
|
|
879
|
+
__testables.renderResourceFieldSchema(severity),
|
|
880
|
+
"Type.Union([Type.Integer({ minimum: 1, maximum: 10 }), Type.Null()])"
|
|
881
|
+
);
|
|
851
882
|
});
|
|
852
883
|
|
|
853
884
|
test("buildReplacementsFromSnapshot normalizes nullable temporal inputs without invalid date errors", () => {
|