velocious 1.0.442 → 1.0.444
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/build/authorization/base-resource.js +2 -2
- package/build/beacon/client.js +13 -7
- package/build/beacon/server.js +11 -0
- package/build/configuration-types.js +5 -1
- package/build/controller.js +1 -1
- package/build/database/record/acts-as-list.js +89 -24
- package/build/database/record/index.js +53 -31
- package/build/database/record/relationships/belongs-to.js +1 -1
- package/build/database/record/relationships/has-many.js +3 -1
- package/build/database/record/relationships/has-one.js +3 -1
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +2 -2
- package/build/frontend-model-resource/base-resource.js +9 -10
- package/build/frontend-models/base.js +6 -6
- package/build/frontend-models/query.js +2 -2
- package/build/src/authorization/base-resource.d.ts +4 -4
- package/build/src/authorization/base-resource.d.ts.map +1 -1
- package/build/src/authorization/base-resource.js +3 -3
- package/build/src/beacon/client.d.ts.map +1 -1
- package/build/src/beacon/client.js +13 -8
- package/build/src/beacon/server.d.ts +5 -0
- package/build/src/beacon/server.d.ts.map +1 -1
- package/build/src/beacon/server.js +11 -1
- package/build/src/configuration-types.d.ts +7 -3
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +5 -2
- package/build/src/controller.d.ts +3 -3
- package/build/src/controller.d.ts.map +1 -1
- package/build/src/controller.js +2 -2
- package/build/src/database/record/acts-as-list.d.ts.map +1 -1
- package/build/src/database/record/acts-as-list.js +80 -23
- package/build/src/database/record/index.d.ts +48 -37
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +50 -32
- package/build/src/database/record/relationships/belongs-to.js +2 -2
- package/build/src/database/record/relationships/has-many.d.ts.map +1 -1
- package/build/src/database/record/relationships/has-many.js +3 -2
- package/build/src/database/record/relationships/has-one.d.ts.map +1 -1
- package/build/src/database/record/relationships/has-one.js +3 -2
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +3 -3
- package/build/src/frontend-model-resource/base-resource.d.ts +15 -16
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +10 -11
- package/build/src/frontend-models/base.d.ts +18 -12
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +7 -7
- package/build/src/frontend-models/query.d.ts +4 -4
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +3 -3
- package/package.json +1 -1
- package/src/authorization/base-resource.js +2 -2
- package/src/beacon/client.js +13 -7
- package/src/beacon/server.js +11 -0
- package/src/configuration-types.js +5 -1
- package/src/controller.js +1 -1
- package/src/database/record/acts-as-list.js +89 -24
- package/src/database/record/index.js +53 -31
- package/src/database/record/relationships/belongs-to.js +1 -1
- package/src/database/record/relationships/has-many.js +3 -1
- package/src/database/record/relationships/has-one.js +3 -1
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +2 -2
- package/src/frontend-model-resource/base-resource.js +9 -10
- package/src/frontend-models/base.js +6 -6
- package/src/frontend-models/query.js +2 -2
|
@@ -111,7 +111,7 @@ export default class AuthorizationBaseResource {
|
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* Runs current user.
|
|
114
|
-
* @returns {
|
|
114
|
+
* @returns {unknown} - Current user from context.
|
|
115
115
|
*/
|
|
116
116
|
currentUser() {
|
|
117
117
|
return this.context.currentUser
|
|
@@ -127,7 +127,7 @@ export default class AuthorizationBaseResource {
|
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
129
|
* Runs params.
|
|
130
|
-
* @returns {import("../configuration-types.js").
|
|
130
|
+
* @returns {import("../configuration-types.js").VelociousParams | undefined} - Params from context.
|
|
131
131
|
*/
|
|
132
132
|
params() {
|
|
133
133
|
return this.context.params
|
package/build/beacon/client.js
CHANGED
|
@@ -225,14 +225,20 @@ export default class BeaconClient extends EventEmitter {
|
|
|
225
225
|
this._reconnectTimer = undefined
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
const socket = this._socket
|
|
228
|
+
const socket = this._socket
|
|
230
229
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
if (!socket) return
|
|
231
|
+
|
|
232
|
+
this._socket = undefined
|
|
233
|
+
this._jsonSocket = undefined
|
|
234
|
+
|
|
235
|
+
if (socket.destroyed) return
|
|
236
|
+
|
|
237
|
+
await new Promise((resolve) => {
|
|
238
|
+
socket.once("close", () => resolve(undefined))
|
|
239
|
+
socket.end()
|
|
240
|
+
socket.destroySoon()
|
|
241
|
+
})
|
|
236
242
|
}
|
|
237
243
|
|
|
238
244
|
/**
|
package/build/beacon/server.js
CHANGED
|
@@ -37,6 +37,11 @@ export default class BeaconServer {
|
|
|
37
37
|
* Narrows the runtime value to the documented type.
|
|
38
38
|
@type {net.Server | undefined} */
|
|
39
39
|
this.server = undefined
|
|
40
|
+
/**
|
|
41
|
+
* Accepted sockets, including connections that have not completed the hello handshake yet.
|
|
42
|
+
* @type {Set<net.Socket>}
|
|
43
|
+
*/
|
|
44
|
+
this.sockets = new Set()
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
/**
|
|
@@ -68,6 +73,10 @@ export default class BeaconServer {
|
|
|
68
73
|
peer.close()
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
for (const socket of this.sockets) {
|
|
77
|
+
socket.destroy()
|
|
78
|
+
}
|
|
79
|
+
|
|
71
80
|
if (!this.server) return
|
|
72
81
|
|
|
73
82
|
const {server} = this
|
|
@@ -97,6 +106,7 @@ export default class BeaconServer {
|
|
|
97
106
|
* @returns {void}
|
|
98
107
|
*/
|
|
99
108
|
_handleConnection(socket) {
|
|
109
|
+
this.sockets.add(socket)
|
|
100
110
|
const jsonSocket = new JsonSocket(socket)
|
|
101
111
|
/**
|
|
102
112
|
* Defines peerId.
|
|
@@ -104,6 +114,7 @@ export default class BeaconServer {
|
|
|
104
114
|
let peerId
|
|
105
115
|
|
|
106
116
|
const cleanup = () => {
|
|
117
|
+
this.sockets.delete(socket)
|
|
107
118
|
this.peers.delete(jsonSocket)
|
|
108
119
|
}
|
|
109
120
|
|
|
@@ -202,7 +202,11 @@
|
|
|
202
202
|
*/
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* @typedef {Record<string,
|
|
205
|
+
* @typedef {Record<string, string>} VelociousParams
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @typedef {Record<string, unknown> & {configuration?: import("./configuration.js").default, currentUser?: unknown, params?: VelociousParams, request?: import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default}} VelociousLooseObject
|
|
206
210
|
*/
|
|
207
211
|
|
|
208
212
|
/**
|
package/build/controller.js
CHANGED
|
@@ -34,7 +34,7 @@ export default class VelociousController {
|
|
|
34
34
|
* @param {string} args.action - Action.
|
|
35
35
|
* @param {import("./configuration.js").default} args.configuration - Configuration instance.
|
|
36
36
|
* @param {string} args.controller - Controller.
|
|
37
|
-
* @param {
|
|
37
|
+
* @param {Record<string, ?>} args.params - Parameters object.
|
|
38
38
|
* @param {import("./http-server/client/request.js").default} args.request - Request object.
|
|
39
39
|
* @param {import("./http-server/client/response.js").default} args.response - Response object.
|
|
40
40
|
* @param {string} args.viewPath - View path.
|
|
@@ -67,14 +67,15 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
67
67
|
@type {typeof import("./index.js").default} */ (record.constructor)
|
|
68
68
|
const posColumn = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
69
69
|
const scopeCol = modelClass.getColumnNameForAttributeName(scope)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const changes =
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
/** @type {Record<string, ?>} */
|
|
71
|
+
const rawAttributes = record._attributes || {}
|
|
72
|
+
/** @type {Record<string, ?>} */
|
|
73
|
+
const changes = record._changes || {}
|
|
74
|
+
/** @type {Set<string>} */
|
|
75
|
+
const assignedAttributeNames = record._assignedAttributeNames || new Set()
|
|
76
76
|
const posChanged = posColumn in changes
|
|
77
77
|
const scopeChanged = scopeCol in changes
|
|
78
|
+
const posAssigned = assignedAttributeNames.has(positionColumn)
|
|
78
79
|
|
|
79
80
|
if (!posChanged && !scopeChanged) return
|
|
80
81
|
|
|
@@ -102,18 +103,13 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
102
103
|
if (oldPosition == null || newPosition == null) return
|
|
103
104
|
if (newPosition === oldPosition && newScopeValue === oldScopeValue) return
|
|
104
105
|
|
|
105
|
-
// Move the record out of the way before shifting others to avoid
|
|
106
|
-
// intermediate UNIQUE constraint violations. Use the old scope value
|
|
107
|
-
// for the move-out-of-way because the record is still in the old scope.
|
|
108
|
-
await moveOutOfWay({record, positionColumn, scope, scopeValue: oldScopeValue})
|
|
109
|
-
setShiftingFlag(record, false)
|
|
110
|
-
|
|
111
106
|
if (scopeChanged && oldScopeValue !== newScopeValue) {
|
|
112
|
-
let targetPosition = newPosition
|
|
113
|
-
|
|
114
107
|
// When only the scope changes without a new position, append to the end
|
|
115
108
|
// of the new scope. There is no target-scope row to shift out of the way.
|
|
116
|
-
if (!
|
|
109
|
+
if (!posAssigned) {
|
|
110
|
+
await moveOutOfWay({record, positionColumn, scope, scopeValue: oldScopeValue})
|
|
111
|
+
setShiftingFlag(record, false)
|
|
112
|
+
|
|
117
113
|
const highestNew = await highestPositionInScope({record, positionColumn, scope, scopeValue: newScopeValue})
|
|
118
114
|
const nextPos = highestNew + 1
|
|
119
115
|
|
|
@@ -122,11 +118,17 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
122
118
|
return
|
|
123
119
|
}
|
|
124
120
|
|
|
121
|
+
await moveOutOfWay({record, positionColumn, scope, scopeValue: oldScopeValue, targetScopeValue: newScopeValue})
|
|
122
|
+
setShiftingFlag(record, false)
|
|
125
123
|
await shiftPositionsDown({record, positionColumn, scope, scopeValue: oldScopeValue, fromPosition: oldPosition + 1})
|
|
126
|
-
await shiftPositionsUp({record, positionColumn, scope, scopeValue: newScopeValue, fromPosition:
|
|
124
|
+
await shiftPositionsUp({record, positionColumn, scope, scopeValue: newScopeValue, fromPosition: newPosition, excludeRecordId: record.id()})
|
|
125
|
+
await placeMovedRecord({record, positionColumn, scope, scopeValue: newScopeValue, position: newPosition})
|
|
127
126
|
return
|
|
128
127
|
}
|
|
129
128
|
|
|
129
|
+
await moveOutOfWay({record, positionColumn, scope, scopeValue: oldScopeValue})
|
|
130
|
+
setShiftingFlag(record, false)
|
|
131
|
+
|
|
130
132
|
if (newPosition < oldPosition) {
|
|
131
133
|
await shiftPositionsUp({record, positionColumn, scope, fromPosition: newPosition, toPosition: oldPosition})
|
|
132
134
|
} else if (newPosition > oldPosition) {
|
|
@@ -146,6 +148,53 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
146
148
|
})
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Places a moved row after surrounding rows have shifted.
|
|
153
|
+
* @param {object} args - Arguments.
|
|
154
|
+
* @param {import("./index.js").default} args.record - Model instance.
|
|
155
|
+
* @param {string} args.positionColumn - Position attribute name.
|
|
156
|
+
* @param {string} args.scope - Scope attribute name.
|
|
157
|
+
* @param {string | number} args.scopeValue - Destination scope value.
|
|
158
|
+
* @param {number} args.position - Destination position.
|
|
159
|
+
* @returns {Promise<void>} Resolves after placement.
|
|
160
|
+
*/
|
|
161
|
+
async function placeMovedRecord({record, positionColumn, scope, scopeValue, position}) {
|
|
162
|
+
const modelClass = /** @type {typeof import("./index.js").default} */ (record.constructor)
|
|
163
|
+
const connection = modelClass.connection()
|
|
164
|
+
const tableSql = connection.quoteTable(modelClass._getTable().getName())
|
|
165
|
+
const scopeCol = modelClass.getColumnNameForAttributeName(scope)
|
|
166
|
+
const posCol = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
167
|
+
const preservedChanges = {...record._changes}
|
|
168
|
+
const scopeColumnSql = connection.quoteColumn(scopeCol)
|
|
169
|
+
const positionColumnSql = connection.quoteColumn(posCol)
|
|
170
|
+
const primaryKeySql = connection.quoteColumn(modelClass.primaryKey())
|
|
171
|
+
|
|
172
|
+
delete preservedChanges[scopeCol]
|
|
173
|
+
delete preservedChanges[posCol]
|
|
174
|
+
|
|
175
|
+
await connection.query(
|
|
176
|
+
`UPDATE ${tableSql} SET ${scopeColumnSql} = ${connection.quote(scopeValue)}, ${positionColumnSql} = ${connection.quote(position)} WHERE ${primaryKeySql} = ${connection.quote(record.id())}`
|
|
177
|
+
)
|
|
178
|
+
await record._reloadWithId(record.id())
|
|
179
|
+
record._changes = preservedChanges
|
|
180
|
+
clearBelongsToChangeForScope(record)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Clears dirty belongs-to state for the scope FK after direct placement.
|
|
185
|
+
* @param {import("./index.js").default} record - Model instance.
|
|
186
|
+
* @returns {void} Nothing.
|
|
187
|
+
*/
|
|
188
|
+
function clearBelongsToChangeForScope(record) {
|
|
189
|
+
for (const relationshipName in record._instanceRelationships || {}) {
|
|
190
|
+
const relationship = record._instanceRelationships[relationshipName]
|
|
191
|
+
|
|
192
|
+
if (relationship.getType() !== "belongsTo") continue
|
|
193
|
+
|
|
194
|
+
relationship.setDirty(false)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
149
198
|
/**
|
|
150
199
|
* Bumps positions UP by 1 in the range [fromPosition, toPosition) within the
|
|
151
200
|
* same scope. Updates in descending order to avoid intermediate UNIQUE
|
|
@@ -157,9 +206,10 @@ export default function registerActsAsListCallbacks(modelClass, positionColumn,
|
|
|
157
206
|
* @param {number} args.fromPosition - Starting position (inclusive).
|
|
158
207
|
* @param {number} [args.toPosition] - Ending position (exclusive).
|
|
159
208
|
* @param {string | number} [args.scopeValue] - Explicit scope value.
|
|
209
|
+
* @param {string | number} [args.excludeRecordId] - Record id to exclude from shifts.
|
|
160
210
|
* @returns {Promise<void>}
|
|
161
211
|
*/
|
|
162
|
-
async function shiftPositionsUp({record, positionColumn, scope, fromPosition, toPosition, scopeValue}) {
|
|
212
|
+
async function shiftPositionsUp({record, positionColumn, scope, fromPosition, toPosition, scopeValue, excludeRecordId}) {
|
|
163
213
|
const modelClass = /**
|
|
164
214
|
* Narrows the runtime value to the documented type.
|
|
165
215
|
@type {typeof import("./index.js").default} */ (record.constructor)
|
|
@@ -173,16 +223,25 @@ async function shiftPositionsUp({record, positionColumn, scope, fromPosition, to
|
|
|
173
223
|
const positionColumnName = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
174
224
|
const positionColumnSql = connection.quoteColumn(positionColumnName)
|
|
175
225
|
const scopeColumnSql = connection.quoteColumn(scopeColumnName)
|
|
226
|
+
const primaryKeySql = connection.quoteColumn(modelClass.primaryKey())
|
|
176
227
|
const tableSql = connection.quoteTable(tableName)
|
|
177
228
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
178
229
|
|
|
179
230
|
// Load rows in descending order so we bump the highest first
|
|
180
231
|
let query = modelClass
|
|
232
|
+
.select(modelClass.primaryKey())
|
|
181
233
|
.select(positionColumn)
|
|
182
234
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
183
235
|
.where(`${positionColumnSql} >= ${connection.quote(fromPosition)}`)
|
|
236
|
+
.where(`${positionColumnSql} > 0`)
|
|
184
237
|
.order(`${positionColumnSql} DESC`)
|
|
185
238
|
|
|
239
|
+
const recordIdToExclude = excludeRecordId || (record.isPersisted() ? record.id() : null)
|
|
240
|
+
|
|
241
|
+
if (recordIdToExclude != null) {
|
|
242
|
+
query = query.where(`${primaryKeySql} != ${connection.quote(recordIdToExclude)}`)
|
|
243
|
+
}
|
|
244
|
+
|
|
186
245
|
if (toPosition != null) {
|
|
187
246
|
query = query.where(`${positionColumnSql} < ${connection.quote(toPosition)}`)
|
|
188
247
|
}
|
|
@@ -196,7 +255,7 @@ async function shiftPositionsUp({record, positionColumn, scope, fromPosition, to
|
|
|
196
255
|
const currentPos = Number(row.readAttribute(positionColumn))
|
|
197
256
|
|
|
198
257
|
await connection.query(
|
|
199
|
-
`UPDATE ${tableSql} SET ${positionColumnSql} = ${positionColumnSql} + 1 WHERE ${scopeColumnSql} = ${quotedScope} AND ${positionColumnSql} = ${connection.quote(currentPos)}`
|
|
258
|
+
`UPDATE ${tableSql} SET ${positionColumnSql} = ${positionColumnSql} + 1 WHERE ${primaryKeySql} = ${connection.quote(row.id())} AND ${scopeColumnSql} = ${quotedScope} AND ${positionColumnSql} = ${connection.quote(currentPos)}`
|
|
200
259
|
)
|
|
201
260
|
}
|
|
202
261
|
} finally {
|
|
@@ -231,14 +290,18 @@ async function shiftPositionsDown({record, positionColumn, scope, fromPosition,
|
|
|
231
290
|
const positionColumnName = modelClass.getColumnNameForAttributeName(positionColumn)
|
|
232
291
|
const positionColumnSql = connection.quoteColumn(positionColumnName)
|
|
233
292
|
const scopeColumnSql = connection.quoteColumn(scopeColumnName)
|
|
293
|
+
const primaryKeySql = connection.quoteColumn(modelClass.primaryKey())
|
|
234
294
|
const tableSql = connection.quoteTable(tableName)
|
|
235
295
|
const quotedScope = connection.quote(resolvedScopeValue)
|
|
236
296
|
|
|
237
297
|
// Load rows in ascending order so we shift the lowest gap first
|
|
238
298
|
let query = modelClass
|
|
299
|
+
.select(modelClass.primaryKey())
|
|
239
300
|
.select(positionColumn)
|
|
240
301
|
.where({[scopeColumnName]: resolvedScopeValue})
|
|
241
302
|
.where(`${positionColumnSql} >= ${connection.quote(fromPosition)}`)
|
|
303
|
+
.where(`${positionColumnSql} > 0`)
|
|
304
|
+
.where(`${primaryKeySql} != ${connection.quote(record.id())}`)
|
|
242
305
|
.order({column: positionColumnName, direction: "ASC"})
|
|
243
306
|
|
|
244
307
|
if (toPosition != null) {
|
|
@@ -254,7 +317,7 @@ async function shiftPositionsDown({record, positionColumn, scope, fromPosition,
|
|
|
254
317
|
const currentPos = Number(row.readAttribute(positionColumn))
|
|
255
318
|
|
|
256
319
|
await connection.query(
|
|
257
|
-
`UPDATE ${tableSql} SET ${positionColumnSql} = ${positionColumnSql} - 1 WHERE ${scopeColumnSql} = ${quotedScope} AND ${positionColumnSql} = ${connection.quote(currentPos)}`
|
|
320
|
+
`UPDATE ${tableSql} SET ${positionColumnSql} = ${positionColumnSql} - 1 WHERE ${primaryKeySql} = ${connection.quote(row.id())} AND ${scopeColumnSql} = ${quotedScope} AND ${positionColumnSql} = ${connection.quote(currentPos)}`
|
|
258
321
|
)
|
|
259
322
|
}
|
|
260
323
|
} finally {
|
|
@@ -342,21 +405,23 @@ function resolveScopeValue(record, scope) {
|
|
|
342
405
|
* @param {import("./index.js").default} args.record - Model instance.
|
|
343
406
|
* @param {string} args.positionColumn - camelCase position attribute.
|
|
344
407
|
* @param {string} args.scope - camelCase scope attribute.
|
|
345
|
-
* @param {string | number | null} [args.scopeValue] -
|
|
408
|
+
* @param {string | number | null} [args.scopeValue] - Scope containing the record before move-out.
|
|
409
|
+
* @param {string | number | null} [args.targetScopeValue] - Temporary scope value to assign.
|
|
346
410
|
* @returns {Promise<void>}
|
|
347
411
|
*/
|
|
348
|
-
async function moveOutOfWay({record, positionColumn, scope, scopeValue}) {
|
|
412
|
+
async function moveOutOfWay({record, positionColumn, scope, scopeValue, targetScopeValue}) {
|
|
349
413
|
const modelClass = /**
|
|
350
414
|
* Narrows the runtime value to the documented type.
|
|
351
415
|
@type {typeof import("./index.js").default} */ (record.constructor)
|
|
352
416
|
const connection = modelClass.connection()
|
|
353
417
|
const tableName = modelClass._getTable().getName()
|
|
354
418
|
const resolvedScopeValue = scopeValue != null ? scopeValue : resolveScopeValue(record, scope)
|
|
419
|
+
const resolvedTargetScopeValue = targetScopeValue != null ? targetScopeValue : resolvedScopeValue
|
|
355
420
|
|
|
356
421
|
if (resolvedScopeValue == null) return
|
|
422
|
+
if (resolvedTargetScopeValue == null) return
|
|
357
423
|
|
|
358
|
-
const
|
|
359
|
-
const tempPosition = highest + 10000
|
|
424
|
+
const tempPosition = -record.id()
|
|
360
425
|
const positionColumnSql = connection.quoteColumn(modelClass.getColumnNameForAttributeName(positionColumn))
|
|
361
426
|
const scopeColumnSql = connection.quoteColumn(modelClass.getColumnNameForAttributeName(scope))
|
|
362
427
|
const tableSql = connection.quoteTable(tableName)
|
|
@@ -366,7 +431,7 @@ async function moveOutOfWay({record, positionColumn, scope, scopeValue}) {
|
|
|
366
431
|
|
|
367
432
|
try {
|
|
368
433
|
await connection.query(
|
|
369
|
-
`UPDATE ${tableSql} SET ${positionColumnSql} = ${connection.quote(tempPosition)} WHERE ${scopeColumnSql} = ${connection.quote(resolvedScopeValue)} AND ${pkSql} = ${connection.quote(record.id())}`
|
|
434
|
+
`UPDATE ${tableSql} SET ${scopeColumnSql} = ${connection.quote(resolvedTargetScopeValue)}, ${positionColumnSql} = ${connection.quote(tempPosition)} WHERE ${scopeColumnSql} = ${connection.quote(resolvedScopeValue)} AND ${pkSql} = ${connection.quote(record.id())}`
|
|
370
435
|
)
|
|
371
436
|
} finally {
|
|
372
437
|
// Don't clear the flag here — the caller will do that after shifts
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
/**
|
|
15
15
|
* Model class constructor type used for static `this` typing.
|
|
16
16
|
* @template {VelociousDatabaseRecord} T
|
|
17
|
-
* @typedef {{new (
|
|
17
|
+
* @typedef {{new (changes?: Record<string, unknown>): T}} ModelConstructor
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import timeout from "awaitery/build/timeout.js"
|
|
@@ -435,6 +435,12 @@ class VelociousDatabaseRecord {
|
|
|
435
435
|
@type {Record<string, ?>} */
|
|
436
436
|
_changes = {}
|
|
437
437
|
|
|
438
|
+
/**
|
|
439
|
+
* Attribute names explicitly assigned in the current update call.
|
|
440
|
+
@type {Set<string> | undefined}
|
|
441
|
+
*/
|
|
442
|
+
_assignedAttributeNames = undefined
|
|
443
|
+
|
|
438
444
|
/**
|
|
439
445
|
* Columns as hash.
|
|
440
446
|
@type {Record<string, import("../drivers/base-column.js").default>} */
|
|
@@ -501,9 +507,9 @@ class VelociousDatabaseRecord {
|
|
|
501
507
|
|
|
502
508
|
/**
|
|
503
509
|
* Runs before validation.
|
|
504
|
-
* @template {VelociousDatabaseRecord}
|
|
505
|
-
* @this {
|
|
506
|
-
* @param {LifecycleCallbackType<
|
|
510
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
511
|
+
* @this {MC}
|
|
512
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
507
513
|
* @returns {void}
|
|
508
514
|
*/
|
|
509
515
|
static beforeValidation(callback) {
|
|
@@ -512,9 +518,9 @@ class VelociousDatabaseRecord {
|
|
|
512
518
|
|
|
513
519
|
/**
|
|
514
520
|
* Runs before save.
|
|
515
|
-
* @template {VelociousDatabaseRecord}
|
|
516
|
-
* @this {
|
|
517
|
-
* @param {LifecycleCallbackType<
|
|
521
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
522
|
+
* @this {MC}
|
|
523
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
518
524
|
* @returns {void}
|
|
519
525
|
*/
|
|
520
526
|
static beforeSave(callback) {
|
|
@@ -523,9 +529,9 @@ class VelociousDatabaseRecord {
|
|
|
523
529
|
|
|
524
530
|
/**
|
|
525
531
|
* Runs before create.
|
|
526
|
-
* @template {VelociousDatabaseRecord}
|
|
527
|
-
* @this {
|
|
528
|
-
* @param {LifecycleCallbackType<
|
|
532
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
533
|
+
* @this {MC}
|
|
534
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
529
535
|
* @returns {void}
|
|
530
536
|
*/
|
|
531
537
|
static beforeCreate(callback) {
|
|
@@ -534,9 +540,9 @@ class VelociousDatabaseRecord {
|
|
|
534
540
|
|
|
535
541
|
/**
|
|
536
542
|
* Runs before update.
|
|
537
|
-
* @template {VelociousDatabaseRecord}
|
|
538
|
-
* @this {
|
|
539
|
-
* @param {LifecycleCallbackType<
|
|
543
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
544
|
+
* @this {MC}
|
|
545
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
540
546
|
* @returns {void}
|
|
541
547
|
*/
|
|
542
548
|
static beforeUpdate(callback) {
|
|
@@ -545,9 +551,9 @@ class VelociousDatabaseRecord {
|
|
|
545
551
|
|
|
546
552
|
/**
|
|
547
553
|
* Runs before destroy.
|
|
548
|
-
* @template {VelociousDatabaseRecord}
|
|
549
|
-
* @this {
|
|
550
|
-
* @param {LifecycleCallbackType<
|
|
554
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
555
|
+
* @this {MC}
|
|
556
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
551
557
|
* @returns {void}
|
|
552
558
|
*/
|
|
553
559
|
static beforeDestroy(callback) {
|
|
@@ -556,9 +562,9 @@ class VelociousDatabaseRecord {
|
|
|
556
562
|
|
|
557
563
|
/**
|
|
558
564
|
* Runs after save.
|
|
559
|
-
* @template {VelociousDatabaseRecord}
|
|
560
|
-
* @this {
|
|
561
|
-
* @param {LifecycleCallbackType<
|
|
565
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
566
|
+
* @this {MC}
|
|
567
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
562
568
|
* @returns {void}
|
|
563
569
|
*/
|
|
564
570
|
static afterSave(callback) {
|
|
@@ -567,9 +573,9 @@ class VelociousDatabaseRecord {
|
|
|
567
573
|
|
|
568
574
|
/**
|
|
569
575
|
* Runs after create.
|
|
570
|
-
* @template {VelociousDatabaseRecord}
|
|
571
|
-
* @this {
|
|
572
|
-
* @param {LifecycleCallbackType<
|
|
576
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
577
|
+
* @this {MC}
|
|
578
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
573
579
|
* @returns {void}
|
|
574
580
|
*/
|
|
575
581
|
static afterCreate(callback) {
|
|
@@ -578,9 +584,9 @@ class VelociousDatabaseRecord {
|
|
|
578
584
|
|
|
579
585
|
/**
|
|
580
586
|
* Runs after update.
|
|
581
|
-
* @template {VelociousDatabaseRecord}
|
|
582
|
-
* @this {
|
|
583
|
-
* @param {LifecycleCallbackType<
|
|
587
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
588
|
+
* @this {MC}
|
|
589
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
584
590
|
* @returns {void}
|
|
585
591
|
*/
|
|
586
592
|
static afterUpdate(callback) {
|
|
@@ -589,9 +595,9 @@ class VelociousDatabaseRecord {
|
|
|
589
595
|
|
|
590
596
|
/**
|
|
591
597
|
* Runs after destroy.
|
|
592
|
-
* @template {VelociousDatabaseRecord}
|
|
593
|
-
* @this {
|
|
594
|
-
* @param {LifecycleCallbackType<
|
|
598
|
+
* @template {typeof VelociousDatabaseRecord} MC
|
|
599
|
+
* @this {MC}
|
|
600
|
+
* @param {LifecycleCallbackType<InstanceType<MC>>} callback - Callback function or instance method name.
|
|
595
601
|
* @returns {void}
|
|
596
602
|
*/
|
|
597
603
|
static afterDestroy(callback) {
|
|
@@ -2414,6 +2420,8 @@ class VelociousDatabaseRecord {
|
|
|
2414
2420
|
})
|
|
2415
2421
|
})
|
|
2416
2422
|
|
|
2423
|
+
this._assignedAttributeNames = undefined
|
|
2424
|
+
|
|
2417
2425
|
return result
|
|
2418
2426
|
}
|
|
2419
2427
|
|
|
@@ -2438,7 +2446,7 @@ class VelociousDatabaseRecord {
|
|
|
2438
2446
|
if (model.isChanged()) {
|
|
2439
2447
|
await model.save()
|
|
2440
2448
|
|
|
2441
|
-
const foreignKey =
|
|
2449
|
+
const foreignKey = this._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2442
2450
|
|
|
2443
2451
|
this.setAttribute(foreignKey, model.id())
|
|
2444
2452
|
|
|
@@ -2493,7 +2501,7 @@ class VelociousDatabaseRecord {
|
|
|
2493
2501
|
|
|
2494
2502
|
if (loaded) {
|
|
2495
2503
|
for (const model of loaded) {
|
|
2496
|
-
const foreignKey =
|
|
2504
|
+
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2497
2505
|
|
|
2498
2506
|
model.setAttribute(foreignKey, this.id())
|
|
2499
2507
|
|
|
@@ -2510,6 +2518,17 @@ class VelociousDatabaseRecord {
|
|
|
2510
2518
|
return relationships
|
|
2511
2519
|
}
|
|
2512
2520
|
|
|
2521
|
+
/**
|
|
2522
|
+
* Resolves a relationship foreign-key column to this model's public attribute name.
|
|
2523
|
+
* @param {import("./instance-relationships/base.js").default<typeof VelociousDatabaseRecord, typeof VelociousDatabaseRecord>} instanceRelationship - Relationship instance.
|
|
2524
|
+
* @returns {string} Attribute name accepted by setAttribute/assign.
|
|
2525
|
+
*/
|
|
2526
|
+
_relationshipForeignKeyAttribute(instanceRelationship) {
|
|
2527
|
+
const foreignKey = instanceRelationship.getForeignKey()
|
|
2528
|
+
|
|
2529
|
+
return this.getModelClass().getColumnNameToAttributeNameMap()[foreignKey] || foreignKey
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2513
2532
|
/**
|
|
2514
2533
|
* Runs auto save has many and has one relationships.
|
|
2515
2534
|
* @param {object} args - Options object.
|
|
@@ -2535,7 +2554,7 @@ class VelociousDatabaseRecord {
|
|
|
2535
2554
|
}
|
|
2536
2555
|
|
|
2537
2556
|
for (const model of loaded) {
|
|
2538
|
-
const foreignKey =
|
|
2557
|
+
const foreignKey = model._relationshipForeignKeyAttribute(instanceRelationship)
|
|
2539
2558
|
|
|
2540
2559
|
model.setAttribute(foreignKey, this.id())
|
|
2541
2560
|
|
|
@@ -3363,7 +3382,9 @@ class VelociousDatabaseRecord {
|
|
|
3363
3382
|
* @returns {void} - No return value.
|
|
3364
3383
|
*/
|
|
3365
3384
|
assign(attributesToAssign) {
|
|
3385
|
+
this._assignedAttributeNames ||= new Set()
|
|
3366
3386
|
for (const attributeToAssign in attributesToAssign) {
|
|
3387
|
+
this._assignedAttributeNames.add(attributeToAssign)
|
|
3367
3388
|
this.setAttribute(attributeToAssign, attributesToAssign[attributeToAssign])
|
|
3368
3389
|
}
|
|
3369
3390
|
}
|
|
@@ -4167,6 +4188,7 @@ class VelociousDatabaseRecord {
|
|
|
4167
4188
|
|
|
4168
4189
|
this._attributes = reloadedModel.rawAttributes()
|
|
4169
4190
|
this._changes = {}
|
|
4191
|
+
this._assignedAttributeNames = undefined
|
|
4170
4192
|
}
|
|
4171
4193
|
|
|
4172
4194
|
/**
|
|
@@ -13,7 +13,9 @@ export default class VelociousDatabaseRecordHasManyRelationship extends BaseRela
|
|
|
13
13
|
this.foreignKey = `${inflection.underscore(this.modelClass.getModelName())}_id`
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const targetModelClass = this.className || this.klass ? this.getTargetModelClass() : undefined
|
|
17
|
+
|
|
18
|
+
return targetModelClass?.getAttributeNameToColumnNameMap()[this.foreignKey] || this.foreignKey
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -13,7 +13,9 @@ export default class VelociousDatabaseRecordHasOneRelationship extends BaseRelat
|
|
|
13
13
|
this.foreignKey = `${inflection.underscore(this.modelClass.getModelName())}_id`
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const targetModelClass = this.className || this.klass ? this.getTargetModelClass() : undefined
|
|
17
|
+
|
|
18
|
+
return targetModelClass?.getAttributeNameToColumnNameMap()[this.foreignKey] || this.foreignKey
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -373,14 +373,14 @@ export default class DbGenerateFrontendModels extends BaseCommand {
|
|
|
373
373
|
|
|
374
374
|
fileContent += "\n"
|
|
375
375
|
fileContent += ` /** @returns {${attributesTypeName}[${JSON.stringify(attribute.name)}]} - Attribute value. */\n`
|
|
376
|
-
fileContent += ` ${camelizedAttribute}() { return this.readAttribute(${JSON.stringify(attribute.name)}) }\n`
|
|
376
|
+
fileContent += ` ${camelizedAttribute}() { return /** @type {${attributesTypeName}[${JSON.stringify(attribute.name)}]} */ (this.readAttribute(${JSON.stringify(attribute.name)})) }\n`
|
|
377
377
|
|
|
378
378
|
fileContent += "\n"
|
|
379
379
|
fileContent += " /**\n"
|
|
380
380
|
fileContent += ` * @param {${attributesTypeName}[${JSON.stringify(attribute.name)}]} newValue - New attribute value.\n`
|
|
381
381
|
fileContent += ` * @returns {${attributesTypeName}[${JSON.stringify(attribute.name)}]} - Assigned value.\n`
|
|
382
382
|
fileContent += " */\n"
|
|
383
|
-
fileContent += ` set${camelizedAttributeUpper}(newValue) { return this.setAttribute(${JSON.stringify(attribute.name)}, newValue) }\n`
|
|
383
|
+
fileContent += ` set${camelizedAttributeUpper}(newValue) { return /** @type {${attributesTypeName}[${JSON.stringify(attribute.name)}]} */ (this.setAttribute(${JSON.stringify(attribute.name)}, newValue)) }\n`
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
for (const methodName of Object.keys(collectionCommands)) {
|