@objectstack/objectql 9.10.0 → 9.11.0
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.d.mts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +48 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.d.mts
CHANGED
|
@@ -2225,15 +2225,22 @@ declare class ObjectQL implements IDataEngine {
|
|
|
2225
2225
|
* owns the value, not the client.
|
|
2226
2226
|
*
|
|
2227
2227
|
* In the fallback path the next value is `max(existing) + 1`, seeded once per
|
|
2228
|
-
* `object.field
|
|
2229
|
-
* the process, resilient to deletions). `autonumberFormat`
|
|
2230
|
-
*
|
|
2228
|
+
* `object.field.<scope>` from the store then incremented in memory (monotonic
|
|
2229
|
+
* within the process, resilient to deletions). The shared `autonumberFormat`
|
|
2230
|
+
* renderer is honored end-to-end, so date tokens (`AD{YYYYMMDD}{0000}`), field
|
|
2231
|
+
* interpolation (`{island_zone}{000}`) and per-scope reset behave identically
|
|
2232
|
+
* to the SQL driver's persistent sequence (#1603). NOTE: this in-memory seeding
|
|
2233
|
+
* is single-instance.
|
|
2231
2234
|
*/
|
|
2232
2235
|
private applyAutonumbers;
|
|
2233
|
-
/**
|
|
2236
|
+
/**
|
|
2237
|
+
* Seed the autonumber counter from the current max in store, scoped to
|
|
2238
|
+
* `prefix`. With a non-empty prefix (date/field formats) only rows in the
|
|
2239
|
+
* same scope count, and the counter is the digit-run immediately after the
|
|
2240
|
+
* prefix; with an empty prefix (legacy fixed-prefix formats) the last digit
|
|
2241
|
+
* run of the whole value is used, preserving the original behaviour.
|
|
2242
|
+
*/
|
|
2234
2243
|
private seedAutonumber;
|
|
2235
|
-
/** Apply an autonumber format like `CASE-{0000}`; default to the bare number. */
|
|
2236
|
-
private formatAutonumber;
|
|
2237
2244
|
/**
|
|
2238
2245
|
* Register contribution (Manifest)
|
|
2239
2246
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -2225,15 +2225,22 @@ declare class ObjectQL implements IDataEngine {
|
|
|
2225
2225
|
* owns the value, not the client.
|
|
2226
2226
|
*
|
|
2227
2227
|
* In the fallback path the next value is `max(existing) + 1`, seeded once per
|
|
2228
|
-
* `object.field
|
|
2229
|
-
* the process, resilient to deletions). `autonumberFormat`
|
|
2230
|
-
*
|
|
2228
|
+
* `object.field.<scope>` from the store then incremented in memory (monotonic
|
|
2229
|
+
* within the process, resilient to deletions). The shared `autonumberFormat`
|
|
2230
|
+
* renderer is honored end-to-end, so date tokens (`AD{YYYYMMDD}{0000}`), field
|
|
2231
|
+
* interpolation (`{island_zone}{000}`) and per-scope reset behave identically
|
|
2232
|
+
* to the SQL driver's persistent sequence (#1603). NOTE: this in-memory seeding
|
|
2233
|
+
* is single-instance.
|
|
2231
2234
|
*/
|
|
2232
2235
|
private applyAutonumbers;
|
|
2233
|
-
/**
|
|
2236
|
+
/**
|
|
2237
|
+
* Seed the autonumber counter from the current max in store, scoped to
|
|
2238
|
+
* `prefix`. With a non-empty prefix (date/field formats) only rows in the
|
|
2239
|
+
* same scope count, and the counter is the digit-run immediately after the
|
|
2240
|
+
* prefix; with an empty prefix (legacy fixed-prefix formats) the last digit
|
|
2241
|
+
* run of the whole value is used, preserving the original behaviour.
|
|
2242
|
+
*/
|
|
2234
2243
|
private seedAutonumber;
|
|
2235
|
-
/** Apply an autonumber format like `CASE-{0000}`; default to the bare number. */
|
|
2236
|
-
private formatAutonumber;
|
|
2237
2244
|
/**
|
|
2238
2245
|
* Register contribution (Manifest)
|
|
2239
2246
|
*
|
package/dist/index.js
CHANGED
|
@@ -6192,6 +6192,7 @@ var ObjectStackProtocolImplementation = _ObjectStackProtocolImplementation;
|
|
|
6192
6192
|
|
|
6193
6193
|
// src/engine.ts
|
|
6194
6194
|
var import_node_async_hooks = require("async_hooks");
|
|
6195
|
+
var import_data4 = require("@objectstack/spec/data");
|
|
6195
6196
|
var import_kernel6 = require("@objectstack/spec/kernel");
|
|
6196
6197
|
var import_core2 = require("@objectstack/core");
|
|
6197
6198
|
var import_system2 = require("@objectstack/spec/system");
|
|
@@ -7617,8 +7618,9 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7617
7618
|
const tx = execCtx?.transaction !== void 0 ? execCtx.transaction : this.txStore.getStore()?.transaction;
|
|
7618
7619
|
const hasTx = tx !== void 0;
|
|
7619
7620
|
const hasTenant = execCtx?.tenantId !== void 0;
|
|
7621
|
+
const hasTz = execCtx?.timezone !== void 0;
|
|
7620
7622
|
const isSystem = execCtx?.isSystem === true;
|
|
7621
|
-
if (!hasTx && !hasTenant && !isSystem) return base;
|
|
7623
|
+
if (!hasTx && !hasTenant && !isSystem && !hasTz) return base;
|
|
7622
7624
|
const opts = base && typeof base === "object" ? { ...base } : {};
|
|
7623
7625
|
if (hasTx && opts.transaction === void 0) {
|
|
7624
7626
|
opts.transaction = tx;
|
|
@@ -7626,6 +7628,9 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7626
7628
|
if (hasTenant && opts.tenantId === void 0) {
|
|
7627
7629
|
opts.tenantId = execCtx.tenantId;
|
|
7628
7630
|
}
|
|
7631
|
+
if (hasTz && opts.timezone === void 0) {
|
|
7632
|
+
opts.timezone = execCtx.timezone;
|
|
7633
|
+
}
|
|
7629
7634
|
if (isSystem && opts.bypassTenantAudit === void 0) {
|
|
7630
7635
|
opts.bypassTenantAudit = true;
|
|
7631
7636
|
}
|
|
@@ -7699,29 +7704,48 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7699
7704
|
* owns the value, not the client.
|
|
7700
7705
|
*
|
|
7701
7706
|
* In the fallback path the next value is `max(existing) + 1`, seeded once per
|
|
7702
|
-
* `object.field
|
|
7703
|
-
* the process, resilient to deletions). `autonumberFormat`
|
|
7704
|
-
*
|
|
7707
|
+
* `object.field.<scope>` from the store then incremented in memory (monotonic
|
|
7708
|
+
* within the process, resilient to deletions). The shared `autonumberFormat`
|
|
7709
|
+
* renderer is honored end-to-end, so date tokens (`AD{YYYYMMDD}{0000}`), field
|
|
7710
|
+
* interpolation (`{island_zone}{000}`) and per-scope reset behave identically
|
|
7711
|
+
* to the SQL driver's persistent sequence (#1603). NOTE: this in-memory seeding
|
|
7712
|
+
* is single-instance.
|
|
7705
7713
|
*/
|
|
7706
7714
|
async applyAutonumbers(object, record, execCtx, driverOwnsAutonumber) {
|
|
7707
7715
|
if (driverOwnsAutonumber) return;
|
|
7708
7716
|
const fields = this.getSchema(object)?.fields;
|
|
7709
7717
|
if (!fields || typeof fields !== "object" || Array.isArray(fields)) return;
|
|
7718
|
+
const now = /* @__PURE__ */ new Date();
|
|
7719
|
+
const timezone = execCtx?.timezone;
|
|
7710
7720
|
for (const [name, def] of Object.entries(fields)) {
|
|
7711
7721
|
if (def?.type !== "autonumber") continue;
|
|
7712
7722
|
const current = record[name];
|
|
7713
7723
|
if (current != null && current !== "") continue;
|
|
7714
|
-
const key = `${object}.${name}`;
|
|
7715
|
-
let next = this.autonumberCounters.get(key);
|
|
7716
|
-
if (next == null) next = await this.seedAutonumber(object, name, execCtx);
|
|
7717
|
-
next += 1;
|
|
7718
|
-
this.autonumberCounters.set(key, next);
|
|
7719
7724
|
const fmt = def.autonumberFormat ?? def.format;
|
|
7720
|
-
|
|
7725
|
+
const tokens = (0, import_data4.parseAutonumberFormat)(typeof fmt === "string" ? fmt : "");
|
|
7726
|
+
const missing = (0, import_data4.missingFieldValues)(tokens, record);
|
|
7727
|
+
if (missing.length > 0) {
|
|
7728
|
+
throw new Error(
|
|
7729
|
+
`Cannot generate autonumber "${object}.${name}" (format "${fmt}"): referenced field(s) [${missing.join(", ")}] are empty on the record. Fields interpolated into an autonumber format must be set before the record is created.`
|
|
7730
|
+
);
|
|
7731
|
+
}
|
|
7732
|
+
const probe = (0, import_data4.renderAutonumber)({ tokens, seq: 0, record, now, timezone });
|
|
7733
|
+
const counterKey = `${object}.${name}.${probe.scope}`;
|
|
7734
|
+
let next = this.autonumberCounters.get(counterKey);
|
|
7735
|
+
if (next == null) next = await this.seedAutonumber(object, name, probe.prefix, execCtx);
|
|
7736
|
+
next += 1;
|
|
7737
|
+
this.autonumberCounters.set(counterKey, next);
|
|
7738
|
+
record[name] = (0, import_data4.renderAutonumber)({ tokens, seq: next, record, now, timezone }).value;
|
|
7721
7739
|
}
|
|
7722
7740
|
}
|
|
7723
|
-
/**
|
|
7724
|
-
|
|
7741
|
+
/**
|
|
7742
|
+
* Seed the autonumber counter from the current max in store, scoped to
|
|
7743
|
+
* `prefix`. With a non-empty prefix (date/field formats) only rows in the
|
|
7744
|
+
* same scope count, and the counter is the digit-run immediately after the
|
|
7745
|
+
* prefix; with an empty prefix (legacy fixed-prefix formats) the last digit
|
|
7746
|
+
* run of the whole value is used, preserving the original behaviour.
|
|
7747
|
+
*/
|
|
7748
|
+
async seedAutonumber(object, field, prefix, execCtx) {
|
|
7725
7749
|
try {
|
|
7726
7750
|
const rows = await this.find(object, {
|
|
7727
7751
|
select: ["id", field],
|
|
@@ -7732,22 +7756,24 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7732
7756
|
for (const r of rows || []) {
|
|
7733
7757
|
const v = r?.[field];
|
|
7734
7758
|
if (v == null) continue;
|
|
7735
|
-
const
|
|
7736
|
-
if (
|
|
7759
|
+
const s = String(v);
|
|
7760
|
+
if (prefix && !s.startsWith(prefix)) continue;
|
|
7761
|
+
const tail = prefix ? s.slice(prefix.length) : s;
|
|
7762
|
+
let digits;
|
|
7763
|
+
if (prefix) {
|
|
7764
|
+
const head = tail.match(/^\d+/);
|
|
7765
|
+
digits = head ? head[0] : void 0;
|
|
7766
|
+
} else {
|
|
7767
|
+
const runs = tail.match(/\d+/g);
|
|
7768
|
+
digits = runs ? runs[runs.length - 1] : void 0;
|
|
7769
|
+
}
|
|
7770
|
+
if (digits) max = Math.max(max, parseInt(digits, 10) || 0);
|
|
7737
7771
|
}
|
|
7738
7772
|
return max;
|
|
7739
7773
|
} catch {
|
|
7740
7774
|
return 0;
|
|
7741
7775
|
}
|
|
7742
7776
|
}
|
|
7743
|
-
/** Apply an autonumber format like `CASE-{0000}`; default to the bare number. */
|
|
7744
|
-
formatAutonumber(format, value) {
|
|
7745
|
-
if (!format) return String(value);
|
|
7746
|
-
const m = format.match(/\{(0+)\}/);
|
|
7747
|
-
if (!m) return format.includes("{0}") ? format.replace("{0}", String(value)) : `${format}${value}`;
|
|
7748
|
-
const padded = String(value).padStart(m[1].length, "0");
|
|
7749
|
-
return format.replace(m[0], padded);
|
|
7750
|
-
}
|
|
7751
7777
|
/**
|
|
7752
7778
|
* Register contribution (Manifest)
|
|
7753
7779
|
*
|