litedbmodel 2.2.5 → 2.2.7
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/README.md +145 -86
- package/dist/Column.d.ts +17 -4
- package/dist/Column.d.ts.map +1 -1
- package/dist/Column.js.map +1 -1
- package/dist/DBModel.d.ts +13 -14
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +20 -21
- package/dist/DBModel.js.map +1 -1
- package/dist/LazyRelation.d.ts +2 -2
- package/dist/LazyRelation.js +2 -2
- package/dist/decorators.d.ts +120 -60
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +379 -248
- package/dist/decorators.js.map +1 -1
- package/dist/index.cjs +283 -217
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/scp/coltype.d.ts +14 -5
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +35 -36
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/decorator-adapter.d.ts +11 -15
- package/dist/scp/decorator-adapter.d.ts.map +1 -1
- package/dist/scp/decorator-adapter.js +11 -15
- package/dist/scp/decorator-adapter.js.map +1 -1
- package/dist/scp/index.cjs +186 -193
- package/dist/scp/index.mjs +186 -193
- package/dist/scp/makesql/json-array.d.ts +6 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +17 -2
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +1 -3
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +8 -10
- package/dist/scp/relation.js.map +1 -1
- package/docs/BENCHMARK.md +3 -3
- package/docs/COMPARISON.md +7 -7
- package/docs/api/README.md +18 -18
- package/docs/api/classes/Conditions.md +1 -1
- package/docs/api/classes/DBHandler.md +1 -1
- package/docs/api/classes/DBModel.md +82 -82
- package/docs/api/classes/LimitExceededError.md +1 -1
- package/docs/api/classes/Middleware.md +1 -1
- package/docs/api/classes/SqlRaw.md +1 -1
- package/docs/api/classes/SqlRef.md +1 -1
- package/docs/api/classes/Values.md +1 -1
- package/docs/api/classes/WriteInReadOnlyContextError.md +1 -1
- package/docs/api/classes/WriteOutsideTransactionError.md +1 -1
- package/docs/api/functions/belongsTo.md +10 -4
- package/docs/api/functions/closeAllPools.md +1 -1
- package/docs/api/functions/condsToRecord.md +2 -2
- package/docs/api/functions/createMiddleware.md +1 -1
- package/docs/api/functions/createPostgresDriver.md +1 -1
- package/docs/api/functions/createSqliteDriver.md +1 -1
- package/docs/api/functions/dbCast.md +1 -1
- package/docs/api/functions/dbCastIn.md +1 -1
- package/docs/api/functions/dbDynamic.md +1 -1
- package/docs/api/functions/dbFalse.md +1 -1
- package/docs/api/functions/dbImmediate.md +1 -1
- package/docs/api/functions/dbIn.md +1 -1
- package/docs/api/functions/dbNotNull.md +1 -1
- package/docs/api/functions/dbNow.md +1 -1
- package/docs/api/functions/dbNull.md +1 -1
- package/docs/api/functions/dbRaw.md +1 -1
- package/docs/api/functions/dbTrue.md +1 -1
- package/docs/api/functions/dbUuid.md +1 -1
- package/docs/api/functions/dbUuidIn.md +1 -1
- package/docs/api/functions/formatLocalDate.md +1 -1
- package/docs/api/functions/formatUTCDate.md +1 -1
- package/docs/api/functions/getDBConfig.md +1 -1
- package/docs/api/functions/getDBHandler.md +1 -1
- package/docs/api/functions/getTransactionConnection.md +1 -1
- package/docs/api/functions/getTransactionContext.md +1 -1
- package/docs/api/functions/hasMany.md +11 -5
- package/docs/api/functions/hasOne.md +10 -4
- package/docs/api/functions/initDBHandler.md +1 -1
- package/docs/api/functions/isAnySqlFragment.md +1 -1
- package/docs/api/functions/isConnectionError.md +1 -1
- package/docs/api/functions/isSqlCondition.md +1 -1
- package/docs/api/functions/isSqlFragment.md +1 -1
- package/docs/api/functions/isSqlRaw.md +1 -1
- package/docs/api/functions/isSqlRef.md +1 -1
- package/docs/api/functions/isSqlTypedFragment.md +1 -1
- package/docs/api/functions/model.md +8 -155
- package/docs/api/functions/parentRef.md +1 -1
- package/docs/api/functions/sql.md +1 -1
- package/docs/api/globals.md +96 -58
- package/docs/api/interfaces/Column.md +1 -1
- package/docs/api/interfaces/ColumnDecorator.md +81 -0
- package/docs/api/interfaces/ColumnOptions.md +6 -10
- package/docs/api/interfaces/CreatedMiddlewareClass.md +1 -1
- package/docs/api/interfaces/DBConfig.md +1 -1
- package/docs/api/interfaces/DBConfigOptions.md +1 -1
- package/docs/api/interfaces/DeleteOptions.md +1 -1
- package/docs/api/interfaces/InsertOptions.md +1 -1
- package/docs/api/interfaces/LimitConfig.md +1 -1
- package/docs/api/interfaces/MiddlewareConfig.md +1 -1
- package/docs/api/interfaces/ModelClassDecorator.md +64 -0
- package/docs/api/interfaces/ModelOptions.md +1 -1
- package/docs/api/interfaces/PkeyResult.md +1 -1
- package/docs/api/interfaces/RelationDecorator.md +72 -0
- package/docs/api/interfaces/SelectOptions.md +1 -1
- package/docs/api/interfaces/SqlCondition.md +1 -1
- package/docs/api/interfaces/SqlFragment.md +1 -1
- package/docs/api/interfaces/SqlTypedFragment.md +1 -1
- package/docs/api/interfaces/TransactionOptions.md +1 -1
- package/docs/api/interfaces/UpdateManyOptions.md +1 -1
- package/docs/api/interfaces/UpdateOptions.md +1 -1
- package/docs/api-guide.md +17 -17
- package/docs/architecture.md +3 -3
- package/docs/sql-tagged-template.md +5 -5
- package/eslint-plugin/rules/require-declare-for-relations.js +59 -4
- package/package.json +11 -10
package/dist/index.cjs
CHANGED
|
@@ -5632,12 +5632,14 @@ function resolvePgArrayCast(sql2, values) {
|
|
|
5632
5632
|
function encodeJsonArrayParam(dialect, values) {
|
|
5633
5633
|
return encodeJsonParam(dialect, values);
|
|
5634
5634
|
}
|
|
5635
|
+
var BIGINT_SENTINEL = "\0int:";
|
|
5635
5636
|
function encodeJsonParam(dialect, payload) {
|
|
5636
|
-
|
|
5637
|
-
if (typeof v === "bigint") return
|
|
5637
|
+
const tagged = JSON.stringify(payload, (_key, v) => {
|
|
5638
|
+
if (typeof v === "bigint") return `${BIGINT_SENTINEL}${v.toString()}`;
|
|
5638
5639
|
if (dialect === "mysql" && typeof v === "boolean") return v ? 1 : 0;
|
|
5639
5640
|
return v;
|
|
5640
5641
|
});
|
|
5642
|
+
return tagged.replace(/"\\u0000int:(-?\d+)"/g, "$1");
|
|
5641
5643
|
}
|
|
5642
5644
|
|
|
5643
5645
|
// src/scp/makesql/json-batch.ts
|
|
@@ -5799,8 +5801,8 @@ function sqlTypeToMaterializeClass(sqlType) {
|
|
|
5799
5801
|
return "passthrough";
|
|
5800
5802
|
}
|
|
5801
5803
|
switch (t) {
|
|
5802
|
-
//
|
|
5803
|
-
//
|
|
5804
|
+
// Integer family. The PostgreSQL SERIAL types are the same integers under an auto-increment
|
|
5805
|
+
// default (SERIAL/SERIAL4=int4, SMALLSERIAL/SERIAL2=int2, BIGSERIAL/SERIAL8=int8).
|
|
5804
5806
|
case "INTEGER":
|
|
5805
5807
|
case "INT":
|
|
5806
5808
|
case "SMALLINT":
|
|
@@ -5812,13 +5814,11 @@ function sqlTypeToMaterializeClass(sqlType) {
|
|
|
5812
5814
|
case "SERIAL4":
|
|
5813
5815
|
case "SMALLSERIAL":
|
|
5814
5816
|
case "SERIAL2":
|
|
5815
|
-
return "int32";
|
|
5816
|
-
// 64-bit int: needs JS bigint for exactness.
|
|
5817
5817
|
case "BIGINT":
|
|
5818
5818
|
case "INT8":
|
|
5819
5819
|
case "BIGSERIAL":
|
|
5820
5820
|
case "SERIAL8":
|
|
5821
|
-
return "
|
|
5821
|
+
return "int";
|
|
5822
5822
|
case "BOOLEAN":
|
|
5823
5823
|
case "BOOL":
|
|
5824
5824
|
return "bool";
|
|
@@ -5853,31 +5853,33 @@ function sqlTypeToMaterializeClass(sqlType) {
|
|
|
5853
5853
|
);
|
|
5854
5854
|
}
|
|
5855
5855
|
}
|
|
5856
|
+
var I64_MIN2 = -(2n ** 63n);
|
|
5857
|
+
var I64_MAX2 = 2n ** 63n - 1n;
|
|
5858
|
+
function checkI642(v) {
|
|
5859
|
+
if (v < I64_MIN2 || v > I64_MAX2) {
|
|
5860
|
+
throw new Error(`materialize int: ${v} is outside the i64 range behavior-contracts' \`int\` admits`);
|
|
5861
|
+
}
|
|
5862
|
+
return v;
|
|
5863
|
+
}
|
|
5856
5864
|
function materializeCell(value, klass) {
|
|
5857
5865
|
if (value === null || value === void 0) return value;
|
|
5858
5866
|
switch (klass) {
|
|
5859
|
-
case "
|
|
5860
|
-
if (typeof value === "bigint") return value
|
|
5867
|
+
case "int": {
|
|
5868
|
+
if (typeof value === "bigint") return checkI642(value);
|
|
5861
5869
|
if (typeof value === "string") {
|
|
5862
|
-
if (!/^-?\d+$/.test(value)) throw new Error(`materialize
|
|
5863
|
-
return value;
|
|
5870
|
+
if (!/^-?\d+$/.test(value)) throw new Error(`materialize int: driver returned a non-integer string '${value}'`);
|
|
5871
|
+
return checkI642(BigInt(value));
|
|
5864
5872
|
}
|
|
5865
5873
|
if (typeof value === "number") {
|
|
5866
|
-
if (!Number.isInteger(value)) throw new Error(`materialize
|
|
5874
|
+
if (!Number.isInteger(value)) throw new Error(`materialize int: driver returned a non-integer number ${value} for an integer column`);
|
|
5867
5875
|
if (!Number.isSafeInteger(value)) {
|
|
5868
5876
|
throw new Error(
|
|
5869
|
-
`materialize
|
|
5877
|
+
`materialize int: driver returned an UNSAFE JS number ${value} for an integer column \u2014 precision was already lost before materialization (the driver must return integers as bigint/string, not a rounded double). Configure the driver (better-sqlite3 safeIntegers / mysql2 supportBigNumbers+bigNumberStrings / pg int-as-bigint).`
|
|
5870
5878
|
);
|
|
5871
5879
|
}
|
|
5872
|
-
return value
|
|
5880
|
+
return BigInt(value);
|
|
5873
5881
|
}
|
|
5874
|
-
throw new Error(`materialize
|
|
5875
|
-
}
|
|
5876
|
-
case "int32": {
|
|
5877
|
-
if (typeof value === "number") return value;
|
|
5878
|
-
if (typeof value === "bigint") return Number(value);
|
|
5879
|
-
if (typeof value === "string" && /^-?\d+$/.test(value)) return Number(value);
|
|
5880
|
-
throw new Error(`materialize int32: unexpected driver JS type ${typeof value} (${String(value)})`);
|
|
5882
|
+
throw new Error(`materialize int: unexpected driver JS type ${typeof value}`);
|
|
5881
5883
|
}
|
|
5882
5884
|
case "date": {
|
|
5883
5885
|
if (typeof value === "string") return value;
|
|
@@ -6376,133 +6378,123 @@ function compileCreateManyBundle(name, options, dialectName = "sqlite", resolveC
|
|
|
6376
6378
|
var import_reflect_metadata = __toESM(require_Reflect());
|
|
6377
6379
|
var COLUMNS_KEY = /* @__PURE__ */ Symbol("litedbmodel:columns");
|
|
6378
6380
|
var RELATIONS_KEY = /* @__PURE__ */ Symbol("litedbmodel:relations");
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
return materializeCell(v, "date");
|
|
6397
|
-
},
|
|
6398
|
-
// Delegate to driver-specific serializeDatetime
|
|
6399
|
-
serialize: (val, typeCast) => {
|
|
6400
|
-
if (val === null || val === void 0) return null;
|
|
6401
|
-
if (val instanceof Date) {
|
|
6402
|
-
return typeCast?.serializeDatetime(val) ?? val;
|
|
6403
|
-
}
|
|
6404
|
-
return val;
|
|
6405
|
-
},
|
|
6406
|
-
sqlCast: "timestamp"
|
|
6407
|
-
};
|
|
6408
|
-
case Number:
|
|
6409
|
-
return {
|
|
6410
|
-
typeCast: (v) => {
|
|
6411
|
-
if (v === void 0) return void 0;
|
|
6412
|
-
if (v === null) return null;
|
|
6413
|
-
const n = Number(v);
|
|
6414
|
-
return isNaN(n) ? null : n;
|
|
6415
|
-
}
|
|
6416
|
-
};
|
|
6417
|
-
case BigInt:
|
|
6418
|
-
return {
|
|
6419
|
-
// v2 read contract: BIGINT/INT8 → EXACT decimal STRING (no i64 rounding, JSON-safe), via the
|
|
6420
|
-
// shared materializer. NOTE: the TS field type stays `bigint` in existing models for source
|
|
6421
|
-
// compat, but the VALUE is now the exact string — the whole point of the #9 realignment.
|
|
6422
|
-
typeCast: (v) => {
|
|
6423
|
-
if (v === void 0) return void 0;
|
|
6424
|
-
return materializeCell(v, "int64");
|
|
6425
|
-
},
|
|
6426
|
-
sqlCast: "bigint"
|
|
6427
|
-
};
|
|
6428
|
-
// Array, Object, String, and other types require explicit specification
|
|
6429
|
-
default:
|
|
6430
|
-
return void 0;
|
|
6381
|
+
if (typeof Symbol === "function" && !Symbol.metadata) {
|
|
6382
|
+
Object.defineProperty(Symbol, "metadata", {
|
|
6383
|
+
value: /* @__PURE__ */ Symbol.for("Symbol.metadata"),
|
|
6384
|
+
writable: false,
|
|
6385
|
+
enumerable: false,
|
|
6386
|
+
configurable: true
|
|
6387
|
+
});
|
|
6388
|
+
}
|
|
6389
|
+
function isStandardContext(second) {
|
|
6390
|
+
return typeof second === "object" && second !== null && typeof second.kind === "string";
|
|
6391
|
+
}
|
|
6392
|
+
function classMetadataBag(context, propertyKey) {
|
|
6393
|
+
const bag = context.metadata;
|
|
6394
|
+
if (bag === void 0) {
|
|
6395
|
+
throw new Error(
|
|
6396
|
+
`litedbmodel: the standard-decorator context for '${propertyKey}' carries no \`context.metadata\`. litedbmodel defines \`Symbol.metadata\` on import, which every current emit needs to create the bag \u2014 import litedbmodel (or 'litedbmodel/decorators') BEFORE the module that defines the model.`
|
|
6397
|
+
);
|
|
6431
6398
|
}
|
|
6399
|
+
return bag;
|
|
6432
6400
|
}
|
|
6433
|
-
function
|
|
6434
|
-
const
|
|
6435
|
-
if (
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
return "TIMESTAMP";
|
|
6445
|
-
case BigInt:
|
|
6446
|
-
return "BIGINT";
|
|
6447
|
-
default:
|
|
6448
|
-
return void 0;
|
|
6401
|
+
function legacyColumnMap(constructor) {
|
|
6402
|
+
const own = Reflect.getOwnMetadata(COLUMNS_KEY, constructor);
|
|
6403
|
+
if (own !== void 0) return own;
|
|
6404
|
+
const inherited = Reflect.getMetadata(COLUMNS_KEY, constructor);
|
|
6405
|
+
const map = new Map(inherited);
|
|
6406
|
+
Reflect.defineMetadata(COLUMNS_KEY, map, constructor);
|
|
6407
|
+
return map;
|
|
6408
|
+
}
|
|
6409
|
+
function standardColumnMap(bag) {
|
|
6410
|
+
if (!Object.prototype.hasOwnProperty.call(bag, COLUMNS_KEY)) {
|
|
6411
|
+
bag[COLUMNS_KEY] = new Map(bag[COLUMNS_KEY]);
|
|
6449
6412
|
}
|
|
6413
|
+
return bag[COLUMNS_KEY];
|
|
6450
6414
|
}
|
|
6451
|
-
function
|
|
6452
|
-
const
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
}
|
|
6415
|
+
function legacyRelationList(constructor) {
|
|
6416
|
+
const own = Reflect.getOwnMetadata(RELATIONS_KEY, constructor);
|
|
6417
|
+
if (own !== void 0) return own;
|
|
6418
|
+
const inherited = Reflect.getMetadata(RELATIONS_KEY, constructor);
|
|
6419
|
+
const list = inherited !== void 0 ? [...inherited] : [];
|
|
6420
|
+
Reflect.defineMetadata(RELATIONS_KEY, list, constructor);
|
|
6421
|
+
return list;
|
|
6422
|
+
}
|
|
6423
|
+
function standardRelationList(bag) {
|
|
6424
|
+
if (!Object.prototype.hasOwnProperty.call(bag, RELATIONS_KEY)) {
|
|
6425
|
+
const inherited = bag[RELATIONS_KEY];
|
|
6426
|
+
bag[RELATIONS_KEY] = inherited !== void 0 ? [...inherited] : [];
|
|
6464
6427
|
}
|
|
6465
|
-
|
|
6428
|
+
return bag[RELATIONS_KEY];
|
|
6429
|
+
}
|
|
6430
|
+
function registerColumn(columns, propertyKey, options) {
|
|
6466
6431
|
columns.set(propertyKey, {
|
|
6467
6432
|
columnName: options.columnName,
|
|
6468
|
-
typeCast:
|
|
6469
|
-
serialize:
|
|
6433
|
+
typeCast: options.typeCast,
|
|
6434
|
+
serialize: options.serialize,
|
|
6470
6435
|
primaryKey: options.primaryKey,
|
|
6471
6436
|
autoIncrement: options.autoIncrement,
|
|
6472
|
-
sqlCast:
|
|
6473
|
-
...baseSqlType !== void 0 ? { baseSqlType } : {}
|
|
6437
|
+
sqlCast: options.sqlCast,
|
|
6438
|
+
...options.baseSqlType !== void 0 ? { baseSqlType: options.baseSqlType } : {}
|
|
6474
6439
|
});
|
|
6475
|
-
Reflect.defineMetadata(COLUMNS_KEY, columns, constructor);
|
|
6476
6440
|
}
|
|
6477
|
-
function
|
|
6441
|
+
function parseColumnOptions(columnNameOrOptions, propKey) {
|
|
6442
|
+
if (typeof columnNameOrOptions === "string") return { columnName: columnNameOrOptions };
|
|
6443
|
+
if (columnNameOrOptions) {
|
|
6444
|
+
return {
|
|
6445
|
+
columnName: columnNameOrOptions.columnName || propKey,
|
|
6446
|
+
primaryKey: columnNameOrOptions.primaryKey,
|
|
6447
|
+
autoIncrement: columnNameOrOptions.autoIncrement
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6450
|
+
return { columnName: propKey };
|
|
6451
|
+
}
|
|
6452
|
+
function rejectNonText(family, val) {
|
|
6453
|
+
if (val === null || val === void 0) return null;
|
|
6454
|
+
if (val instanceof Date) {
|
|
6455
|
+
throw new Error(
|
|
6456
|
+
`litedbmodel: @column.${family}() received a Date. A text column cannot serialize one \u2014 the driver would store an object literal. Use @column.datetime() / @column.date() for a date column, or format the value yourself.`
|
|
6457
|
+
);
|
|
6458
|
+
}
|
|
6459
|
+
if (typeof val === "object") {
|
|
6460
|
+
throw new Error(
|
|
6461
|
+
`litedbmodel: @column.${family}() received an object. Use @column.json<T>() for a JSON column, or @column.custom() with a serializer.`
|
|
6462
|
+
);
|
|
6463
|
+
}
|
|
6464
|
+
return val;
|
|
6465
|
+
}
|
|
6466
|
+
function createColumnDecorator(typeCast, serialize, sqlCast, baseSqlType) {
|
|
6478
6467
|
return function(columnNameOrOptions) {
|
|
6479
|
-
return function(
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
} else {
|
|
6492
|
-
columnName = propKey;
|
|
6468
|
+
return function(targetOrValue, keyOrContext) {
|
|
6469
|
+
if (isStandardContext(keyOrContext)) {
|
|
6470
|
+
const propKey2 = String(keyOrContext.name);
|
|
6471
|
+
const parsed2 = parseColumnOptions(columnNameOrOptions, propKey2);
|
|
6472
|
+
registerColumn(standardColumnMap(classMetadataBag(keyOrContext, propKey2)), propKey2, {
|
|
6473
|
+
...parsed2,
|
|
6474
|
+
typeCast,
|
|
6475
|
+
serialize,
|
|
6476
|
+
sqlCast,
|
|
6477
|
+
baseSqlType
|
|
6478
|
+
});
|
|
6479
|
+
return;
|
|
6493
6480
|
}
|
|
6494
|
-
|
|
6495
|
-
|
|
6481
|
+
const propKey = String(keyOrContext);
|
|
6482
|
+
const parsed = parseColumnOptions(columnNameOrOptions, propKey);
|
|
6483
|
+
registerColumn(legacyColumnMap(targetOrValue.constructor), propKey, {
|
|
6484
|
+
...parsed,
|
|
6496
6485
|
typeCast,
|
|
6497
6486
|
serialize,
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
autoIncrement,
|
|
6501
|
-
sqlCast
|
|
6487
|
+
sqlCast,
|
|
6488
|
+
baseSqlType
|
|
6502
6489
|
});
|
|
6503
6490
|
};
|
|
6504
6491
|
};
|
|
6505
6492
|
}
|
|
6493
|
+
function requireColumnFamily() {
|
|
6494
|
+
throw new Error(
|
|
6495
|
+
"litedbmodel: `@column()` no longer declares a column \u2014 a column must state its type with a family: @column.text() / .number() / .boolean() / .bigint() / .datetime() / .date() / .uuid() / .json() / .stringArray() / .intArray() / .numericArray() / .booleanArray() / .datetimeArray() / .passthrough() / .custom(). Every family takes the same argument as `@column()` did (`@column.text('db_name')`, `@column.number({ primaryKey: true })`). The bare form inferred the type from `emitDecoratorMetadata`, which esbuild (tsx/vite/vitest) never emits and standard decorators do not have, so it silently produced untyped reads."
|
|
6496
|
+
);
|
|
6497
|
+
}
|
|
6506
6498
|
function serializeArray(val, typeCast) {
|
|
6507
6499
|
if (val === null || val === void 0) return null;
|
|
6508
6500
|
if (!Array.isArray(val)) return val;
|
|
@@ -6540,19 +6532,44 @@ function serializeJson(val, typeCast) {
|
|
|
6540
6532
|
return JSON.stringify(val);
|
|
6541
6533
|
}
|
|
6542
6534
|
var column = Object.assign(
|
|
6543
|
-
//
|
|
6544
|
-
|
|
6535
|
+
// The bare `@column()` declared no type — it is rejected, with the migration in the message.
|
|
6536
|
+
(_columnNameOrOptions) => requireColumnFamily(),
|
|
6545
6537
|
{
|
|
6546
6538
|
// ============================================
|
|
6547
6539
|
// Primitive Types
|
|
6548
6540
|
// ============================================
|
|
6541
|
+
/**
|
|
6542
|
+
* Text type (TEXT / VARCHAR / CHAR / ENUM / citext) — the driver value is already a string, so no
|
|
6543
|
+
* cast is applied. The family still DECLARES the column so the typed read types it as `TEXT`.
|
|
6544
|
+
* @example @column.text() name?: string;
|
|
6545
|
+
* @example @column.text('user_name') name?: string;
|
|
6546
|
+
*/
|
|
6547
|
+
text: (columnNameOrOptions) => createColumnDecorator(
|
|
6548
|
+
// The family DECLARES `string`, so it must hand back one. Most drivers already do, but SQLite
|
|
6549
|
+
// is dynamically typed: it returns a JS number for a `NUMERIC`/`DECIMAL` column whatever the
|
|
6550
|
+
// declaration says, and the declared type would be a lie on that dialect alone.
|
|
6551
|
+
(v) => {
|
|
6552
|
+
if (v === void 0 || v === null) return v;
|
|
6553
|
+
if (typeof v === "string") return v;
|
|
6554
|
+
if (typeof v === "number" || typeof v === "bigint" || typeof v === "boolean") return String(v);
|
|
6555
|
+
throw new Error(
|
|
6556
|
+
`materialize text: driver returned ${typeof v} for a text column. Use @column.passthrough() for a BYTEA/BLOB column, or @column.json<T>() for JSON.`
|
|
6557
|
+
);
|
|
6558
|
+
},
|
|
6559
|
+
(val) => rejectNonText("text", val),
|
|
6560
|
+
// …and it cannot SERIALIZE a Date or an object
|
|
6561
|
+
void 0,
|
|
6562
|
+
// no sqlCast family (a text literal needs no SQL cast)
|
|
6563
|
+
"TEXT"
|
|
6564
|
+
// §4.1 token: types the SCP typed read
|
|
6565
|
+
)(columnNameOrOptions),
|
|
6549
6566
|
/**
|
|
6550
6567
|
* Boolean type conversion
|
|
6551
6568
|
* Converts 't'/'f', 'true'/'false', 1/0 to boolean
|
|
6552
6569
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6553
6570
|
* @example @column.boolean() is_active?: boolean;
|
|
6554
6571
|
*/
|
|
6555
|
-
boolean: (
|
|
6572
|
+
boolean: (columnNameOrOptions) => createColumnDecorator(
|
|
6556
6573
|
// v2 read contract: BOOLEAN → boolean, via the shared materializer (issue #9).
|
|
6557
6574
|
(v) => {
|
|
6558
6575
|
if (v === void 0) return void 0;
|
|
@@ -6560,42 +6577,38 @@ var column = Object.assign(
|
|
|
6560
6577
|
},
|
|
6561
6578
|
void 0,
|
|
6562
6579
|
// no custom serialize
|
|
6563
|
-
false,
|
|
6564
|
-
// allow auto-inference
|
|
6565
6580
|
"boolean"
|
|
6566
6581
|
// sqlCast for updateMany type inference
|
|
6567
|
-
)(
|
|
6582
|
+
)(columnNameOrOptions),
|
|
6568
6583
|
/**
|
|
6569
6584
|
* Number type conversion (from string)
|
|
6570
6585
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6571
6586
|
* @example @column.number() amount?: number;
|
|
6572
6587
|
*/
|
|
6573
|
-
number: (
|
|
6588
|
+
number: (columnNameOrOptions) => createColumnDecorator((v) => {
|
|
6574
6589
|
if (v === void 0) return void 0;
|
|
6575
6590
|
if (v === null) return null;
|
|
6576
6591
|
const n = Number(v);
|
|
6577
6592
|
return isNaN(n) ? null : n;
|
|
6578
|
-
})(
|
|
6593
|
+
})(columnNameOrOptions),
|
|
6579
6594
|
/**
|
|
6580
6595
|
* BigInt type conversion
|
|
6581
6596
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6582
|
-
* @example @column.bigint() large_id?: bigint;
|
|
6597
|
+
* @example @column.bigint() large_id?: bigint; // bc `int` — a JS bigint, checked i64
|
|
6583
6598
|
*/
|
|
6584
|
-
bigint: (
|
|
6585
|
-
//
|
|
6586
|
-
//
|
|
6587
|
-
//
|
|
6599
|
+
bigint: (columnNameOrOptions) => createColumnDecorator(
|
|
6600
|
+
// An integer column reads back as a JS `bigint` — behavior-contracts' `int` value model
|
|
6601
|
+
// (`int` = bigint, checked i64), which is what the drivers already hand over. `JSON.stringify`
|
|
6602
|
+
// does not serialize a bigint: give the field a `toJSON`, or convert at the boundary.
|
|
6588
6603
|
(v) => {
|
|
6589
6604
|
if (v === void 0) return void 0;
|
|
6590
|
-
return materializeCell(v, "
|
|
6605
|
+
return materializeCell(v, "int");
|
|
6591
6606
|
},
|
|
6592
6607
|
void 0,
|
|
6593
6608
|
// no custom serialize
|
|
6594
|
-
false,
|
|
6595
|
-
// allow auto-inference
|
|
6596
6609
|
"bigint"
|
|
6597
6610
|
// sqlCast for WHERE/INSERT type casting
|
|
6598
|
-
)(
|
|
6611
|
+
)(columnNameOrOptions),
|
|
6599
6612
|
// ============================================
|
|
6600
6613
|
// Date/Time Types
|
|
6601
6614
|
// ============================================
|
|
@@ -6607,9 +6620,9 @@ var column = Object.assign(
|
|
|
6607
6620
|
* - PostgreSQL: Serializes to ISO 8601 UTC string with 'Z' suffix for explicit timezone
|
|
6608
6621
|
* - MySQL/SQLite: Passes Date object to driver (driver-dependent timezone handling)
|
|
6609
6622
|
*
|
|
6610
|
-
* @example @column.datetime() created_at?: Date
|
|
6623
|
+
* @example @column.datetime() created_at?: string; // TZ-attached string, NOT a JS Date
|
|
6611
6624
|
*/
|
|
6612
|
-
datetime: (
|
|
6625
|
+
datetime: (columnNameOrOptions) => createColumnDecorator(
|
|
6613
6626
|
// v2 read contract: DATE/TIMESTAMP/TIMESTAMPTZ/DATETIME/TIME → TZ-attached STRING (NOT a
|
|
6614
6627
|
// TZ-shifted JS Date), via the shared materializer (issue #9). A driver already returning the
|
|
6615
6628
|
// native textual form passes through; a JS Date is rendered to its lossless ISO instant.
|
|
@@ -6625,11 +6638,9 @@ var column = Object.assign(
|
|
|
6625
6638
|
}
|
|
6626
6639
|
return val;
|
|
6627
6640
|
},
|
|
6628
|
-
false,
|
|
6629
|
-
// allow auto-inference
|
|
6630
6641
|
"timestamp"
|
|
6631
6642
|
// sqlCast for updateMany type inference
|
|
6632
|
-
)(
|
|
6643
|
+
)(columnNameOrOptions),
|
|
6633
6644
|
/**
|
|
6634
6645
|
* Date type conversion — returns YYYY-MM-DD string.
|
|
6635
6646
|
* Preserves null for nullable columns, undefined stays undefined.
|
|
@@ -6637,9 +6648,9 @@ var column = Object.assign(
|
|
|
6637
6648
|
* DB values (Date object or string) are normalized to 'YYYY-MM-DD' string.
|
|
6638
6649
|
* On write, string values are passed through; Date objects are formatted as 'YYYY-MM-DD'.
|
|
6639
6650
|
*
|
|
6640
|
-
* @example @column.date() birth_date?: string;
|
|
6651
|
+
* @example @column.date() birth_date?: string; // 'YYYY-MM-DD'
|
|
6641
6652
|
*/
|
|
6642
|
-
date: (
|
|
6653
|
+
date: (columnNameOrOptions) => createColumnDecorator(
|
|
6643
6654
|
(v) => {
|
|
6644
6655
|
if (v === void 0) return void 0;
|
|
6645
6656
|
if (v === null) return null;
|
|
@@ -6664,11 +6675,9 @@ var column = Object.assign(
|
|
|
6664
6675
|
}
|
|
6665
6676
|
return val;
|
|
6666
6677
|
},
|
|
6667
|
-
false,
|
|
6668
|
-
// allow auto-inference
|
|
6669
6678
|
"date"
|
|
6670
6679
|
// sqlCast for updateMany type inference
|
|
6671
|
-
)(
|
|
6680
|
+
)(columnNameOrOptions),
|
|
6672
6681
|
// ============================================
|
|
6673
6682
|
// Array Types
|
|
6674
6683
|
// ============================================
|
|
@@ -6677,71 +6686,71 @@ var column = Object.assign(
|
|
|
6677
6686
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6678
6687
|
* @example @column.stringArray() tags?: string[];
|
|
6679
6688
|
*/
|
|
6680
|
-
stringArray: (
|
|
6689
|
+
stringArray: (columnNameOrOptions) => createColumnDecorator(
|
|
6681
6690
|
(v) => {
|
|
6682
6691
|
if (v === void 0) return void 0;
|
|
6683
6692
|
if (v === null) return null;
|
|
6684
6693
|
return castToStringArray(v);
|
|
6685
6694
|
},
|
|
6686
6695
|
serializeArray,
|
|
6687
|
-
false,
|
|
6688
6696
|
"text[]"
|
|
6689
|
-
)(
|
|
6697
|
+
)(columnNameOrOptions),
|
|
6690
6698
|
/**
|
|
6691
6699
|
* Integer array type conversion (integer[])
|
|
6692
6700
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6693
6701
|
* @example @column.intArray() scores?: number[];
|
|
6694
6702
|
*/
|
|
6695
|
-
intArray: (
|
|
6703
|
+
intArray: (columnNameOrOptions) => createColumnDecorator(
|
|
6696
6704
|
(v) => {
|
|
6697
6705
|
if (v === void 0) return void 0;
|
|
6698
6706
|
if (v === null) return null;
|
|
6699
6707
|
return castToIntegerArray(v);
|
|
6700
6708
|
},
|
|
6701
6709
|
serializeArray,
|
|
6702
|
-
false,
|
|
6703
6710
|
"int[]"
|
|
6704
|
-
)(
|
|
6711
|
+
)(columnNameOrOptions),
|
|
6705
6712
|
/**
|
|
6706
6713
|
* Numeric array type conversion (numeric[], allows null elements)
|
|
6707
6714
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6708
6715
|
* @example @column.numericArray() values?: (number | null)[];
|
|
6709
6716
|
*/
|
|
6710
|
-
numericArray: (
|
|
6717
|
+
numericArray: (columnNameOrOptions) => createColumnDecorator(
|
|
6711
6718
|
(v) => {
|
|
6712
6719
|
if (v === void 0) return void 0;
|
|
6713
6720
|
if (v === null) return null;
|
|
6714
6721
|
return castToNumericArray(v);
|
|
6715
6722
|
},
|
|
6716
6723
|
serializeArray,
|
|
6717
|
-
false,
|
|
6718
6724
|
"numeric[]"
|
|
6719
|
-
)(
|
|
6725
|
+
)(columnNameOrOptions),
|
|
6720
6726
|
/**
|
|
6721
6727
|
* Boolean array type conversion (boolean[])
|
|
6722
6728
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6723
6729
|
* @example @column.booleanArray() flags?: (boolean | null)[];
|
|
6724
6730
|
*/
|
|
6725
|
-
booleanArray: (
|
|
6731
|
+
booleanArray: (columnNameOrOptions) => createColumnDecorator(
|
|
6726
6732
|
(v) => {
|
|
6727
6733
|
if (v === void 0) return void 0;
|
|
6728
6734
|
if (v === null) return null;
|
|
6729
6735
|
return castToBooleanArray(v);
|
|
6730
6736
|
},
|
|
6731
6737
|
serializeBooleanArray,
|
|
6732
|
-
false,
|
|
6733
6738
|
"boolean[]"
|
|
6734
|
-
)(
|
|
6739
|
+
)(columnNameOrOptions),
|
|
6735
6740
|
/**
|
|
6736
6741
|
* DateTime array type conversion (timestamp[])
|
|
6737
6742
|
* Preserves null for nullable columns, undefined stays undefined
|
|
6738
|
-
* @example @column.datetimeArray() event_dates?: (
|
|
6743
|
+
* @example @column.datetimeArray() event_dates?: (string | null)[];
|
|
6739
6744
|
*/
|
|
6740
|
-
datetimeArray: (
|
|
6745
|
+
datetimeArray: (columnNameOrOptions) => createColumnDecorator(
|
|
6746
|
+
// Element-wise the SAME contract as `@column.datetime()`: a TZ-attached STRING, never a
|
|
6747
|
+
// TZ-shifted JS Date. The array family used to be the one place a `Date` still came back, so
|
|
6748
|
+
// `JSON.stringify` of a row silently re-rendered those elements in UTC — the exact hazard #9
|
|
6749
|
+
// closed for the scalar.
|
|
6741
6750
|
(v) => {
|
|
6742
6751
|
if (v === void 0) return void 0;
|
|
6743
6752
|
if (v === null) return null;
|
|
6744
|
-
return castToDatetimeArray(v);
|
|
6753
|
+
return castToDatetimeArray(v).map((d) => d === null ? null : materializeCell(d, "date"));
|
|
6745
6754
|
},
|
|
6746
6755
|
// DateTime arrays serialize each Date to ISO string
|
|
6747
6756
|
(val) => {
|
|
@@ -6750,7 +6759,7 @@ var column = Object.assign(
|
|
|
6750
6759
|
const mapped = val.map((v) => v === null ? "NULL" : v instanceof Date ? v.toISOString() : String(v));
|
|
6751
6760
|
return `{${mapped.join(",")}}`;
|
|
6752
6761
|
}
|
|
6753
|
-
)(
|
|
6762
|
+
)(columnNameOrOptions),
|
|
6754
6763
|
// ============================================
|
|
6755
6764
|
// JSON Types
|
|
6756
6765
|
// ============================================
|
|
@@ -6760,16 +6769,15 @@ var column = Object.assign(
|
|
|
6760
6769
|
* @example @column.json() metadata?: Record<string, unknown>;
|
|
6761
6770
|
* @example @column.json<UserSettings>() settings?: UserSettings;
|
|
6762
6771
|
*/
|
|
6763
|
-
json: (
|
|
6772
|
+
json: (columnNameOrOptions) => createColumnDecorator(
|
|
6764
6773
|
(v) => {
|
|
6765
6774
|
if (v === void 0) return void 0;
|
|
6766
6775
|
if (v === null) return null;
|
|
6767
6776
|
return castToJson(v);
|
|
6768
6777
|
},
|
|
6769
6778
|
serializeJson,
|
|
6770
|
-
false,
|
|
6771
6779
|
"jsonb"
|
|
6772
|
-
)(
|
|
6780
|
+
)(columnNameOrOptions),
|
|
6773
6781
|
// ============================================
|
|
6774
6782
|
// UUID Type (PostgreSQL)
|
|
6775
6783
|
// ============================================
|
|
@@ -6798,61 +6806,101 @@ var column = Object.assign(
|
|
|
6798
6806
|
if (v === null) return null;
|
|
6799
6807
|
return String(v);
|
|
6800
6808
|
},
|
|
6801
|
-
|
|
6802
|
-
//
|
|
6803
|
-
true,
|
|
6804
|
-
// Skip auto-inference
|
|
6809
|
+
(val) => rejectNonText("uuid", val),
|
|
6810
|
+
// the ::uuid cast handles the rest
|
|
6805
6811
|
"uuid"
|
|
6806
6812
|
// SQL type for casting
|
|
6807
6813
|
)(columnNameOrOptions),
|
|
6808
6814
|
// ============================================
|
|
6809
6815
|
// Custom Type Conversion
|
|
6810
6816
|
// ============================================
|
|
6817
|
+
/**
|
|
6818
|
+
* The driver's value, UNCAST — for a column whose type the library has no cast for (`BYTEA` /
|
|
6819
|
+
* `BLOB` arrives as a driver Buffer, a vendor type as whatever the driver decodes). It states
|
|
6820
|
+
* "this column is passed through", which is a DECLARATION; the removed bare `@column()` was the
|
|
6821
|
+
* absence of one, and produced this same passthrough by accident for every unresolvable type.
|
|
6822
|
+
* @example @column.passthrough() payload?: unknown;
|
|
6823
|
+
*/
|
|
6824
|
+
passthrough: (columnNameOrOptions) => createColumnDecorator()(columnNameOrOptions),
|
|
6811
6825
|
/**
|
|
6812
6826
|
* Custom type conversion with user-provided function
|
|
6813
6827
|
* @example @column.custom((v) => String(v).toUpperCase()) status?: string;
|
|
6814
6828
|
* @example @column.custom((v) => v, (v) => JSON.stringify(v)) data?: MyType; // with serializer
|
|
6815
6829
|
*/
|
|
6816
|
-
custom: (castFn, serializeFn,
|
|
6830
|
+
custom: (castFn, serializeFn, columnNameOrOptions) => createColumnDecorator(castFn, serializeFn)(columnNameOrOptions)
|
|
6817
6831
|
}
|
|
6818
6832
|
);
|
|
6819
|
-
function registerRelation(
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6833
|
+
function registerRelation(relations, propertyKey, type, keysFactory, options) {
|
|
6834
|
+
relations.push({ propertyKey, type, keysFactory, options });
|
|
6835
|
+
}
|
|
6836
|
+
function createRelationDecorator(type, keys, options) {
|
|
6837
|
+
return function(targetOrValue, keyOrContext) {
|
|
6838
|
+
if (isStandardContext(keyOrContext)) {
|
|
6839
|
+
const propKey2 = String(keyOrContext.name);
|
|
6840
|
+
registerRelation(standardRelationList(classMetadataBag(keyOrContext, propKey2)), propKey2, type, keys, options);
|
|
6841
|
+
if (typeof keyOrContext.addInitializer !== "function") {
|
|
6842
|
+
throw new Error(
|
|
6843
|
+
`litedbmodel: the standard-decorator context for relation '${propKey2}' has no \`addInitializer\`, so the class field cannot be removed and would shadow the relation getter.`
|
|
6844
|
+
);
|
|
6845
|
+
}
|
|
6846
|
+
keyOrContext.addInitializer(function() {
|
|
6847
|
+
if (Object.prototype.hasOwnProperty.call(this, propKey2)) {
|
|
6848
|
+
delete this[propKey2];
|
|
6849
|
+
}
|
|
6850
|
+
});
|
|
6851
|
+
return;
|
|
6852
|
+
}
|
|
6853
|
+
const propKey = String(keyOrContext);
|
|
6854
|
+
registerRelation(legacyRelationList(targetOrValue.constructor), propKey, type, keys, options);
|
|
6855
|
+
};
|
|
6829
6856
|
}
|
|
6830
6857
|
function hasMany(keys, options) {
|
|
6831
|
-
return
|
|
6832
|
-
registerRelation(target, String(propertyKey), "hasMany", keys, options);
|
|
6833
|
-
};
|
|
6858
|
+
return createRelationDecorator("hasMany", keys, options);
|
|
6834
6859
|
}
|
|
6835
6860
|
function belongsTo(keys, options) {
|
|
6836
|
-
return
|
|
6837
|
-
registerRelation(target, String(propertyKey), "belongsTo", keys, options);
|
|
6838
|
-
};
|
|
6861
|
+
return createRelationDecorator("belongsTo", keys, options);
|
|
6839
6862
|
}
|
|
6840
6863
|
function hasOne(keys, options) {
|
|
6841
|
-
return
|
|
6842
|
-
registerRelation(target, String(propertyKey), "hasOne", keys, options);
|
|
6843
|
-
};
|
|
6864
|
+
return createRelationDecorator("hasOne", keys, options);
|
|
6844
6865
|
}
|
|
6845
6866
|
function getRelationMeta(modelClass) {
|
|
6846
6867
|
return modelClass._relationMeta || Reflect.getMetadata(RELATIONS_KEY, modelClass) || [];
|
|
6847
6868
|
}
|
|
6848
|
-
function model(tableNameOrConstructor,
|
|
6869
|
+
function model(tableNameOrConstructor, optionsOrContext) {
|
|
6849
6870
|
if (typeof tableNameOrConstructor === "string") {
|
|
6850
6871
|
const tableName = tableNameOrConstructor;
|
|
6851
|
-
|
|
6852
|
-
|
|
6872
|
+
const options = optionsOrContext;
|
|
6873
|
+
return function(constructor, context) {
|
|
6874
|
+
return applyToClass(constructor, context, tableName, options);
|
|
6875
|
+
};
|
|
6876
|
+
}
|
|
6877
|
+
return applyToClass(tableNameOrConstructor, optionsOrContext);
|
|
6878
|
+
}
|
|
6879
|
+
function applyToClass(constructor, context, tableName, options) {
|
|
6880
|
+
const members = modelMembers(constructor, context);
|
|
6881
|
+
if (!isStandardContext(context)) return applyModelDecorator(constructor, members, tableName, options);
|
|
6882
|
+
if (typeof context.addInitializer !== "function") {
|
|
6883
|
+
throw new Error(
|
|
6884
|
+
`litedbmodel: the standard-decorator context for '${constructor.name}' has no \`addInitializer\`, so \`@model\` cannot assemble the model after the class is defined.`
|
|
6885
|
+
);
|
|
6886
|
+
}
|
|
6887
|
+
context.addInitializer(function() {
|
|
6888
|
+
applyModelDecorator(this, members, tableName, options);
|
|
6889
|
+
});
|
|
6890
|
+
return constructor;
|
|
6891
|
+
}
|
|
6892
|
+
function modelMembers(constructor, context) {
|
|
6893
|
+
if (isStandardContext(context)) {
|
|
6894
|
+
const bag = classMetadataBag(context, String(constructor.name ?? "model"));
|
|
6895
|
+
return {
|
|
6896
|
+
columns: bag[COLUMNS_KEY] ?? /* @__PURE__ */ new Map(),
|
|
6897
|
+
relations: bag[RELATIONS_KEY] ?? []
|
|
6853
6898
|
};
|
|
6854
6899
|
}
|
|
6855
|
-
return
|
|
6900
|
+
return {
|
|
6901
|
+
columns: Reflect.getMetadata(COLUMNS_KEY, constructor) ?? /* @__PURE__ */ new Map(),
|
|
6902
|
+
relations: Reflect.getMetadata(RELATIONS_KEY, constructor) ?? []
|
|
6903
|
+
};
|
|
6856
6904
|
}
|
|
6857
6905
|
function isCompositeKeys(keys) {
|
|
6858
6906
|
return Array.isArray(keys[0]);
|
|
@@ -6872,9 +6920,8 @@ function parseKeys(keys) {
|
|
|
6872
6920
|
};
|
|
6873
6921
|
}
|
|
6874
6922
|
}
|
|
6875
|
-
function applyModelDecorator(constructor, tableName, options) {
|
|
6876
|
-
const columns
|
|
6877
|
-
const relations = Reflect.getMetadata(RELATIONS_KEY, constructor) || [];
|
|
6923
|
+
function applyModelDecorator(constructor, members, tableName, options) {
|
|
6924
|
+
const { columns, relations } = members;
|
|
6878
6925
|
const modelName = constructor.name;
|
|
6879
6926
|
if (tableName) {
|
|
6880
6927
|
Object.defineProperty(constructor, "TABLE_NAME", {
|
|
@@ -6992,6 +7039,26 @@ function applyModelDecorator(constructor, tableName, options) {
|
|
|
6992
7039
|
relationName: propertyKey
|
|
6993
7040
|
});
|
|
6994
7041
|
},
|
|
7042
|
+
/**
|
|
7043
|
+
* A relation is a getter, but a class FIELD declaring it still writes to the property. Which
|
|
7044
|
+
* write it is depends on `useDefineForClassFields`: with define semantics (the default from
|
|
7045
|
+
* target ES2022) the field is `defineProperty`-d onto the instance, bypassing this setter — the
|
|
7046
|
+
* standard protocol's initializer removes that shadowing property. With SET semantics (the
|
|
7047
|
+
* default below ES2022) the field ASSIGNS, and an accessor with no setter throws
|
|
7048
|
+
* `Cannot set property … which has only a getter` on EVERY instantiation.
|
|
7049
|
+
*
|
|
7050
|
+
* So: the field's own `undefined` is ignored, and any other value is honoured as an own
|
|
7051
|
+
* property — priming a relation (a loaded graph, a test double) reads back what was set.
|
|
7052
|
+
*/
|
|
7053
|
+
set: function(value) {
|
|
7054
|
+
if (value === void 0) return;
|
|
7055
|
+
Object.defineProperty(this, propertyKey, {
|
|
7056
|
+
value,
|
|
7057
|
+
writable: true,
|
|
7058
|
+
enumerable: true,
|
|
7059
|
+
configurable: true
|
|
7060
|
+
});
|
|
7061
|
+
},
|
|
6995
7062
|
enumerable: true,
|
|
6996
7063
|
configurable: false
|
|
6997
7064
|
});
|
|
@@ -8054,8 +8121,8 @@ var DBModel = class _DBModel {
|
|
|
8054
8121
|
* ```typescript
|
|
8055
8122
|
* @model('users')
|
|
8056
8123
|
* class UserModel extends DBModel {
|
|
8057
|
-
* @column() id?: number;
|
|
8058
|
-
* @column() name?: string;
|
|
8124
|
+
* @column.number() id?: number;
|
|
8125
|
+
* @column.text() name?: string;
|
|
8059
8126
|
* }
|
|
8060
8127
|
* export const User = UserModel.asModel();
|
|
8061
8128
|
* export type User = UserModel;
|
|
@@ -8187,15 +8254,14 @@ var DBModel = class _DBModel {
|
|
|
8187
8254
|
static _scpColumnTypesCache = /* @__PURE__ */ new WeakMap();
|
|
8188
8255
|
/**
|
|
8189
8256
|
* The §4.1 column-type OVERRIDES for the SCP read/write bundle (the F1 `columnTypes` escape hatch).
|
|
8190
|
-
*
|
|
8191
|
-
*
|
|
8192
|
-
*
|
|
8193
|
-
* otherwise take the blanket-INTEGER default and THROW `materialize int32` on a live string. Because
|
|
8257
|
+
* A column whose SQL type cannot be derived from its family — `@column.number()`, whose JS `number`
|
|
8258
|
+
* backs an INTEGER just as well as a REAL/DECIMAL (pg returns DECIMAL as a string that an `int32`
|
|
8259
|
+
* materialize REJECTS) — would otherwise take the blanket-INTEGER default and THROW. Because
|
|
8194
8260
|
* the DBModel read path does its OWN v1 de-box (`_createInstance` → `typeCastFromDB`), the SCP typed
|
|
8195
8261
|
* read only needs a NON-THROWING, passthrough-safe SQL type for such columns: we pin them to `TEXT`
|
|
8196
8262
|
* (passthrough — the driver value flows through unchanged, then v1 casts it). Columns WITH a derivable
|
|
8197
|
-
* type (
|
|
8198
|
-
*
|
|
8263
|
+
* type (every family but `@column.number()`) keep it. This preserves the v1 read contract exactly
|
|
8264
|
+
* (int→number, string→string) while never throwing on a column whose width the model did not state.
|
|
8199
8265
|
* @internal
|
|
8200
8266
|
*/
|
|
8201
8267
|
static _scpColumnTypes() {
|
|
@@ -8207,7 +8273,7 @@ var DBModel = class _DBModel {
|
|
|
8207
8273
|
for (const [propKey, m] of meta) {
|
|
8208
8274
|
const baseSqlType = m.baseSqlType;
|
|
8209
8275
|
if (m.sqlCast !== void 0) continue;
|
|
8210
|
-
if (baseSqlType !== void 0
|
|
8276
|
+
if (baseSqlType !== void 0) continue;
|
|
8211
8277
|
columnTypes[propKey] = "TEXT";
|
|
8212
8278
|
}
|
|
8213
8279
|
}
|
|
@@ -10426,12 +10492,12 @@ var DBModel = class _DBModel {
|
|
|
10426
10492
|
* // Define models using appropriate base class
|
|
10427
10493
|
* @model('users')
|
|
10428
10494
|
* class UserModel extends BaseDB {
|
|
10429
|
-
* @column() id?: number;
|
|
10495
|
+
* @column.number() id?: number;
|
|
10430
10496
|
* }
|
|
10431
10497
|
*
|
|
10432
10498
|
* @model('articles')
|
|
10433
10499
|
* class ArticleModel extends CmsDB {
|
|
10434
|
-
* @column() id?: number;
|
|
10500
|
+
* @column.number() id?: number;
|
|
10435
10501
|
* }
|
|
10436
10502
|
*
|
|
10437
10503
|
* // Each base class has independent transactions
|