velocious 1.0.515 → 1.0.516
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 +3 -3
- package/build/background-jobs/cron-expression.js +9 -9
- package/build/background-jobs/forked-runner-child.js +1 -1
- package/build/background-jobs/job-runner.js +21 -15
- package/build/background-jobs/json-socket.js +4 -0
- package/build/background-jobs/main.js +180 -18
- package/build/background-jobs/status-reporter.js +12 -5
- package/build/background-jobs/store.js +132 -50
- package/build/background-jobs/types.js +11 -3
- package/build/background-jobs/worker.js +9 -5
- package/build/beacon/client.js +13 -6
- package/build/configuration.js +31 -29
- package/build/controller.js +9 -3
- package/build/database/drivers/sqlite/base.js +1 -1
- package/build/database/drivers/sqlite/index.js +15 -14
- package/build/database/migrations-ledger.js +16 -16
- package/build/database/query/where-model-class-hash.js +2 -0
- package/build/database/query/with-count.js +1 -1
- package/build/database/record/acts-as-list.js +2 -2
- package/build/database/record/auditing.js +23 -6
- package/build/database/record/index.js +7 -7
- package/build/database/record/validators/uniqueness.js +3 -3
- package/build/database/tenants/data-copier.js +23 -23
- package/build/database/tenants/schema-cloner.js +27 -27
- package/build/environment-handlers/browser.js +0 -1
- package/build/environment-handlers/node/cli/commands/background-jobs-runner.js +2 -1
- package/build/environment-handlers/node/cli/commands/lint/relationships.js +2 -2
- package/build/environment-handlers/node.js +1 -1
- package/build/frontend-model-controller.js +26 -18
- package/build/frontend-models/base.js +5 -5
- package/build/frontend-models/query.js +12 -12
- package/build/http-server/client/index.js +61 -15
- package/build/http-server/client/response.js +17 -1
- package/build/http-server/client/websocket-session.js +13 -13
- package/build/http-server/server-client.js +96 -0
- package/build/http-server/websocket-channel.js +12 -11
- package/build/http-server/websocket-connection.js +12 -11
- package/build/http-server/websocket-events-host.js +1 -1
- package/build/http-server/worker-handler/in-process.js +48 -9
- package/build/http-server/worker-handler/index.js +67 -7
- package/build/http-server/worker-handler/worker-thread.js +68 -0
- package/build/src/background-jobs/cron-expression.d.ts +2 -2
- package/build/src/background-jobs/cron-expression.js +10 -10
- package/build/src/background-jobs/forked-runner-child.js +2 -2
- package/build/src/background-jobs/job-runner.d.ts +5 -1
- package/build/src/background-jobs/job-runner.d.ts.map +1 -1
- package/build/src/background-jobs/job-runner.js +22 -16
- package/build/src/background-jobs/json-socket.d.ts +4 -0
- package/build/src/background-jobs/json-socket.d.ts.map +1 -1
- package/build/src/background-jobs/json-socket.js +5 -1
- package/build/src/background-jobs/main.d.ts +62 -10
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +171 -19
- package/build/src/background-jobs/status-reporter.d.ts +6 -2
- package/build/src/background-jobs/status-reporter.d.ts.map +1 -1
- package/build/src/background-jobs/status-reporter.js +13 -6
- package/build/src/background-jobs/store.d.ts +48 -25
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +123 -50
- package/build/src/background-jobs/types.d.ts +36 -3
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +12 -4
- package/build/src/background-jobs/worker.d.ts +7 -5
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +10 -6
- package/build/src/beacon/client.d.ts +6 -3
- package/build/src/beacon/client.d.ts.map +1 -1
- package/build/src/beacon/client.js +14 -7
- package/build/src/configuration-types.d.ts +1 -1
- package/build/src/configuration.d.ts +31 -29
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +32 -30
- package/build/src/controller.d.ts +3 -0
- package/build/src/controller.d.ts.map +1 -1
- package/build/src/controller.js +9 -4
- package/build/src/database/drivers/sqlite/base.js +2 -2
- package/build/src/database/drivers/sqlite/index.d.ts +7 -6
- package/build/src/database/drivers/sqlite/index.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.js +16 -15
- package/build/src/database/migrations-ledger.d.ts +16 -16
- package/build/src/database/migrations-ledger.js +17 -17
- package/build/src/database/query/where-model-class-hash.d.ts.map +1 -1
- package/build/src/database/query/where-model-class-hash.js +3 -1
- package/build/src/database/query/with-count.js +2 -2
- package/build/src/database/record/acts-as-list.js +3 -3
- package/build/src/database/record/auditing.d.ts +1 -1
- package/build/src/database/record/auditing.d.ts.map +1 -1
- package/build/src/database/record/auditing.js +24 -7
- package/build/src/database/record/index.d.ts +7 -7
- package/build/src/database/record/index.js +8 -8
- package/build/src/database/record/validators/uniqueness.d.ts +3 -3
- package/build/src/database/record/validators/uniqueness.js +4 -4
- package/build/src/database/tenants/data-copier.d.ts +18 -18
- package/build/src/database/tenants/data-copier.js +24 -24
- package/build/src/database/tenants/schema-cloner.d.ts +27 -27
- package/build/src/database/tenants/schema-cloner.js +28 -28
- package/build/src/environment-handlers/browser.d.ts +9 -0
- package/build/src/environment-handlers/browser.d.ts.map +1 -1
- package/build/src/environment-handlers/browser.js +1 -2
- package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +3 -2
- package/build/src/environment-handlers/node/cli/commands/lint/relationships.js +3 -3
- package/build/src/environment-handlers/node.js +2 -2
- package/build/src/frontend-model-controller.d.ts +9 -8
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +26 -19
- package/build/src/frontend-models/base.d.ts +4 -4
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +6 -6
- package/build/src/frontend-models/query.d.ts +7 -7
- package/build/src/frontend-models/query.js +13 -13
- package/build/src/http-server/client/index.d.ts +23 -1
- package/build/src/http-server/client/index.d.ts.map +1 -1
- package/build/src/http-server/client/index.js +55 -17
- package/build/src/http-server/client/response.d.ts +11 -1
- package/build/src/http-server/client/response.d.ts.map +1 -1
- package/build/src/http-server/client/response.js +16 -2
- package/build/src/http-server/client/websocket-session.d.ts +13 -13
- package/build/src/http-server/client/websocket-session.js +14 -14
- package/build/src/http-server/server-client.d.ts +13 -0
- package/build/src/http-server/server-client.d.ts.map +1 -1
- package/build/src/http-server/server-client.js +94 -1
- package/build/src/http-server/websocket-channel.d.ts +12 -11
- package/build/src/http-server/websocket-channel.d.ts.map +1 -1
- package/build/src/http-server/websocket-channel.js +13 -12
- package/build/src/http-server/websocket-connection.d.ts +12 -11
- package/build/src/http-server/websocket-connection.d.ts.map +1 -1
- package/build/src/http-server/websocket-connection.js +13 -12
- package/build/src/http-server/websocket-events-host.d.ts +1 -1
- package/build/src/http-server/websocket-events-host.js +2 -2
- package/build/src/http-server/worker-handler/in-process.d.ts +2 -0
- package/build/src/http-server/worker-handler/in-process.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/in-process.js +42 -11
- package/build/src/http-server/worker-handler/index.d.ts +21 -0
- package/build/src/http-server/worker-handler/index.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/index.js +61 -7
- package/build/src/http-server/worker-handler/worker-thread.d.ts +30 -0
- package/build/src/http-server/worker-handler/worker-thread.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/worker-thread.js +61 -1
- package/build/src/sync/device-identity.d.ts +2 -2
- package/build/src/sync/device-identity.d.ts.map +1 -1
- package/build/src/sync/device-identity.js +4 -4
- package/build/src/sync/local-mutation-log.d.ts +0 -1
- package/build/src/sync/local-mutation-log.d.ts.map +1 -1
- package/build/src/sync/local-mutation-log.js +1 -2
- package/build/src/tenants/tenant-iterator.d.ts +8 -8
- package/build/src/tenants/tenant-iterator.js +9 -9
- package/build/src/tenants/tenant.d.ts +6 -6
- package/build/src/tenants/tenant.js +7 -7
- package/build/sync/device-identity.js +3 -3
- package/build/sync/local-mutation-log.js +0 -1
- package/build/tenants/tenant-iterator.js +8 -8
- package/build/tenants/tenant.js +6 -6
- package/package.json +2 -2
- package/src/background-jobs/cron-expression.js +9 -9
- package/src/background-jobs/forked-runner-child.js +1 -1
- package/src/background-jobs/job-runner.js +21 -15
- package/src/background-jobs/json-socket.js +4 -0
- package/src/background-jobs/main.js +180 -18
- package/src/background-jobs/status-reporter.js +12 -5
- package/src/background-jobs/store.js +132 -50
- package/src/background-jobs/types.js +11 -3
- package/src/background-jobs/worker.js +9 -5
- package/src/beacon/client.js +13 -6
- package/src/configuration.js +31 -29
- package/src/controller.js +9 -3
- package/src/database/drivers/sqlite/base.js +1 -1
- package/src/database/drivers/sqlite/index.js +15 -14
- package/src/database/migrations-ledger.js +16 -16
- package/src/database/query/where-model-class-hash.js +2 -0
- package/src/database/query/with-count.js +1 -1
- package/src/database/record/acts-as-list.js +2 -2
- package/src/database/record/auditing.js +23 -6
- package/src/database/record/index.js +7 -7
- package/src/database/record/validators/uniqueness.js +3 -3
- package/src/database/tenants/data-copier.js +23 -23
- package/src/database/tenants/schema-cloner.js +27 -27
- package/src/environment-handlers/browser.js +0 -1
- package/src/environment-handlers/node/cli/commands/background-jobs-runner.js +2 -1
- package/src/environment-handlers/node/cli/commands/lint/relationships.js +2 -2
- package/src/environment-handlers/node.js +1 -1
- package/src/frontend-model-controller.js +26 -18
- package/src/frontend-models/base.js +5 -5
- package/src/frontend-models/query.js +12 -12
- package/src/http-server/client/index.js +61 -15
- package/src/http-server/client/response.js +17 -1
- package/src/http-server/client/websocket-session.js +13 -13
- package/src/http-server/server-client.js +96 -0
- package/src/http-server/websocket-channel.js +12 -11
- package/src/http-server/websocket-connection.js +12 -11
- package/src/http-server/websocket-events-host.js +1 -1
- package/src/http-server/worker-handler/in-process.js +48 -9
- package/src/http-server/worker-handler/index.js +67 -7
- package/src/http-server/worker-handler/worker-thread.js +68 -0
- package/src/sync/device-identity.js +3 -3
- package/src/sync/local-mutation-log.js +0 -1
- package/src/tenants/tenant-iterator.js +8 -8
- package/src/tenants/tenant.js +6 -6
|
@@ -74,9 +74,9 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
74
74
|
* `new Task({project})`, the FK (`projectId`) is only flushed onto
|
|
75
75
|
* the attribute store during save — but the relationship object is
|
|
76
76
|
* already loaded and carries the id we need for the WHERE clause.
|
|
77
|
-
* @param {import("../index.js").default} model
|
|
77
|
+
* @param {import("../index.js").default} model - Record whose loaded relationship may supply the scope value.
|
|
78
78
|
* @param {string} scopeColumn - camelCase attribute name (e.g. `"projectId"`).
|
|
79
|
-
* @returns {string | number | null}
|
|
79
|
+
* @returns {string | number | null} - Value normalized for comparison.
|
|
80
80
|
*/
|
|
81
81
|
_resolveScopeValueFromRelationship(model, scopeColumn) {
|
|
82
82
|
const modelClass = /** @type {typeof import("../index.js").default} */ (model.constructor)
|
|
@@ -106,7 +106,7 @@ export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
|
|
|
106
106
|
* Normalize the `scope` option into an array of attribute names.
|
|
107
107
|
* Supports string (`"userId"`), array of strings (`["userId", "projectId"]`),
|
|
108
108
|
* or absent (empty array — no scope, original single-column behavior).
|
|
109
|
-
* @returns {string[]}
|
|
109
|
+
* @returns {string[]} - Columns participating in the uniqueness check.
|
|
110
110
|
*/
|
|
111
111
|
_normalizeScopeColumns() {
|
|
112
112
|
const scope = this.args?.scope
|
|
@@ -6,9 +6,9 @@ const DEFAULT_QUERY_CHUNK_SIZE = 500
|
|
|
6
6
|
/**
|
|
7
7
|
* Splits an array into chunks of at most `chunkSize` items.
|
|
8
8
|
* @template T
|
|
9
|
-
* @param {T[]} values
|
|
10
|
-
* @param {number} chunkSize
|
|
11
|
-
* @returns {T[][]}
|
|
9
|
+
* @param {T[]} values - Ordered items to partition.
|
|
10
|
+
* @param {number} chunkSize - Maximum items per chunk.
|
|
11
|
+
* @returns {T[][]} - Consecutive chunks preserving input order.
|
|
12
12
|
*/
|
|
13
13
|
function chunks(values, chunkSize) {
|
|
14
14
|
const chunkedValues = []
|
|
@@ -22,8 +22,8 @@ function chunks(values, chunkSize) {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Stringifies values and returns the distinct, non-blank ones, preserving first-seen order.
|
|
25
|
-
* @param {unknown[]} values
|
|
26
|
-
* @returns {string[]}
|
|
25
|
+
* @param {unknown[]} values - Candidate database identifiers to stringify and deduplicate.
|
|
26
|
+
* @returns {string[]} - Distinct non-blank identifiers in first-seen order.
|
|
27
27
|
*/
|
|
28
28
|
function uniqueStrings(values) {
|
|
29
29
|
return Array.from(new Set(values.map((value) => String(value)).filter((value) => value.trim())))
|
|
@@ -60,7 +60,7 @@ export default class DataCopier {
|
|
|
60
60
|
* insertChunkSize?: number,
|
|
61
61
|
* queryChunkSize?: number,
|
|
62
62
|
* onProgress?: (message: string) => void
|
|
63
|
-
* }} args
|
|
63
|
+
* }} args - Source, target, traversal plan, chunk limits, and progress handler.
|
|
64
64
|
*/
|
|
65
65
|
constructor({sourceDb, targetDb, tablePlan, idColumn = "id", insertChunkSize = DEFAULT_INSERT_CHUNK_SIZE, queryChunkSize = DEFAULT_QUERY_CHUNK_SIZE, onProgress}) {
|
|
66
66
|
this.sourceDb = sourceDb
|
|
@@ -77,8 +77,8 @@ export default class DataCopier {
|
|
|
77
77
|
* returns the copied source rows keyed by table name. The target's current tenant rows
|
|
78
78
|
* are deleted (children first) and the source rows inserted (parents first) in a single
|
|
79
79
|
* target transaction with foreign keys disabled.
|
|
80
|
-
* @param {string} keyValue
|
|
81
|
-
* @returns {Promise<Map<string, Record<string, unknown>[]>>}
|
|
80
|
+
* @param {string} keyValue - Tenant key selecting the rows to copy.
|
|
81
|
+
* @returns {Promise<Map<string, Record<string, unknown>[]>>} - Copied source rows grouped by table name.
|
|
82
82
|
*/
|
|
83
83
|
async copy(keyValue) {
|
|
84
84
|
const sourceRowsByTableName = await this.loadRows(this.sourceDb, keyValue)
|
|
@@ -125,9 +125,9 @@ export default class DataCopier {
|
|
|
125
125
|
* Loads the rows for `keyValue` for every table in the plan from `db`, resolving
|
|
126
126
|
* parent-scoped tables from the ids already selected for their parent table. Used for
|
|
127
127
|
* both the source rows to copy and the target's current tenant rows to delete.
|
|
128
|
-
* @param {import("../drivers/base.js").default} db
|
|
129
|
-
* @param {string} keyValue
|
|
130
|
-
* @returns {Promise<Map<string, Record<string, unknown>[]>>}
|
|
128
|
+
* @param {import("../drivers/base.js").default} db - Source or target database to traverse.
|
|
129
|
+
* @param {string} keyValue - Tenant key selecting the root plan rows.
|
|
130
|
+
* @returns {Promise<Map<string, Record<string, unknown>[]>>} - Loaded rows grouped by table name.
|
|
131
131
|
*/
|
|
132
132
|
async loadRows(db, keyValue) {
|
|
133
133
|
/** @type {Map<string, string[]>} */
|
|
@@ -175,8 +175,8 @@ export default class DataCopier {
|
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
177
|
* Selects all rows of `tableName` in `db` whose `columnName` is in `values`, chunked.
|
|
178
|
-
* @param {{columnName: string, db: import("../drivers/base.js").default, tableName: string, values: string[]}} args
|
|
179
|
-
* @returns {Promise<Record<string, unknown>[]>}
|
|
178
|
+
* @param {{columnName: string, db: import("../drivers/base.js").default, tableName: string, values: string[]}} args - Table, column, database, and values for the chunked lookup.
|
|
179
|
+
* @returns {Promise<Record<string, unknown>[]>} - Rows matching the supplied column values.
|
|
180
180
|
*/
|
|
181
181
|
async queryRowsByColumn({columnName, db, tableName, values}) {
|
|
182
182
|
const normalizedValues = uniqueStrings(values)
|
|
@@ -201,7 +201,7 @@ export default class DataCopier {
|
|
|
201
201
|
/**
|
|
202
202
|
* Deletes the matching target rows for every plan table, children before parents, so the
|
|
203
203
|
* reinsert that follows starts from a clean slate without violating foreign keys.
|
|
204
|
-
* @param {Map<string, Record<string, unknown>[]>} rowsByTableName
|
|
204
|
+
* @param {Map<string, Record<string, unknown>[]>} rowsByTableName - Rows grouped by table name.
|
|
205
205
|
* @returns {Promise<void>}
|
|
206
206
|
*/
|
|
207
207
|
async deleteTargetRows(rowsByTableName) {
|
|
@@ -227,7 +227,7 @@ export default class DataCopier {
|
|
|
227
227
|
/**
|
|
228
228
|
* Inserts the loaded source rows into the target for every plan table, parents before
|
|
229
229
|
* children, chunked to bound statement size.
|
|
230
|
-
* @param {Map<string, Record<string, unknown>[]>} rowsByTableName
|
|
230
|
+
* @param {Map<string, Record<string, unknown>[]>} rowsByTableName - Rows grouped by table name.
|
|
231
231
|
* @returns {Promise<void>}
|
|
232
232
|
*/
|
|
233
233
|
async insertTargetRows(rowsByTableName) {
|
|
@@ -256,9 +256,9 @@ export default class DataCopier {
|
|
|
256
256
|
|
|
257
257
|
/**
|
|
258
258
|
* Quotes and comma-joins values for an SQL `IN (...)` list against the given database.
|
|
259
|
-
* @param {import("../drivers/base.js").default} db
|
|
260
|
-
* @param {string[]} values
|
|
261
|
-
* @returns {string}
|
|
259
|
+
* @param {import("../drivers/base.js").default} db - Database whose quoting rules format the values.
|
|
260
|
+
* @param {string[]} values - Values to quote for the `IN` list.
|
|
261
|
+
* @returns {string} - Quoted SQL value list.
|
|
262
262
|
*/
|
|
263
263
|
quotedValuesSql(db, values) {
|
|
264
264
|
return values.map((value) => db.quote(value)).join(", ")
|
|
@@ -266,9 +266,9 @@ export default class DataCopier {
|
|
|
266
266
|
|
|
267
267
|
/**
|
|
268
268
|
* Runs a query without per-query logging, used for the high-volume copy statements.
|
|
269
|
-
* @param {import("../drivers/base.js").default} db
|
|
270
|
-
* @param {string} sql
|
|
271
|
-
* @returns {Promise<Record<string, unknown>[]>}
|
|
269
|
+
* @param {import("../drivers/base.js").default} db - Database on which to execute the copy query.
|
|
270
|
+
* @param {string} sql - Copy-related SQL statement to execute quietly.
|
|
271
|
+
* @returns {Promise<Record<string, unknown>[]>} - Query result rows.
|
|
272
272
|
*/
|
|
273
273
|
async executeQuietQuery(db, sql) {
|
|
274
274
|
return await db.query(sql, {logQuery: false})
|
|
@@ -276,7 +276,7 @@ export default class DataCopier {
|
|
|
276
276
|
|
|
277
277
|
/**
|
|
278
278
|
* Inserts column-aligned row tuples into a table without per-query logging.
|
|
279
|
-
* @param {{columns: string[], db: import("../drivers/base.js").default, rows: Array<Array<unknown>>, tableName: string}} args
|
|
279
|
+
* @param {{columns: string[], db: import("../drivers/base.js").default, rows: Array<Array<unknown>>, tableName: string}} args - Destination table and column-aligned row values to insert.
|
|
280
280
|
* @returns {Promise<void>}
|
|
281
281
|
*/
|
|
282
282
|
async insertRowsQuietly({columns, db, rows, tableName}) {
|
|
@@ -285,7 +285,7 @@ export default class DataCopier {
|
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* Forwards a progress message to the optional `onProgress` callback when one was given.
|
|
288
|
-
* @param {string} message
|
|
288
|
+
* @param {string} message - Copy progress message to forward when reporting is enabled.
|
|
289
289
|
* @returns {void}
|
|
290
290
|
*/
|
|
291
291
|
reportProgress(message) {
|
|
@@ -31,7 +31,7 @@ const TEXT_TYPE_RANKS = {
|
|
|
31
31
|
export default class SchemaCloner {
|
|
32
32
|
/**
|
|
33
33
|
* Creates a cloner that copies table structure from `sourceDb` into `targetDb`.
|
|
34
|
-
* @param {{sourceDb: import("../drivers/base.js").default, targetDb: import("../drivers/base.js").default}} args
|
|
34
|
+
* @param {{sourceDb: import("../drivers/base.js").default, targetDb: import("../drivers/base.js").default}} args - Databases to clone structure from and into.
|
|
35
35
|
*/
|
|
36
36
|
constructor({sourceDb, targetDb}) {
|
|
37
37
|
this.sourceDb = sourceDb
|
|
@@ -41,7 +41,7 @@ export default class SchemaCloner {
|
|
|
41
41
|
/**
|
|
42
42
|
* Clones every given table from the source into the target, then baselines the
|
|
43
43
|
* target's ledger so the cloned schema is recorded as already-migrated.
|
|
44
|
-
* @param {string[]} tableNames
|
|
44
|
+
* @param {string[]} tableNames - Source tables whose structure should be cloned.
|
|
45
45
|
* @returns {Promise<void>}
|
|
46
46
|
*/
|
|
47
47
|
async syncTables(tableNames) {
|
|
@@ -55,7 +55,7 @@ export default class SchemaCloner {
|
|
|
55
55
|
/**
|
|
56
56
|
* Clones a single table from the source into the target, creating it or adding and
|
|
57
57
|
* widening columns and indexes as needed.
|
|
58
|
-
* @param {string} tableName
|
|
58
|
+
* @param {string} tableName - Source table to synchronize with the target.
|
|
59
59
|
* @returns {Promise<void>}
|
|
60
60
|
*/
|
|
61
61
|
async syncTable(tableName) {
|
|
@@ -82,7 +82,7 @@ export default class SchemaCloner {
|
|
|
82
82
|
/**
|
|
83
83
|
* Creates the table in the target from the source table's columns and its
|
|
84
84
|
* non-primary-key indexes.
|
|
85
|
-
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args
|
|
85
|
+
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args - Source table metadata and target table name.
|
|
86
86
|
* @returns {Promise<void>}
|
|
87
87
|
*/
|
|
88
88
|
async createTargetTable({sourceTable, tableName}) {
|
|
@@ -105,7 +105,7 @@ export default class SchemaCloner {
|
|
|
105
105
|
/**
|
|
106
106
|
* Adds columns present on the source but missing from the target, and widens
|
|
107
107
|
* too-narrow target text columns.
|
|
108
|
-
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args
|
|
108
|
+
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args - Source table metadata and target table name.
|
|
109
109
|
* @returns {Promise<boolean>} Whether any column was added or widened.
|
|
110
110
|
*/
|
|
111
111
|
async ensureTargetColumns({sourceTable, tableName}) {
|
|
@@ -154,7 +154,7 @@ export default class SchemaCloner {
|
|
|
154
154
|
* Creates non-primary-key indexes present on the source but missing from the target,
|
|
155
155
|
* and replaces target indexes whose definition (columns or uniqueness) drifted from
|
|
156
156
|
* the source.
|
|
157
|
-
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args
|
|
157
|
+
* @param {{sourceTable: import("../drivers/base-table.js").default, tableName: string}} args - Source table metadata and target table name.
|
|
158
158
|
* @returns {Promise<void>}
|
|
159
159
|
*/
|
|
160
160
|
async ensureTargetIndexes({sourceTable, tableName}) {
|
|
@@ -230,7 +230,7 @@ export default class SchemaCloner {
|
|
|
230
230
|
|
|
231
231
|
/**
|
|
232
232
|
* Drops an index on the target database.
|
|
233
|
-
* @param {{tableName: string, targetIndex: import("../drivers/base-columns-index.js").default}} args
|
|
233
|
+
* @param {{tableName: string, targetIndex: import("../drivers/base-columns-index.js").default}} args - Target table and index to remove.
|
|
234
234
|
* @returns {Promise<void>}
|
|
235
235
|
*/
|
|
236
236
|
async dropTargetIndex({tableName, targetIndex}) {
|
|
@@ -252,7 +252,7 @@ export default class SchemaCloner {
|
|
|
252
252
|
/**
|
|
253
253
|
* Whether the target ledger is missing any version applied on the source — i.e. the
|
|
254
254
|
* target schema may have been advanced out of band without recording it.
|
|
255
|
-
* @returns {Promise<boolean>}
|
|
255
|
+
* @returns {Promise<boolean>} - Whether the target ledger differs from the source.
|
|
256
256
|
*/
|
|
257
257
|
async ledgerDriftsFromSource() {
|
|
258
258
|
if (!await MigrationsLedger.tableExists(this.targetDb)) {
|
|
@@ -268,8 +268,8 @@ export default class SchemaCloner {
|
|
|
268
268
|
/**
|
|
269
269
|
* Maps a source index into a TableData index for table creation (SQLite omits the
|
|
270
270
|
* index name so the driver can generate a unique one).
|
|
271
|
-
* @param {import("../drivers/base-columns-index.js").default} sourceIndex
|
|
272
|
-
* @returns {TableIndex}
|
|
271
|
+
* @param {import("../drivers/base-columns-index.js").default} sourceIndex - Source index definition.
|
|
272
|
+
* @returns {TableIndex} - Framework-independent index definition.
|
|
273
273
|
*/
|
|
274
274
|
tableDataIndexFromSourceIndex(sourceIndex) {
|
|
275
275
|
/** @type {{name?: string, unique: boolean}} */
|
|
@@ -289,8 +289,8 @@ export default class SchemaCloner {
|
|
|
289
289
|
/**
|
|
290
290
|
* Builds driver create-index args from a source index (the index name is omitted on
|
|
291
291
|
* SQLite, where index names are unique per-database rather than per-table).
|
|
292
|
-
* @param {{sourceIndex: import("../drivers/base-columns-index.js").default, tableName: string}} args
|
|
293
|
-
* @returns {{columns: string[], name?: string, tableName: string, unique: boolean}}
|
|
292
|
+
* @param {{sourceIndex: import("../drivers/base-columns-index.js").default, tableName: string}} args - Source index and target table receiving it.
|
|
293
|
+
* @returns {{columns: string[], name?: string, tableName: string, unique: boolean}} - Arguments for creating the target index.
|
|
294
294
|
*/
|
|
295
295
|
createIndexArgsFromSourceIndex({sourceIndex, tableName}) {
|
|
296
296
|
/** @type {{columns: string[], name?: string, tableName: string, unique: boolean}} */
|
|
@@ -309,9 +309,9 @@ export default class SchemaCloner {
|
|
|
309
309
|
|
|
310
310
|
/**
|
|
311
311
|
* Whether two indexes have the same uniqueness and ordered column list.
|
|
312
|
-
* @param {import("../drivers/base-columns-index.js").default} sourceIndex
|
|
313
|
-
* @param {import("../drivers/base-columns-index.js").default} targetIndex
|
|
314
|
-
* @returns {boolean}
|
|
312
|
+
* @param {import("../drivers/base-columns-index.js").default} sourceIndex - Source index definition.
|
|
313
|
+
* @param {import("../drivers/base-columns-index.js").default} targetIndex - Target index definition.
|
|
314
|
+
* @returns {boolean} - Whether both indexes have the same shape.
|
|
315
315
|
*/
|
|
316
316
|
indexesMatch(sourceIndex, targetIndex) {
|
|
317
317
|
const sourceColumnNames = sourceIndex.getColumnNames()
|
|
@@ -336,8 +336,8 @@ export default class SchemaCloner {
|
|
|
336
336
|
|
|
337
337
|
/**
|
|
338
338
|
* A stable signature for an index, used to match cloned indexes by shape.
|
|
339
|
-
* @param {import("../drivers/base-columns-index.js").default} index
|
|
340
|
-
* @returns {string}
|
|
339
|
+
* @param {import("../drivers/base-columns-index.js").default} index - Index definition.
|
|
340
|
+
* @returns {string} - Stable index-shape signature.
|
|
341
341
|
*/
|
|
342
342
|
indexSignature(index) {
|
|
343
343
|
return `${index.isUnique() ? "unique" : "index"}:${index.getColumnNames().join(",")}`
|
|
@@ -345,8 +345,8 @@ export default class SchemaCloner {
|
|
|
345
345
|
|
|
346
346
|
/**
|
|
347
347
|
* Normalizes a column type to its canonical lowercase form (`int` becomes `integer`).
|
|
348
|
-
* @param {string} columnType
|
|
349
|
-
* @returns {string}
|
|
348
|
+
* @param {string} columnType - Database column type.
|
|
349
|
+
* @returns {string} - Canonical lowercase column type.
|
|
350
350
|
*/
|
|
351
351
|
normalizedColumnType(columnType) {
|
|
352
352
|
const normalizedType = columnType.toLowerCase()
|
|
@@ -360,8 +360,8 @@ export default class SchemaCloner {
|
|
|
360
360
|
|
|
361
361
|
/**
|
|
362
362
|
* The widening rank of a text column type (0 when not a text type).
|
|
363
|
-
* @param {string} columnType
|
|
364
|
-
* @returns {number}
|
|
363
|
+
* @param {string} columnType - Database column type.
|
|
364
|
+
* @returns {number} - Text-type widening rank.
|
|
365
365
|
*/
|
|
366
366
|
textTypeRank(columnType) {
|
|
367
367
|
return TEXT_TYPE_RANKS[this.normalizedColumnType(columnType)] || 0
|
|
@@ -369,9 +369,9 @@ export default class SchemaCloner {
|
|
|
369
369
|
|
|
370
370
|
/**
|
|
371
371
|
* Whether the target's text column is narrower than the source's and must be widened.
|
|
372
|
-
* @param {import("../drivers/base-column.js").default} sourceColumn
|
|
373
|
-
* @param {import("../drivers/base-column.js").default} targetColumn
|
|
374
|
-
* @returns {boolean}
|
|
372
|
+
* @param {import("../drivers/base-column.js").default} sourceColumn - Source column definition.
|
|
373
|
+
* @param {import("../drivers/base-column.js").default} targetColumn - Target column definition.
|
|
374
|
+
* @returns {boolean} - Whether the target text column must be widened.
|
|
375
375
|
*/
|
|
376
376
|
columnNeedsWidening(sourceColumn, targetColumn) {
|
|
377
377
|
const sourceRank = this.textTypeRank(sourceColumn.getType())
|
|
@@ -383,9 +383,9 @@ export default class SchemaCloner {
|
|
|
383
383
|
/**
|
|
384
384
|
* Builds TableData column args from a source column, copying type, nullability,
|
|
385
385
|
* length, notes, simple defaults and (for full clones) primary-key flag.
|
|
386
|
-
* @param {import("../drivers/base-column.js").default} sourceColumn
|
|
387
|
-
* @param {{isNewColumn: boolean}} args
|
|
388
|
-
* @returns {Record<string, unknown>}
|
|
386
|
+
* @param {import("../drivers/base-column.js").default} sourceColumn - Source column definition.
|
|
387
|
+
* @param {{isNewColumn: boolean}} args - Whether the column is being added instead of cloned with its table.
|
|
388
|
+
* @returns {Record<string, unknown>} - Arguments for altering the target column.
|
|
389
389
|
*/
|
|
390
390
|
columnArgsFromSourceColumn(sourceColumn, {isNewColumn}) {
|
|
391
391
|
/** @type {{autoIncrement?: boolean, default?: unknown, isNewColumn: boolean, maxLength?: number, notes?: string, null: boolean, primaryKey?: boolean, type: string}} */
|
|
@@ -290,7 +290,6 @@ export default class VelociousEnvironmentsHandlerBrowser extends Base {
|
|
|
290
290
|
* Runs after migrations.
|
|
291
291
|
* @param {object} args - Options object.
|
|
292
292
|
* @param {Record<string, import("../database/drivers/base.js").default>} args.dbs - Dbs.
|
|
293
|
-
* @param {"migration" | "schemaDump"} [args.reason] - Why the structure hook is running.
|
|
294
293
|
* @returns {Promise<void>} - Resolves when complete.
|
|
295
294
|
*/
|
|
296
295
|
async afterMigrations({dbs}) {
|
|
@@ -19,6 +19,7 @@ export default class BackgroundJobsRunnerCommand extends BaseCommand {
|
|
|
19
19
|
const decoded = Buffer.from(payload, "base64").toString("utf8")
|
|
20
20
|
const jobPayload = JSON.parse(decoded)
|
|
21
21
|
|
|
22
|
-
await runJobPayload(jobPayload)
|
|
22
|
+
await runJobPayload(jobPayload, {closeConnections: false})
|
|
23
|
+
process.exit(0)
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -124,7 +124,7 @@ export default class VelociousCliCommandsLintRelationships extends BaseCommand {
|
|
|
124
124
|
|
|
125
125
|
if (!stats.isDirectory()) return false
|
|
126
126
|
} catch (error) {
|
|
127
|
-
if (/** @type {
|
|
127
|
+
if (/** @type {Error & {code?: string}} */ (error).code == "ENOENT") return false
|
|
128
128
|
|
|
129
129
|
throw error
|
|
130
130
|
}
|
|
@@ -213,7 +213,7 @@ export default class VelociousCliCommandsLintRelationships extends BaseCommand {
|
|
|
213
213
|
try {
|
|
214
214
|
configContent = await fs.readFile(configPath, "utf8")
|
|
215
215
|
} catch (error) {
|
|
216
|
-
if (!explicitConfigPath && /** @type {
|
|
216
|
+
if (!explicitConfigPath && /** @type {Error & {code?: string}} */ (error).code == "ENOENT") {
|
|
217
217
|
return new Set()
|
|
218
218
|
}
|
|
219
219
|
|
|
@@ -860,7 +860,7 @@ export default class VelociousEnvironmentHandlerNode extends Base{
|
|
|
860
860
|
files.push({file, fullPath, date, migrationClassName})
|
|
861
861
|
}
|
|
862
862
|
} catch (error) {
|
|
863
|
-
if (/** @type {
|
|
863
|
+
if (/** @type {Error & {code?: string}} */ (error)?.code !== "ENOENT") {
|
|
864
864
|
throw error
|
|
865
865
|
}
|
|
866
866
|
}
|
|
@@ -20,6 +20,8 @@ import isDate from "./utils/is-date.js"
|
|
|
20
20
|
import isPlainObject from "./utils/plain-object.js"
|
|
21
21
|
import {RansackQueryError, normalizeRansackGroup, parseRansackSort} from "./utils/ransack.js"
|
|
22
22
|
|
|
23
|
+
/** @typedef {import("./database/query/model-class-query.js").default & Record<symbol, Set<string> | undefined>} FrontendModelQueryMetadata */
|
|
24
|
+
|
|
23
25
|
/**
|
|
24
26
|
* Runs normalize frontend model preload.
|
|
25
27
|
* @param {import("./database/query/index.js").NestedPreloadRecord | string | string[] | boolean | undefined | null} preload - Preload shorthand.
|
|
@@ -31,7 +33,7 @@ function normalizeFrontendModelPreload(preload) {
|
|
|
31
33
|
try {
|
|
32
34
|
return normalizeQueryPreload(preload)
|
|
33
35
|
} catch (error) {
|
|
34
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
36
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -46,7 +48,7 @@ function normalizeFrontendModelJoins(joins) {
|
|
|
46
48
|
try {
|
|
47
49
|
return normalizeQueryJoins(joins)
|
|
48
50
|
} catch (error) {
|
|
49
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
51
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
|
|
@@ -190,10 +192,10 @@ function frontendSyncReplaySafeError(message, cause) {
|
|
|
190
192
|
/**
|
|
191
193
|
* Runs frontend model query metadata.
|
|
192
194
|
* @param {import("./database/query/model-class-query.js").default} query - Query instance.
|
|
193
|
-
* @returns {
|
|
195
|
+
* @returns {FrontendModelQueryMetadata} - Query metadata access helper.
|
|
194
196
|
*/
|
|
195
197
|
function frontendModelQueryMetadata(query) {
|
|
196
|
-
return /** @type {
|
|
198
|
+
return /** @type {FrontendModelQueryMetadata} */ (query)
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
/**
|
|
@@ -1253,7 +1255,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1253
1255
|
try {
|
|
1254
1256
|
return normalizeQuerySort(this.frontendModelParams().sort)
|
|
1255
1257
|
} catch (error) {
|
|
1256
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
1258
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
1257
1259
|
}
|
|
1258
1260
|
}
|
|
1259
1261
|
|
|
@@ -1265,7 +1267,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1265
1267
|
try {
|
|
1266
1268
|
return normalizeQueryGroup(this.frontendModelParams().group)
|
|
1267
1269
|
} catch (error) {
|
|
1268
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
1270
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
1269
1271
|
}
|
|
1270
1272
|
}
|
|
1271
1273
|
|
|
@@ -1304,7 +1306,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1304
1306
|
|
|
1305
1307
|
return pluck
|
|
1306
1308
|
} catch (error) {
|
|
1307
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
1309
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
1308
1310
|
}
|
|
1309
1311
|
}
|
|
1310
1312
|
|
|
@@ -1351,8 +1353,8 @@ export default class FrontendModelController extends Controller {
|
|
|
1351
1353
|
* its backend model class by looking up the resource by modelName
|
|
1352
1354
|
* across all configured backend projects. Returns null when no
|
|
1353
1355
|
* resource matches the user-provided ability entry.
|
|
1354
|
-
* @param {string} modelName
|
|
1355
|
-
* @returns {typeof import("./database/record/index.js").default | null}
|
|
1356
|
+
* @param {string} modelName - Frontend model name from an ability request.
|
|
1357
|
+
* @returns {typeof import("./database/record/index.js").default | null} - Backend model class exposed under that frontend name, if present.
|
|
1356
1358
|
*/
|
|
1357
1359
|
_frontendModelClassForAbilities(modelName) {
|
|
1358
1360
|
if (typeof modelName !== "string" || modelName.length === 0) return null
|
|
@@ -1383,9 +1385,9 @@ export default class FrontendModelController extends Controller {
|
|
|
1383
1385
|
* preloaded relationships at any depth. Used to evaluate per-record
|
|
1384
1386
|
* abilities against nested preloaded children with a single batched
|
|
1385
1387
|
* query per (modelClass, action) pair.
|
|
1386
|
-
* @param {import("./database/record/index.js").default[]} rootModels
|
|
1387
|
-
* @param {string} modelName
|
|
1388
|
-
* @returns {import("./database/record/index.js").default[]}
|
|
1388
|
+
* @param {import("./database/record/index.js").default[]} rootModels - Loaded roots whose relationship graphs should be traversed.
|
|
1389
|
+
* @param {string} modelName - Model name records must match.
|
|
1390
|
+
* @returns {import("./database/record/index.js").default[]} - Matching records reachable from the loaded roots.
|
|
1389
1391
|
*/
|
|
1390
1392
|
_frontendModelCollectRecordsForName(rootModels, modelName) {
|
|
1391
1393
|
/**
|
|
@@ -1399,7 +1401,8 @@ export default class FrontendModelController extends Controller {
|
|
|
1399
1401
|
|
|
1400
1402
|
/**
|
|
1401
1403
|
* Walk.
|
|
1402
|
-
* @param {import("./database/record/index.js").default | null | undefined} record
|
|
1404
|
+
* @param {import("./database/record/index.js").default | null | undefined} record - Loaded record whose relationship graph should be visited.
|
|
1405
|
+
*/
|
|
1403
1406
|
const walk = (record) => {
|
|
1404
1407
|
if (!record || typeof record !== "object") return
|
|
1405
1408
|
if (seen.has(record)) return
|
|
@@ -1437,7 +1440,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1437
1440
|
* `_setComputedAbility`. Runs one batched `authorized query + pluck`
|
|
1438
1441
|
* per (modelClass, action) pair, regardless of how many records
|
|
1439
1442
|
* were loaded.
|
|
1440
|
-
* @param {import("./database/record/index.js").default[]} rootModels
|
|
1443
|
+
* @param {import("./database/record/index.js").default[]} rootModels - Loaded roots that receive computed ability results.
|
|
1441
1444
|
* @returns {Promise<void>}
|
|
1442
1445
|
*/
|
|
1443
1446
|
async frontendModelComputeAbilities(rootModels) {
|
|
@@ -1491,7 +1494,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1491
1494
|
* Unknown entries are silently skipped — downstream code resolves
|
|
1492
1495
|
* model names to classes when applying the check, so unresolved
|
|
1493
1496
|
* names naturally become no-ops.
|
|
1494
|
-
* @returns {Array<{modelName: string, actions: string[]}>}
|
|
1497
|
+
* @returns {Array<{modelName: string, actions: string[]}>} - Normalized model ability requests.
|
|
1495
1498
|
*/
|
|
1496
1499
|
frontendModelAbilities() {
|
|
1497
1500
|
const raw = this.frontendModelParams().abilities
|
|
@@ -1529,7 +1532,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1529
1532
|
*
|
|
1530
1533
|
* Returns the raw nested-record spec (shape validated by the
|
|
1531
1534
|
* normalizer inside `Query.queryData`) or `null` when not requested.
|
|
1532
|
-
* @returns {import("./database/query/query-data.js").QueryDataSpec | null}
|
|
1535
|
+
* @returns {import("./database/query/query-data.js").QueryDataSpec | null} - Normalized query-data specification.
|
|
1533
1536
|
*/
|
|
1534
1537
|
frontendModelQueryData() {
|
|
1535
1538
|
const raw = this.frontendModelParams().queryData
|
|
@@ -1853,7 +1856,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1853
1856
|
try {
|
|
1854
1857
|
return normalizeRansackGroup(this.frontendModelClass(), filterParams)
|
|
1855
1858
|
} catch (error) {
|
|
1856
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
1859
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
1857
1860
|
}
|
|
1858
1861
|
}
|
|
1859
1862
|
|
|
@@ -1866,7 +1869,7 @@ export default class FrontendModelController extends Controller {
|
|
|
1866
1869
|
try {
|
|
1867
1870
|
return parseRansackSort(this.frontendModelClass(), sortString)
|
|
1868
1871
|
} catch (error) {
|
|
1869
|
-
throwFrontendModelQueryErrorForParserError(error)
|
|
1872
|
+
return throwFrontendModelQueryErrorForParserError(error)
|
|
1870
1873
|
}
|
|
1871
1874
|
}
|
|
1872
1875
|
|
|
@@ -2698,12 +2701,14 @@ export default class FrontendModelController extends Controller {
|
|
|
2698
2701
|
/**
|
|
2699
2702
|
* Resource attribute method name.
|
|
2700
2703
|
* @param {string} attributeName - Attribute name.
|
|
2704
|
+
* @returns {string} - Resource attribute method name.
|
|
2701
2705
|
*/
|
|
2702
2706
|
const resourceAttributeMethodName = (attributeName) => `${attributeName}Attribute`
|
|
2703
2707
|
|
|
2704
2708
|
/**
|
|
2705
2709
|
* Resource has attribute.
|
|
2706
2710
|
* @param {string} attributeName - Attribute name.
|
|
2711
|
+
* @returns {ReturnType<FrontendModelBaseResource["resourceMethod"]>} - Resource attribute method details.
|
|
2707
2712
|
*/
|
|
2708
2713
|
const resourceAttributeMethod = (attributeName) => {
|
|
2709
2714
|
const methodName = resourceAttributeMethodName(attributeName)
|
|
@@ -2714,6 +2719,7 @@ export default class FrontendModelController extends Controller {
|
|
|
2714
2719
|
/**
|
|
2715
2720
|
* Prototype attribute method.
|
|
2716
2721
|
* @param {string} attributeName - Attribute name.
|
|
2722
|
+
* @returns {{method: (...args: Array<?>) => ?, ownerName: string} | undefined} - Prototype method details when present.
|
|
2717
2723
|
*/
|
|
2718
2724
|
const prototypeAttributeMethod = (attributeName) => {
|
|
2719
2725
|
let currentPrototype = Object.getPrototypeOf(model)
|
|
@@ -2735,6 +2741,7 @@ export default class FrontendModelController extends Controller {
|
|
|
2735
2741
|
/**
|
|
2736
2742
|
* Serialized attribute value.
|
|
2737
2743
|
* @param {string} attributeName - Attribute name.
|
|
2744
|
+
* @returns {Promise<?>} - Serialized attribute value.
|
|
2738
2745
|
*/
|
|
2739
2746
|
const serializedAttributeValue = async (attributeName) => {
|
|
2740
2747
|
// Check resource instance first (virtual/computed attributes via ${name}Attribute convention)
|
|
@@ -2758,6 +2765,7 @@ export default class FrontendModelController extends Controller {
|
|
|
2758
2765
|
/**
|
|
2759
2766
|
* Attribute exists.
|
|
2760
2767
|
* @param {string} attributeName - Attribute name.
|
|
2768
|
+
* @returns {boolean} - Whether the attribute exists.
|
|
2761
2769
|
*/
|
|
2762
2770
|
const attributeExists = (attributeName) => {
|
|
2763
2771
|
return (attributeName in modelAttributes) || (attributeName in /** @type {Record<string, ?>} */ (model)) || Boolean(resourceAttributeMethod(attributeName))
|
|
@@ -104,7 +104,7 @@ import {readPayloadAssociationCount, readPayloadComputedAbility, readPayloadQuer
|
|
|
104
104
|
* frontend models passed model classes into relationship helpers, while newer
|
|
105
105
|
* generated models pass instance types.
|
|
106
106
|
* @template {FrontendModelBase<any, any, any> | typeof FrontendModelBase} T
|
|
107
|
-
* @typedef {T extends
|
|
107
|
+
* @typedef {T extends typeof FrontendModelBase ? InstanceType<T> : T} FrontendModelRelationshipModel
|
|
108
108
|
*/
|
|
109
109
|
/**
|
|
110
110
|
* FrontendModelTransportConfig type.
|
|
@@ -1799,7 +1799,7 @@ async function performSharedFrontendModelApiRequest(requestPayload) {
|
|
|
1799
1799
|
/**
|
|
1800
1800
|
* Throws a frontend-model HTTP error with backend-provided envelope details when available.
|
|
1801
1801
|
* @param {{commandLabel: string, response: Response, responseText: string}} args - Error response details.
|
|
1802
|
-
* @returns {never}
|
|
1802
|
+
* @returns {never} - Always throws an unknown-attribute error.
|
|
1803
1803
|
*/
|
|
1804
1804
|
function throwFrontendModelHttpError({commandLabel, response, responseText}) {
|
|
1805
1805
|
// Surface the backend's friendly errorMessage envelope (the
|
|
@@ -2612,7 +2612,7 @@ export default class FrontendModelBase {
|
|
|
2612
2612
|
* column of the same name. Returns the attached value, or 0 when
|
|
2613
2613
|
* `.withCount(...)` wasn't requested for this attribute.
|
|
2614
2614
|
* @param {string} attributeName - Attribute name, e.g. `"tasksCount"` or a custom name from `.withCount({customName: {...}})`.
|
|
2615
|
-
* @returns {number}
|
|
2615
|
+
* @returns {number} - Attached association count, or zero when absent.
|
|
2616
2616
|
*/
|
|
2617
2617
|
readCount(attributeName) {
|
|
2618
2618
|
return readPayloadAssociationCount(/** @type {import("../record-payload-values.js").RecordPayloadValuesTarget} */ (/** @type {?} */ (this)), attributeName)
|
|
@@ -2638,7 +2638,7 @@ export default class FrontendModelBase {
|
|
|
2638
2638
|
* on `record.can("update")` without first checking whether the
|
|
2639
2639
|
* ability was loaded.
|
|
2640
2640
|
* @param {string} action - Ability action name, e.g. `"update"`.
|
|
2641
|
-
* @returns {boolean}
|
|
2641
|
+
* @returns {boolean} - Whether the requested ability is allowed.
|
|
2642
2642
|
*/
|
|
2643
2643
|
can(action) {
|
|
2644
2644
|
return readPayloadComputedAbility(/** @type {import("../record-payload-values.js").RecordPayloadValuesTarget} */ (/** @type {?} */ (this)), action)
|
|
@@ -2663,7 +2663,7 @@ export default class FrontendModelBase {
|
|
|
2663
2663
|
* name. Returns `null` when no registered fn produced that alias for
|
|
2664
2664
|
* this record (e.g. no child rows matched the aggregate).
|
|
2665
2665
|
* @param {string} name - queryData alias name.
|
|
2666
|
-
* @returns {?}
|
|
2666
|
+
* @returns {?} - Attached query-data value.
|
|
2667
2667
|
*/
|
|
2668
2668
|
queryData(name) {
|
|
2669
2669
|
return readPayloadQueryData(/** @type {import("../record-payload-values.js").RecordPayloadValuesTarget} */ (/** @type {?} */ (this)), name)
|
|
@@ -166,8 +166,8 @@ export function normalizePreload(preload) {
|
|
|
166
166
|
* query API into the strict internal entries used in the transport
|
|
167
167
|
* payload. Shares the shape semantics with the backend normalizer in
|
|
168
168
|
* `database/query/with-count.js`.
|
|
169
|
-
* @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec
|
|
170
|
-
* @returns {Array<{attributeName: string, relationshipName: string, where?: Record<string, ?>}>}
|
|
169
|
+
* @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec - Association-count shorthand to normalize.
|
|
170
|
+
* @returns {Array<{attributeName: string, relationshipName: string, where?: Record<string, ?>}>} - Normalized association-count requests.
|
|
171
171
|
*/
|
|
172
172
|
function normalizeWithCountFrontend(spec) {
|
|
173
173
|
if (spec == null) return []
|
|
@@ -222,9 +222,9 @@ function normalizeWithCountFrontend(spec) {
|
|
|
222
222
|
* shorthand (applies to the query's own model class) and the keyed
|
|
223
223
|
* `{ModelName: [action, ...]}` form (applies to records of that model
|
|
224
224
|
* class, useful for preloaded children).
|
|
225
|
-
* @param {string[] | Record<string, string[]>} spec
|
|
226
|
-
* @param {{getModelName: () => string}} rootModelClass
|
|
227
|
-
* @returns {Array<{modelName: string, actions: string[]}>}
|
|
225
|
+
* @param {string[] | Record<string, string[]>} spec - Ability actions grouped by model, or root-model action shorthand.
|
|
226
|
+
* @param {{getModelName: () => string}} rootModelClass - Query root used by the flat action shorthand.
|
|
227
|
+
* @returns {Array<{modelName: string, actions: string[]}>} - Normalized model ability requests.
|
|
228
228
|
*/
|
|
229
229
|
function normalizeAbilitiesSpec(spec, rootModelClass) {
|
|
230
230
|
if (spec == null) return []
|
|
@@ -1181,8 +1181,8 @@ export default class FrontendModelQuery {
|
|
|
1181
1181
|
* strings — typically `"update"` / `"destroy"` / `"create"` /
|
|
1182
1182
|
* `"read"`, but any custom action registered on the resource's
|
|
1183
1183
|
* authorization ability is accepted.
|
|
1184
|
-
* @param {string[] | Record<string, string[]>} spec
|
|
1185
|
-
* @returns {this}
|
|
1184
|
+
* @param {string[] | Record<string, string[]>} spec - Ability actions to request for root or named models.
|
|
1185
|
+
* @returns {this} - This query for chaining.
|
|
1186
1186
|
*/
|
|
1187
1187
|
abilities(spec) {
|
|
1188
1188
|
for (const entry of normalizeAbilitiesSpec(spec, this.modelClass)) {
|
|
@@ -1194,7 +1194,7 @@ export default class FrontendModelQuery {
|
|
|
1194
1194
|
|
|
1195
1195
|
/**
|
|
1196
1196
|
* Runs merge ability entry.
|
|
1197
|
-
* @param {{modelName: string, actions: string[]}} entry
|
|
1197
|
+
* @param {{modelName: string, actions: string[]}} entry - Normalized model ability request to append.
|
|
1198
1198
|
* @returns {void}
|
|
1199
1199
|
*/
|
|
1200
1200
|
_mergeAbilityEntry(entry) {
|
|
@@ -1215,8 +1215,8 @@ export default class FrontendModelQuery {
|
|
|
1215
1215
|
* counts to each returned record. Parses the same shapes as the
|
|
1216
1216
|
* backend `ModelClassQuery#withCount`, then ships the normalized
|
|
1217
1217
|
* entries as part of the `index` command payload.
|
|
1218
|
-
* @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec
|
|
1219
|
-
* @returns {this}
|
|
1218
|
+
* @param {string | string[] | Record<string, boolean | {relationship?: string, where?: Record<string, ?>}>} spec - Relationships whose counts should be serialized.
|
|
1219
|
+
* @returns {this} - This query for chaining.
|
|
1220
1220
|
*/
|
|
1221
1221
|
withCount(spec) {
|
|
1222
1222
|
for (const entry of normalizeWithCountFrontend(spec)) {
|
|
@@ -1233,8 +1233,8 @@ export default class FrontendModelQuery {
|
|
|
1233
1233
|
* frontend ships only these names; the SQL fragments stay server-
|
|
1234
1234
|
* side. All resulting aliases are attached to the root record and
|
|
1235
1235
|
* read back with `record.queryData(aliasName)`.
|
|
1236
|
-
* @param {string | Array<string | Record<string, ?>> | Record<string, ?>} spec
|
|
1237
|
-
* @returns {this}
|
|
1236
|
+
* @param {string | Array<string | Record<string, ?>> | Record<string, ?>} spec - Backend query-data names and arguments to serialize.
|
|
1237
|
+
* @returns {this} - This query for chaining.
|
|
1238
1238
|
*/
|
|
1239
1239
|
queryData(spec) {
|
|
1240
1240
|
if (spec == null) return this
|