velocious 1.0.430 → 1.0.431
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/bin/velocious.js +48 -0
- package/build/bin/velocious.js +39 -34
- package/build/index.js +1 -2
- package/build/src/application.js +214 -187
- package/build/src/authorization/ability.d.ts +24 -23
- package/build/src/authorization/ability.d.ts.map +1 -1
- package/build/src/authorization/ability.js +300 -252
- package/build/src/authorization/base-resource.d.ts +20 -26
- package/build/src/authorization/base-resource.d.ts.map +1 -1
- package/build/src/authorization/base-resource.js +136 -118
- package/build/src/background-jobs/client.js +47 -43
- package/build/src/background-jobs/cron-expression.js +166 -127
- package/build/src/background-jobs/forked-runner-child.js +47 -37
- package/build/src/background-jobs/job-record.js +10 -8
- package/build/src/background-jobs/job-registry.js +84 -72
- package/build/src/background-jobs/job-runner.js +81 -74
- package/build/src/background-jobs/job.js +72 -62
- package/build/src/background-jobs/json-socket.js +70 -65
- package/build/src/background-jobs/main.js +900 -841
- package/build/src/background-jobs/normalize-error.js +11 -12
- package/build/src/background-jobs/scheduler.js +247 -205
- package/build/src/background-jobs/socket-request.js +65 -60
- package/build/src/background-jobs/status-reporter.js +96 -86
- package/build/src/background-jobs/store.js +980 -862
- package/build/src/background-jobs/types.js +3 -2
- package/build/src/background-jobs/web/authorization.js +50 -38
- package/build/src/background-jobs/web/controller.js +268 -232
- package/build/src/background-jobs/web/index.js +40 -36
- package/build/src/background-jobs/web/path-matcher.js +48 -45
- package/build/src/background-jobs/web/registry.js +14 -9
- package/build/src/background-jobs/worker.js +639 -585
- package/build/src/beacon/client.js +293 -264
- package/build/src/beacon/in-process-broker.js +25 -20
- package/build/src/beacon/in-process-client.js +116 -104
- package/build/src/beacon/server.js +126 -110
- package/build/src/beacon/types.js +8 -2
- package/build/src/cli/base-command.js +57 -49
- package/build/src/cli/browser-cli.js +42 -37
- package/build/src/cli/commands/background-jobs-main.js +5 -5
- package/build/src/cli/commands/background-jobs-runner.js +5 -5
- package/build/src/cli/commands/background-jobs-worker.js +5 -5
- package/build/src/cli/commands/beacon.js +5 -5
- package/build/src/cli/commands/console.js +10 -10
- package/build/src/cli/commands/db/base-command.js +76 -71
- package/build/src/cli/commands/db/create.js +61 -53
- package/build/src/cli/commands/db/drop.js +71 -62
- package/build/src/cli/commands/db/migrate.js +15 -13
- package/build/src/cli/commands/db/reset.js +19 -16
- package/build/src/cli/commands/db/rollback.js +13 -12
- package/build/src/cli/commands/db/schema/dump.js +9 -9
- package/build/src/cli/commands/db/schema/load.js +9 -9
- package/build/src/cli/commands/db/seed.js +9 -9
- package/build/src/cli/commands/db/tenants/check.js +35 -32
- package/build/src/cli/commands/db/tenants/create.js +29 -26
- package/build/src/cli/commands/db/tenants/migrate.js +44 -40
- package/build/src/cli/commands/destroy/migration.js +5 -5
- package/build/src/cli/commands/generate/base-models.js +5 -5
- package/build/src/cli/commands/generate/frontend-models.js +9 -9
- package/build/src/cli/commands/generate/migration.js +5 -5
- package/build/src/cli/commands/generate/model.js +5 -5
- package/build/src/cli/commands/init.js +9 -7
- package/build/src/cli/commands/routes.js +6 -6
- package/build/src/cli/commands/run-script.js +9 -9
- package/build/src/cli/commands/runner.js +9 -9
- package/build/src/cli/commands/server.js +6 -6
- package/build/src/cli/commands/test.js +7 -6
- package/build/src/cli/index.js +141 -127
- package/build/src/cli/tenant-database-command-helper.js +185 -154
- package/build/src/cli/use-browser-cli.js +20 -15
- package/build/src/configuration-resolver.js +54 -47
- package/build/src/configuration-types.d.ts +21 -2
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +60 -3
- package/build/src/configuration.js +2547 -2240
- package/build/src/controller.js +407 -363
- package/build/src/current-configuration.js +12 -9
- package/build/src/current.js +75 -70
- package/build/src/database/annotations-async-hooks.js +22 -16
- package/build/src/database/annotations.js +18 -12
- package/build/src/database/drivers/base-column.js +179 -155
- package/build/src/database/drivers/base-columns-index.js +78 -69
- package/build/src/database/drivers/base-foreign-key.js +101 -89
- package/build/src/database/drivers/base-table.js +149 -124
- package/build/src/database/drivers/base.js +1489 -1306
- package/build/src/database/drivers/mssql/column.js +50 -39
- package/build/src/database/drivers/mssql/columns-index.js +3 -2
- package/build/src/database/drivers/mssql/connect-connection.js +9 -11
- package/build/src/database/drivers/mssql/foreign-key.js +9 -8
- package/build/src/database/drivers/mssql/index.js +587 -507
- package/build/src/database/drivers/mssql/options.js +75 -68
- package/build/src/database/drivers/mssql/query-parser.js +3 -2
- package/build/src/database/drivers/mssql/sql/alter-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/create-database.js +31 -24
- package/build/src/database/drivers/mssql/sql/create-index.js +2 -2
- package/build/src/database/drivers/mssql/sql/create-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/delete.js +16 -14
- package/build/src/database/drivers/mssql/sql/drop-database.js +31 -24
- package/build/src/database/drivers/mssql/sql/drop-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/insert.js +2 -2
- package/build/src/database/drivers/mssql/sql/update.js +28 -24
- package/build/src/database/drivers/mssql/sql/upsert.js +20 -18
- package/build/src/database/drivers/mssql/structure-sql.js +114 -102
- package/build/src/database/drivers/mssql/table.js +96 -81
- package/build/src/database/drivers/mysql/column.js +92 -75
- package/build/src/database/drivers/mysql/columns-index.js +19 -16
- package/build/src/database/drivers/mysql/foreign-key.js +9 -8
- package/build/src/database/drivers/mysql/index.js +457 -396
- package/build/src/database/drivers/mysql/options.js +30 -26
- package/build/src/database/drivers/mysql/query-parser.js +3 -2
- package/build/src/database/drivers/mysql/query.js +29 -26
- package/build/src/database/drivers/mysql/sql/alter-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/create-database.js +28 -23
- package/build/src/database/drivers/mysql/sql/create-index.js +3 -2
- package/build/src/database/drivers/mysql/sql/create-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/delete.js +17 -14
- package/build/src/database/drivers/mysql/sql/drop-database.js +3 -2
- package/build/src/database/drivers/mysql/sql/drop-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/insert.js +3 -2
- package/build/src/database/drivers/mysql/sql/update.js +29 -24
- package/build/src/database/drivers/mysql/sql/upsert.js +10 -8
- package/build/src/database/drivers/mysql/structure-sql.js +88 -79
- package/build/src/database/drivers/mysql/table.js +98 -83
- package/build/src/database/drivers/pgsql/column.js +72 -56
- package/build/src/database/drivers/pgsql/columns-index.js +3 -2
- package/build/src/database/drivers/pgsql/foreign-key.js +9 -8
- package/build/src/database/drivers/pgsql/index.js +438 -377
- package/build/src/database/drivers/pgsql/options.js +28 -25
- package/build/src/database/drivers/pgsql/query-parser.js +3 -2
- package/build/src/database/drivers/pgsql/sql/alter-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/create-database.js +23 -19
- package/build/src/database/drivers/pgsql/sql/create-index.js +3 -2
- package/build/src/database/drivers/pgsql/sql/create-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/delete.js +17 -14
- package/build/src/database/drivers/pgsql/sql/drop-database.js +3 -2
- package/build/src/database/drivers/pgsql/sql/drop-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/insert.js +3 -2
- package/build/src/database/drivers/pgsql/sql/update.js +29 -24
- package/build/src/database/drivers/pgsql/sql/upsert.js +11 -9
- package/build/src/database/drivers/pgsql/structure-sql.js +120 -108
- package/build/src/database/drivers/pgsql/table.js +77 -60
- package/build/src/database/drivers/sqlite/base.js +478 -405
- package/build/src/database/drivers/sqlite/column.js +69 -54
- package/build/src/database/drivers/sqlite/columns-index.js +27 -22
- package/build/src/database/drivers/sqlite/connection-sql-js.js +42 -35
- package/build/src/database/drivers/sqlite/foreign-key.js +21 -18
- package/build/src/database/drivers/sqlite/index.js +373 -330
- package/build/src/database/drivers/sqlite/index.native.js +64 -55
- package/build/src/database/drivers/sqlite/index.web.js +87 -69
- package/build/src/database/drivers/sqlite/options.js +28 -25
- package/build/src/database/drivers/sqlite/query-parser.js +3 -2
- package/build/src/database/drivers/sqlite/query.js +24 -21
- package/build/src/database/drivers/sqlite/query.native.js +25 -20
- package/build/src/database/drivers/sqlite/query.web.js +37 -30
- package/build/src/database/drivers/sqlite/sql/alter-table.js +179 -159
- package/build/src/database/drivers/sqlite/sql/create-index.js +3 -2
- package/build/src/database/drivers/sqlite/sql/create-table.js +3 -2
- package/build/src/database/drivers/sqlite/sql/delete.js +22 -17
- package/build/src/database/drivers/sqlite/sql/drop-table.js +3 -2
- package/build/src/database/drivers/sqlite/sql/insert.js +3 -2
- package/build/src/database/drivers/sqlite/sql/update.js +29 -24
- package/build/src/database/drivers/sqlite/sql/upsert.js +11 -9
- package/build/src/database/drivers/sqlite/structure-sql.js +52 -49
- package/build/src/database/drivers/sqlite/table-rebuilder.js +75 -62
- package/build/src/database/drivers/sqlite/table.js +125 -102
- package/build/src/database/drivers/structure-sql/utils.js +17 -14
- package/build/src/database/handler.js +10 -9
- package/build/src/database/initializer-from-require-context.js +87 -76
- package/build/src/database/migration/index.js +395 -332
- package/build/src/database/migrator/files-finder.js +50 -40
- package/build/src/database/migrator/types.js +30 -2
- package/build/src/database/migrator.js +526 -454
- package/build/src/database/pool/async-tracked-multi-connection.js +1147 -997
- package/build/src/database/pool/base-methods-forward.js +43 -40
- package/build/src/database/pool/base.js +343 -298
- package/build/src/database/pool/single-multi-use.js +110 -93
- package/build/src/database/query/alter-table-base.js +99 -84
- package/build/src/database/query/base.js +46 -39
- package/build/src/database/query/create-database-base.js +30 -25
- package/build/src/database/query/create-index-base.js +94 -75
- package/build/src/database/query/create-table-base.js +193 -151
- package/build/src/database/query/delete-base.js +16 -14
- package/build/src/database/query/drop-database-base.js +28 -23
- package/build/src/database/query/drop-table-base.js +53 -42
- package/build/src/database/query/from-base.js +33 -30
- package/build/src/database/query/from-plain.js +13 -11
- package/build/src/database/query/from-table.js +15 -13
- package/build/src/database/query/index.js +472 -410
- package/build/src/database/query/insert-base.js +164 -143
- package/build/src/database/query/join-base.js +40 -35
- package/build/src/database/query/join-object.js +153 -128
- package/build/src/database/query/join-plain.js +15 -13
- package/build/src/database/query/join-tracker.js +90 -76
- package/build/src/database/query/model-class-query.js +1370 -1134
- package/build/src/database/query/order-base.js +30 -27
- package/build/src/database/query/order-column.js +53 -44
- package/build/src/database/query/order-plain.js +24 -20
- package/build/src/database/query/preloader/belongs-to.js +258 -210
- package/build/src/database/query/preloader/ensure-model-class-initialized.js +9 -8
- package/build/src/database/query/preloader/has-many.js +301 -240
- package/build/src/database/query/preloader/has-one.js +117 -91
- package/build/src/database/query/preloader/selection.js +129 -117
- package/build/src/database/query/preloader.js +185 -160
- package/build/src/database/query/query-data.js +201 -157
- package/build/src/database/query/select-base.js +27 -25
- package/build/src/database/query/select-plain.js +15 -13
- package/build/src/database/query/select-table-and-column.js +25 -21
- package/build/src/database/query/update-base.js +38 -35
- package/build/src/database/query/upsert-base.js +100 -93
- package/build/src/database/query/where-base.js +35 -32
- package/build/src/database/query/where-combinator.d.ts.map +1 -1
- package/build/src/database/query/where-combinator.js +28 -26
- package/build/src/database/query/where-hash.js +68 -61
- package/build/src/database/query/where-model-class-hash.js +469 -414
- package/build/src/database/query/where-not.js +20 -18
- package/build/src/database/query/where-plain.js +17 -15
- package/build/src/database/query/with-count.js +159 -125
- package/build/src/database/query-parser/base-query-parser.js +37 -32
- package/build/src/database/query-parser/from-parser.js +45 -36
- package/build/src/database/query-parser/group-parser.js +50 -42
- package/build/src/database/query-parser/joins-parser.js +33 -28
- package/build/src/database/query-parser/limit-parser.js +70 -67
- package/build/src/database/query-parser/options.js +82 -75
- package/build/src/database/query-parser/order-parser.js +40 -36
- package/build/src/database/query-parser/select-parser.js +60 -49
- package/build/src/database/query-parser/where-parser.js +41 -36
- package/build/src/database/record/acts-as-list.js +273 -235
- package/build/src/database/record/attachments/download.js +45 -44
- package/build/src/database/record/attachments/handle.js +161 -141
- package/build/src/database/record/attachments/normalize-input.js +138 -128
- package/build/src/database/record/attachments/storage-drivers/filesystem.js +91 -77
- package/build/src/database/record/attachments/storage-drivers/native.js +121 -112
- package/build/src/database/record/attachments/storage-drivers/s3.js +208 -177
- package/build/src/database/record/attachments/store.d.ts +1 -1
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +540 -468
- package/build/src/database/record/index.d.ts +17 -15
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +3894 -3361
- package/build/src/database/record/instance-relationships/base.js +268 -234
- package/build/src/database/record/instance-relationships/belongs-to.js +73 -58
- package/build/src/database/record/instance-relationships/has-many.js +264 -225
- package/build/src/database/record/instance-relationships/has-one.js +105 -85
- package/build/src/database/record/record-not-found-error.js +2 -3
- package/build/src/database/record/relationships/base.d.ts +2 -2
- package/build/src/database/record/relationships/base.d.ts.map +1 -1
- package/build/src/database/record/relationships/base.js +167 -145
- package/build/src/database/record/relationships/belongs-to.js +51 -44
- package/build/src/database/record/relationships/has-many.js +40 -32
- package/build/src/database/record/relationships/has-one.js +40 -32
- package/build/src/database/record/state-machine.js +208 -156
- package/build/src/database/record/user-module.js +38 -32
- package/build/src/database/record/validators/base.js +24 -22
- package/build/src/database/record/validators/format.js +46 -36
- package/build/src/database/record/validators/presence.js +20 -18
- package/build/src/database/record/validators/uniqueness.js +117 -99
- package/build/src/database/table-data/index.js +231 -199
- package/build/src/database/table-data/table-column.js +382 -338
- package/build/src/database/table-data/table-foreign-key.js +66 -57
- package/build/src/database/table-data/table-index.js +36 -29
- package/build/src/database/table-data/table-reference.js +10 -10
- package/build/src/database/use-database.js +40 -32
- package/build/src/environment-handlers/base.js +544 -484
- package/build/src/environment-handlers/browser.js +294 -241
- package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +19 -16
- package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +21 -18
- package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +29 -22
- package/build/src/environment-handlers/node/cli/commands/beacon.js +19 -16
- package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +15 -14
- package/build/src/environment-handlers/node/cli/commands/console.js +120 -99
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +39 -34
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +63 -57
- package/build/src/environment-handlers/node/cli/commands/db/seed.js +63 -51
- package/build/src/environment-handlers/node/cli/commands/destroy/migration.js +40 -32
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +353 -298
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +844 -729
- package/build/src/environment-handlers/node/cli/commands/generate/migration.js +38 -34
- package/build/src/environment-handlers/node/cli/commands/generate/model.js +38 -34
- package/build/src/environment-handlers/node/cli/commands/init.js +61 -56
- package/build/src/environment-handlers/node/cli/commands/routes.js +59 -51
- package/build/src/environment-handlers/node/cli/commands/run-script.js +68 -54
- package/build/src/environment-handlers/node/cli/commands/runner.js +74 -56
- package/build/src/environment-handlers/node/cli/commands/server.js +106 -93
- package/build/src/environment-handlers/node/cli/commands/test.js +113 -97
- package/build/src/environment-handlers/node.js +874 -753
- package/build/src/error-logger.js +21 -22
- package/build/src/frontend-model-controller.d.ts +6 -6
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +3288 -2788
- package/build/src/frontend-model-resource/base-resource.d.ts +18 -17
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +869 -759
- package/build/src/frontend-models/base.d.ts +19 -12
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +3602 -3114
- package/build/src/frontend-models/clear-pending-debounced-callback.js +8 -7
- package/build/src/frontend-models/event-hook-models.js +21 -16
- package/build/src/frontend-models/model-registry.js +11 -9
- package/build/src/frontend-models/outgoing-event-buffer.js +17 -10
- package/build/src/frontend-models/preloader.d.ts +6 -6
- package/build/src/frontend-models/preloader.d.ts.map +1 -1
- package/build/src/frontend-models/preloader.js +149 -131
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +1855 -1560
- package/build/src/frontend-models/resource-config-validation.js +37 -27
- package/build/src/frontend-models/resource-definition.js +288 -234
- package/build/src/frontend-models/transport-serialization.js +266 -203
- package/build/src/frontend-models/use-created-event.js +7 -5
- package/build/src/frontend-models/use-destroyed-event.js +93 -80
- package/build/src/frontend-models/use-model-class-event.js +91 -79
- package/build/src/frontend-models/use-updated-event.js +97 -84
- package/build/src/frontend-models/websocket-channel.js +441 -381
- package/build/src/frontend-models/websocket-publishers.js +173 -140
- package/build/src/http-client/header.js +14 -13
- package/build/src/http-client/index.js +132 -116
- package/build/src/http-client/request.js +87 -71
- package/build/src/http-client/response.js +140 -122
- package/build/src/http-client/websocket-client.js +17 -15
- package/build/src/http-server/client/index.js +465 -409
- package/build/src/http-server/client/params-to-object.js +135 -124
- package/build/src/http-server/client/request-buffer/form-data-part.js +132 -111
- package/build/src/http-server/client/request-buffer/header.js +16 -15
- package/build/src/http-server/client/request-buffer/index.js +506 -446
- package/build/src/http-server/client/request-parser.js +186 -163
- package/build/src/http-server/client/request-runner.js +259 -226
- package/build/src/http-server/client/request-timing.js +151 -132
- package/build/src/http-server/client/request.js +108 -96
- package/build/src/http-server/client/response.js +235 -213
- package/build/src/http-server/client/uploaded-file/memory-uploaded-file.js +29 -25
- package/build/src/http-server/client/uploaded-file/temporary-uploaded-file.js +29 -25
- package/build/src/http-server/client/uploaded-file/uploaded-file.js +33 -33
- package/build/src/http-server/client/websocket-request.js +137 -114
- package/build/src/http-server/client/websocket-session.js +1657 -1452
- package/build/src/http-server/cookie.js +236 -216
- package/build/src/http-server/development-reloader.js +221 -190
- package/build/src/http-server/index.js +525 -451
- package/build/src/http-server/remote-address.js +50 -38
- package/build/src/http-server/server-client.js +208 -181
- package/build/src/http-server/server-lock.js +167 -153
- package/build/src/http-server/websocket-channel-subscribers.js +93 -81
- package/build/src/http-server/websocket-channel.js +117 -104
- package/build/src/http-server/websocket-connection.js +104 -96
- package/build/src/http-server/websocket-event-log-store.js +404 -350
- package/build/src/http-server/websocket-events-host.js +164 -145
- package/build/src/http-server/websocket-events.js +47 -47
- package/build/src/http-server/worker-handler/channel-subscriber-dispatch.js +14 -13
- package/build/src/http-server/worker-handler/in-process.js +141 -123
- package/build/src/http-server/worker-handler/index.js +349 -313
- package/build/src/http-server/worker-handler/worker-script.js +5 -4
- package/build/src/http-server/worker-handler/worker-thread.js +269 -240
- package/build/src/initializer.js +36 -31
- package/build/src/jobs/mail-delivery.js +15 -13
- package/build/src/logger/base-logger.js +26 -24
- package/build/src/logger/console-logger.js +23 -21
- package/build/src/logger/file-logger.js +31 -29
- package/build/src/logger/outputs/array-output.js +42 -37
- package/build/src/logger/outputs/console-output.js +24 -20
- package/build/src/logger/outputs/file-output.js +48 -43
- package/build/src/logger/outputs/stdout-output.js +48 -39
- package/build/src/logger.js +394 -338
- package/build/src/mailer/backends/smtp.js +163 -134
- package/build/src/mailer/base.js +251 -211
- package/build/src/mailer/delivery.js +64 -56
- package/build/src/mailer/index.js +22 -4
- package/build/src/mailer.js +13 -4
- package/build/src/plugins/sqljs-wasm-route-controller.js +52 -42
- package/build/src/plugins/sqljs-wasm-route.js +38 -28
- package/build/src/record-payload-values.js +28 -25
- package/build/src/routes/app-routes.js +14 -12
- package/build/src/routes/base-route.js +130 -112
- package/build/src/routes/basic-route.js +102 -83
- package/build/src/routes/built-in/debug/controller.js +10 -10
- package/build/src/routes/built-in/errors/controller.js +5 -5
- package/build/src/routes/get-route.js +63 -50
- package/build/src/routes/hooks/frontend-model-command-route-hook.js +80 -66
- package/build/src/routes/index.js +43 -36
- package/build/src/routes/namespace-route.js +47 -38
- package/build/src/routes/plugin-routes.js +124 -107
- package/build/src/routes/post-route.js +62 -51
- package/build/src/routes/resolver.js +494 -422
- package/build/src/routes/resource-route.js +143 -124
- package/build/src/routes/root-route.js +8 -7
- package/build/src/testing/base-expect.js +14 -13
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +405 -329
- package/build/src/testing/browser-test-app.js +29 -23
- package/build/src/testing/expect-to-change.js +50 -41
- package/build/src/testing/expect-utils.js +184 -139
- package/build/src/testing/expect.js +731 -638
- package/build/src/testing/request-client.js +85 -70
- package/build/src/testing/test-files-finder.js +339 -285
- package/build/src/testing/test-filter-parser.js +155 -124
- package/build/src/testing/test-runner.js +1020 -883
- package/build/src/testing/test-suite-splitter.js +142 -114
- package/build/src/testing/test.js +256 -216
- package/build/src/utils/backtrace-cleaner-node.js +69 -62
- package/build/src/utils/backtrace-cleaner.js +216 -188
- package/build/src/utils/ensure-error.js +7 -7
- package/build/src/utils/event-emitter.js +6 -4
- package/build/src/utils/file-exists.js +10 -9
- package/build/src/utils/format-value.js +76 -67
- package/build/src/utils/model-scope.js +31 -27
- package/build/src/utils/nest-callbacks.js +13 -10
- package/build/src/utils/plain-object.js +6 -5
- package/build/src/utils/ransack.d.ts.map +1 -1
- package/build/src/utils/ransack.js +563 -449
- package/build/src/utils/rest-args-error.js +6 -5
- package/build/src/utils/singularize-model-name.js +11 -9
- package/build/src/utils/split-sql-statements.js +79 -68
- package/build/src/utils/to-import-specifier.js +30 -24
- package/build/src/utils/with-tracked-stack-async-hooks.js +74 -60
- package/build/src/utils/with-tracked-stack.js +18 -14
- package/build/src/velocious-error.js +30 -27
- package/index.js +1 -0
- package/package.json +10 -4
- package/scripts/clean-build.js +8 -0
- package/scripts/ensure-bin-executable.js +13 -0
- package/scripts/run-tests.js +37 -0
- package/scripts/test-browser.js +486 -0
- package/src/application.js +229 -0
- package/src/authorization/ability.js +329 -0
- package/src/authorization/base-resource.js +143 -0
- package/src/background-jobs/client.js +50 -0
- package/src/background-jobs/cron-expression.js +277 -0
- package/src/background-jobs/forked-runner-child.js +86 -0
- package/src/background-jobs/job-record.js +13 -0
- package/src/background-jobs/job-registry.js +92 -0
- package/src/background-jobs/job-runner.js +107 -0
- package/src/background-jobs/job.js +77 -0
- package/src/background-jobs/json-socket.js +78 -0
- package/src/background-jobs/main.js +926 -0
- package/src/background-jobs/normalize-error.js +26 -0
- package/src/background-jobs/scheduler.js +274 -0
- package/src/background-jobs/socket-request.js +68 -0
- package/src/background-jobs/status-reporter.js +101 -0
- package/src/background-jobs/store.js +994 -0
- package/src/background-jobs/types.js +70 -0
- package/src/background-jobs/web/authorization.js +89 -0
- package/src/background-jobs/web/controller.js +280 -0
- package/src/background-jobs/web/index.js +57 -0
- package/src/background-jobs/web/path-matcher.js +74 -0
- package/src/background-jobs/web/registry.js +49 -0
- package/src/background-jobs/worker.js +683 -0
- package/src/beacon/client.js +330 -0
- package/src/beacon/in-process-broker.js +71 -0
- package/src/beacon/in-process-client.js +139 -0
- package/src/beacon/server.js +148 -0
- package/src/beacon/types.js +55 -0
- package/src/cli/base-command.js +67 -0
- package/src/cli/browser-cli.js +45 -0
- package/src/cli/commands/background-jobs-main.js +7 -0
- package/src/cli/commands/background-jobs-runner.js +7 -0
- package/src/cli/commands/background-jobs-worker.js +7 -0
- package/src/cli/commands/beacon.js +7 -0
- package/src/cli/commands/console.js +12 -0
- package/src/cli/commands/db/base-command.js +82 -0
- package/src/cli/commands/db/create.js +64 -0
- package/src/cli/commands/db/drop.js +75 -0
- package/src/cli/commands/db/migrate.js +17 -0
- package/src/cli/commands/db/reset.js +22 -0
- package/src/cli/commands/db/rollback.js +15 -0
- package/src/cli/commands/db/schema/dump.js +12 -0
- package/src/cli/commands/db/schema/load.js +12 -0
- package/src/cli/commands/db/seed.js +12 -0
- package/src/cli/commands/db/tenants/check.js +38 -0
- package/src/cli/commands/db/tenants/create.js +33 -0
- package/src/cli/commands/db/tenants/migrate.js +49 -0
- package/src/cli/commands/destroy/migration.js +7 -0
- package/src/cli/commands/generate/base-models.js +7 -0
- package/src/cli/commands/generate/frontend-models.js +12 -0
- package/src/cli/commands/generate/migration.js +7 -0
- package/src/cli/commands/generate/model.js +7 -0
- package/src/cli/commands/init.js +11 -0
- package/src/cli/commands/routes.js +7 -0
- package/src/cli/commands/run-script.js +12 -0
- package/src/cli/commands/runner.js +12 -0
- package/src/cli/commands/server.js +7 -0
- package/src/cli/commands/test.js +9 -0
- package/src/cli/index.js +152 -0
- package/src/cli/tenant-database-command-helper.js +198 -0
- package/src/cli/use-browser-cli.js +30 -0
- package/src/configuration-resolver.js +65 -0
- package/src/configuration-types.js +429 -0
- package/src/configuration.js +2590 -0
- package/src/controller.js +421 -0
- package/src/current-configuration.js +31 -0
- package/src/current.js +80 -0
- package/src/database/annotations-async-hooks.js +47 -0
- package/src/database/annotations.js +40 -0
- package/src/database/drivers/base-column.js +182 -0
- package/src/database/drivers/base-columns-index.js +81 -0
- package/src/database/drivers/base-foreign-key.js +104 -0
- package/src/database/drivers/base-table.js +156 -0
- package/src/database/drivers/base.js +1609 -0
- package/src/database/drivers/mssql/column.js +74 -0
- package/src/database/drivers/mssql/columns-index.js +6 -0
- package/src/database/drivers/mssql/connect-connection.js +16 -0
- package/src/database/drivers/mssql/foreign-key.js +12 -0
- package/src/database/drivers/mssql/index.js +590 -0
- package/src/database/drivers/mssql/options.js +79 -0
- package/src/database/drivers/mssql/query-parser.js +6 -0
- package/src/database/drivers/mssql/sql/alter-table.js +4 -0
- package/src/database/drivers/mssql/sql/create-database.js +36 -0
- package/src/database/drivers/mssql/sql/create-index.js +4 -0
- package/src/database/drivers/mssql/sql/create-table.js +4 -0
- package/src/database/drivers/mssql/sql/delete.js +19 -0
- package/src/database/drivers/mssql/sql/drop-database.js +36 -0
- package/src/database/drivers/mssql/sql/drop-table.js +4 -0
- package/src/database/drivers/mssql/sql/insert.js +4 -0
- package/src/database/drivers/mssql/sql/update.js +31 -0
- package/src/database/drivers/mssql/sql/upsert.js +23 -0
- package/src/database/drivers/mssql/structure-sql.js +120 -0
- package/src/database/drivers/mssql/table.js +145 -0
- package/src/database/drivers/mysql/column.js +112 -0
- package/src/database/drivers/mysql/columns-index.js +22 -0
- package/src/database/drivers/mysql/foreign-key.js +12 -0
- package/src/database/drivers/mysql/index.js +473 -0
- package/src/database/drivers/mysql/options.js +34 -0
- package/src/database/drivers/mysql/query-parser.js +6 -0
- package/src/database/drivers/mysql/query.js +37 -0
- package/src/database/drivers/mysql/sql/alter-table.js +6 -0
- package/src/database/drivers/mysql/sql/create-database.js +39 -0
- package/src/database/drivers/mysql/sql/create-index.js +6 -0
- package/src/database/drivers/mysql/sql/create-table.js +6 -0
- package/src/database/drivers/mysql/sql/delete.js +21 -0
- package/src/database/drivers/mysql/sql/drop-database.js +6 -0
- package/src/database/drivers/mysql/sql/drop-table.js +6 -0
- package/src/database/drivers/mysql/sql/insert.js +6 -0
- package/src/database/drivers/mysql/sql/update.js +33 -0
- package/src/database/drivers/mysql/sql/upsert.js +13 -0
- package/src/database/drivers/mysql/structure-sql.js +93 -0
- package/src/database/drivers/mysql/table.js +121 -0
- package/src/database/drivers/pgsql/column.js +90 -0
- package/src/database/drivers/pgsql/columns-index.js +6 -0
- package/src/database/drivers/pgsql/foreign-key.js +12 -0
- package/src/database/drivers/pgsql/index.js +441 -0
- package/src/database/drivers/pgsql/options.js +32 -0
- package/src/database/drivers/pgsql/query-parser.js +6 -0
- package/src/database/drivers/pgsql/sql/alter-table.js +6 -0
- package/src/database/drivers/pgsql/sql/create-database.js +38 -0
- package/src/database/drivers/pgsql/sql/create-index.js +6 -0
- package/src/database/drivers/pgsql/sql/create-table.js +6 -0
- package/src/database/drivers/pgsql/sql/delete.js +21 -0
- package/src/database/drivers/pgsql/sql/drop-database.js +6 -0
- package/src/database/drivers/pgsql/sql/drop-table.js +6 -0
- package/src/database/drivers/pgsql/sql/insert.js +6 -0
- package/src/database/drivers/pgsql/sql/update.js +33 -0
- package/src/database/drivers/pgsql/sql/upsert.js +14 -0
- package/src/database/drivers/pgsql/structure-sql.js +126 -0
- package/src/database/drivers/pgsql/table.js +135 -0
- package/src/database/drivers/sqlite/base.js +509 -0
- package/src/database/drivers/sqlite/column.js +75 -0
- package/src/database/drivers/sqlite/columns-index.js +30 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +46 -0
- package/src/database/drivers/sqlite/foreign-key.js +24 -0
- package/src/database/drivers/sqlite/index.js +394 -0
- package/src/database/drivers/sqlite/index.native.js +72 -0
- package/src/database/drivers/sqlite/index.web.js +99 -0
- package/src/database/drivers/sqlite/options.js +32 -0
- package/src/database/drivers/sqlite/query-parser.js +6 -0
- package/src/database/drivers/sqlite/query.js +35 -0
- package/src/database/drivers/sqlite/query.native.js +35 -0
- package/src/database/drivers/sqlite/query.web.js +49 -0
- package/src/database/drivers/sqlite/sql/alter-table.js +187 -0
- package/src/database/drivers/sqlite/sql/create-index.js +6 -0
- package/src/database/drivers/sqlite/sql/create-table.js +6 -0
- package/src/database/drivers/sqlite/sql/delete.js +26 -0
- package/src/database/drivers/sqlite/sql/drop-table.js +6 -0
- package/src/database/drivers/sqlite/sql/insert.js +6 -0
- package/src/database/drivers/sqlite/sql/update.js +33 -0
- package/src/database/drivers/sqlite/sql/upsert.js +14 -0
- package/src/database/drivers/sqlite/structure-sql.js +56 -0
- package/src/database/drivers/sqlite/table-rebuilder.js +96 -0
- package/src/database/drivers/sqlite/table.js +131 -0
- package/src/database/drivers/structure-sql/utils.js +35 -0
- package/src/database/handler.js +13 -0
- package/src/database/initializer-from-require-context.js +101 -0
- package/src/database/migration/index.js +438 -0
- package/src/database/migrator/files-finder.js +55 -0
- package/src/database/migrator/types.js +31 -0
- package/src/database/migrator.js +557 -0
- package/src/database/pool/async-tracked-multi-connection.js +1164 -0
- package/src/database/pool/base-methods-forward.js +52 -0
- package/src/database/pool/base.js +380 -0
- package/src/database/pool/single-multi-use.js +118 -0
- package/src/database/query/alter-table-base.js +104 -0
- package/src/database/query/base.js +49 -0
- package/src/database/query/create-database-base.js +42 -0
- package/src/database/query/create-index-base.js +117 -0
- package/src/database/query/create-table-base.js +205 -0
- package/src/database/query/delete-base.js +19 -0
- package/src/database/query/drop-database-base.js +38 -0
- package/src/database/query/drop-table-base.js +58 -0
- package/src/database/query/from-base.js +36 -0
- package/src/database/query/from-plain.js +16 -0
- package/src/database/query/from-table.js +18 -0
- package/src/database/query/index.js +533 -0
- package/src/database/query/insert-base.js +172 -0
- package/src/database/query/join-base.js +43 -0
- package/src/database/query/join-object.js +167 -0
- package/src/database/query/join-plain.js +18 -0
- package/src/database/query/join-tracker.js +93 -0
- package/src/database/query/model-class-query.js +1577 -0
- package/src/database/query/order-base.js +33 -0
- package/src/database/query/order-column.js +77 -0
- package/src/database/query/order-plain.js +28 -0
- package/src/database/query/preloader/belongs-to.js +267 -0
- package/src/database/query/preloader/ensure-model-class-initialized.js +18 -0
- package/src/database/query/preloader/has-many.js +316 -0
- package/src/database/query/preloader/has-one.js +123 -0
- package/src/database/query/preloader/selection.js +152 -0
- package/src/database/query/preloader.js +201 -0
- package/src/database/query/query-data.js +305 -0
- package/src/database/query/select-base.js +30 -0
- package/src/database/query/select-plain.js +18 -0
- package/src/database/query/select-table-and-column.js +28 -0
- package/src/database/query/update-base.js +41 -0
- package/src/database/query/upsert-base.js +103 -0
- package/src/database/query/where-base.js +38 -0
- package/src/database/query/where-combinator.js +31 -0
- package/src/database/query/where-hash.js +77 -0
- package/src/database/query/where-model-class-hash.js +505 -0
- package/src/database/query/where-not.js +23 -0
- package/src/database/query/where-plain.js +20 -0
- package/src/database/query/with-count.js +219 -0
- package/src/database/query-parser/base-query-parser.js +40 -0
- package/src/database/query-parser/from-parser.js +49 -0
- package/src/database/query-parser/group-parser.js +55 -0
- package/src/database/query-parser/joins-parser.js +37 -0
- package/src/database/query-parser/limit-parser.js +77 -0
- package/src/database/query-parser/options.js +94 -0
- package/src/database/query-parser/order-parser.js +45 -0
- package/src/database/query-parser/select-parser.js +67 -0
- package/src/database/query-parser/where-parser.js +46 -0
- package/src/database/record/acts-as-list.js +374 -0
- package/src/database/record/attachments/download.js +49 -0
- package/src/database/record/attachments/handle.js +188 -0
- package/src/database/record/attachments/normalize-input.js +213 -0
- package/src/database/record/attachments/storage-drivers/filesystem.js +114 -0
- package/src/database/record/attachments/storage-drivers/native.js +146 -0
- package/src/database/record/attachments/storage-drivers/s3.js +245 -0
- package/src/database/record/attachments/store.js +591 -0
- package/src/database/record/index.js +3970 -0
- package/src/database/record/instance-relationships/base.js +289 -0
- package/src/database/record/instance-relationships/belongs-to.js +84 -0
- package/src/database/record/instance-relationships/has-many.js +284 -0
- package/src/database/record/instance-relationships/has-one.js +117 -0
- package/src/database/record/record-not-found-error.js +3 -0
- package/src/database/record/relationships/base.js +195 -0
- package/src/database/record/relationships/belongs-to.js +57 -0
- package/src/database/record/relationships/has-many.js +46 -0
- package/src/database/record/relationships/has-one.js +46 -0
- package/src/database/record/state-machine.js +278 -0
- package/src/database/record/user-module.js +43 -0
- package/src/database/record/validators/base.js +27 -0
- package/src/database/record/validators/format.js +50 -0
- package/src/database/record/validators/presence.js +24 -0
- package/src/database/record/validators/uniqueness.js +124 -0
- package/src/database/table-data/index.js +241 -0
- package/src/database/table-data/table-column.js +416 -0
- package/src/database/table-data/table-foreign-key.js +69 -0
- package/src/database/table-data/table-index.js +46 -0
- package/src/database/table-data/table-reference.js +13 -0
- package/src/database/use-database.js +48 -0
- package/src/environment-handlers/base.js +561 -0
- package/src/environment-handlers/browser.js +338 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
- package/src/environment-handlers/node/cli/commands/beacon.js +21 -0
- package/src/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
- package/src/environment-handlers/node/cli/commands/console.js +149 -0
- package/src/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
- package/src/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
- package/src/environment-handlers/node/cli/commands/db/seed.js +79 -0
- package/src/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +367 -0
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
- package/src/environment-handlers/node/cli/commands/generate/migration.js +45 -0
- package/src/environment-handlers/node/cli/commands/generate/model.js +45 -0
- package/src/environment-handlers/node/cli/commands/init.js +68 -0
- package/src/environment-handlers/node/cli/commands/routes.js +63 -0
- package/src/environment-handlers/node/cli/commands/run-script.js +85 -0
- package/src/environment-handlers/node/cli/commands/runner.js +84 -0
- package/src/environment-handlers/node/cli/commands/server.js +151 -0
- package/src/environment-handlers/node/cli/commands/test.js +118 -0
- package/src/environment-handlers/node.js +887 -0
- package/src/error-logger.js +30 -0
- package/src/frontend-model-controller.js +3491 -0
- package/src/frontend-model-resource/base-resource.js +935 -0
- package/src/frontend-models/base.js +4004 -0
- package/src/frontend-models/clear-pending-debounced-callback.js +16 -0
- package/src/frontend-models/event-hook-models.js +49 -0
- package/src/frontend-models/model-registry.js +28 -0
- package/src/frontend-models/outgoing-event-buffer.js +51 -0
- package/src/frontend-models/preloader.js +169 -0
- package/src/frontend-models/query.js +2245 -0
- package/src/frontend-models/resource-config-validation.js +56 -0
- package/src/frontend-models/resource-definition.js +399 -0
- package/src/frontend-models/transport-serialization.js +369 -0
- package/src/frontend-models/use-created-event.js +21 -0
- package/src/frontend-models/use-destroyed-event.js +148 -0
- package/src/frontend-models/use-model-class-event.js +164 -0
- package/src/frontend-models/use-updated-event.js +152 -0
- package/src/frontend-models/websocket-channel.js +494 -0
- package/src/frontend-models/websocket-publishers.js +224 -0
- package/src/http-client/header.js +17 -0
- package/src/http-client/index.js +139 -0
- package/src/http-client/request.js +94 -0
- package/src/http-client/response.js +151 -0
- package/src/http-client/websocket-client.js +27 -0
- package/src/http-server/client/index.js +507 -0
- package/src/http-server/client/params-to-object.js +152 -0
- package/src/http-server/client/request-buffer/form-data-part.js +139 -0
- package/src/http-server/client/request-buffer/header.js +19 -0
- package/src/http-server/client/request-buffer/index.js +535 -0
- package/src/http-server/client/request-parser.js +195 -0
- package/src/http-server/client/request-runner.js +321 -0
- package/src/http-server/client/request-timing.js +171 -0
- package/src/http-server/client/request.js +114 -0
- package/src/http-server/client/response.js +251 -0
- package/src/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
- package/src/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
- package/src/http-server/client/uploaded-file/uploaded-file.js +36 -0
- package/src/http-server/client/websocket-request.js +147 -0
- package/src/http-server/client/websocket-session.js +1755 -0
- package/src/http-server/cookie.js +245 -0
- package/src/http-server/development-reloader.js +240 -0
- package/src/http-server/index.js +561 -0
- package/src/http-server/remote-address.js +77 -0
- package/src/http-server/server-client.js +222 -0
- package/src/http-server/server-lock.js +178 -0
- package/src/http-server/websocket-channel-subscribers.js +110 -0
- package/src/http-server/websocket-channel.js +137 -0
- package/src/http-server/websocket-connection.js +118 -0
- package/src/http-server/websocket-event-log-store.js +433 -0
- package/src/http-server/websocket-events-host.js +170 -0
- package/src/http-server/websocket-events.js +50 -0
- package/src/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
- package/src/http-server/worker-handler/in-process.js +155 -0
- package/src/http-server/worker-handler/index.js +370 -0
- package/src/http-server/worker-handler/worker-script.js +6 -0
- package/src/http-server/worker-handler/worker-thread.js +286 -0
- package/src/initializer.js +39 -0
- package/src/jobs/.gitkeep +1 -0
- package/src/jobs/mail-delivery.js +22 -0
- package/src/logger/base-logger.js +34 -0
- package/src/logger/console-logger.js +28 -0
- package/src/logger/file-logger.js +36 -0
- package/src/logger/outputs/array-output.js +50 -0
- package/src/logger/outputs/console-output.js +32 -0
- package/src/logger/outputs/file-output.js +55 -0
- package/src/logger/outputs/stdout-output.js +64 -0
- package/src/logger.js +507 -0
- package/src/mailer/backends/smtp.js +197 -0
- package/src/mailer/base.js +337 -0
- package/src/mailer/delivery.js +70 -0
- package/src/mailer/index.js +24 -0
- package/src/mailer.js +15 -0
- package/src/plugins/sqljs-wasm-route-controller.js +70 -0
- package/src/plugins/sqljs-wasm-route.js +71 -0
- package/src/record-payload-values.js +83 -0
- package/src/routes/app-routes.js +17 -0
- package/src/routes/base-route.js +133 -0
- package/src/routes/basic-route.js +109 -0
- package/src/routes/built-in/debug/controller.js +12 -0
- package/src/routes/built-in/errors/controller.js +7 -0
- package/src/routes/built-in/errors/not-found.ejs +1 -0
- package/src/routes/get-route.js +75 -0
- package/src/routes/hooks/frontend-model-command-route-hook.js +100 -0
- package/src/routes/index.js +50 -0
- package/src/routes/namespace-route.js +51 -0
- package/src/routes/plugin-routes.js +141 -0
- package/src/routes/post-route.js +74 -0
- package/src/routes/resolver.js +535 -0
- package/src/routes/resource-route.js +154 -0
- package/src/routes/root-route.js +11 -0
- package/src/templates/configuration.js +61 -0
- package/src/templates/generate-migration.js +11 -0
- package/src/templates/generate-model.js +6 -0
- package/src/templates/routes.js +11 -0
- package/src/testing/base-expect.js +17 -0
- package/src/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
- package/src/testing/browser-test-app.js +32 -0
- package/src/testing/expect-to-change.js +55 -0
- package/src/testing/expect-utils.js +269 -0
- package/src/testing/expect.js +763 -0
- package/src/testing/request-client.js +90 -0
- package/src/testing/test-files-finder.js +364 -0
- package/src/testing/test-filter-parser.js +198 -0
- package/src/testing/test-runner.js +1168 -0
- package/src/testing/test-suite-splitter.js +177 -0
- package/src/testing/test.js +370 -0
- package/src/types/external-modules.d.ts +57 -0
- package/src/utils/backtrace-cleaner-node.js +87 -0
- package/src/utils/backtrace-cleaner.js +266 -0
- package/src/utils/ensure-error.js +15 -0
- package/src/utils/event-emitter.js +8 -0
- package/src/utils/file-exists.js +18 -0
- package/src/utils/format-value.js +101 -0
- package/src/utils/model-scope.js +56 -0
- package/src/utils/nest-callbacks.js +22 -0
- package/src/utils/plain-object.js +14 -0
- package/src/utils/ransack.js +859 -0
- package/src/utils/rest-args-error.js +14 -0
- package/src/utils/singularize-model-name.js +18 -0
- package/src/utils/split-sql-statements.js +88 -0
- package/src/utils/to-import-specifier.js +53 -0
- package/src/utils/with-tracked-stack-async-hooks.js +103 -0
- package/src/utils/with-tracked-stack.js +38 -0
- package/src/velocious-error.js +34 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,1577 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {incorporate} from "incorporator"
|
|
4
|
+
import * as inflection from "inflection"
|
|
5
|
+
import {isPlainObject} from "is-plain-object"
|
|
6
|
+
import Logger from "../../logger.js"
|
|
7
|
+
import Preloader from "./preloader.js"
|
|
8
|
+
import {normalizeQueryDataSpec, runQueryData} from "./query-data.js"
|
|
9
|
+
import {normalizeWithCount, runWithCount} from "./with-count.js"
|
|
10
|
+
import DatabaseQuery from "./index.js"
|
|
11
|
+
import JoinObject from "./join-object.js"
|
|
12
|
+
import JoinPlain from "./join-plain.js"
|
|
13
|
+
import JoinTracker from "./join-tracker.js"
|
|
14
|
+
import RecordNotFoundError from "../record/record-not-found-error.js"
|
|
15
|
+
import {normalizeRansackGroup, parseRansackSort} from "../../utils/ransack.js"
|
|
16
|
+
import {isModelScopeDescriptor} from "../../utils/model-scope.js"
|
|
17
|
+
import WhereCombinator from "./where-combinator.js"
|
|
18
|
+
import WhereModelClassHash from "./where-model-class-hash.js"
|
|
19
|
+
import WhereNot from "./where-not.js"
|
|
20
|
+
import JoinsParser from "../query-parser/joins-parser.js"
|
|
21
|
+
import WhereParser from "../query-parser/where-parser.js"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Runs unquote sql identifier.
|
|
25
|
+
* @param {string} value - Potentially quoted SQL identifier.
|
|
26
|
+
* @returns {string} - Unquoted identifier.
|
|
27
|
+
*/
|
|
28
|
+
function unquoteSqlIdentifier(value) {
|
|
29
|
+
const trimmed = value.trim()
|
|
30
|
+
|
|
31
|
+
if (trimmed.length >= 2 && ((trimmed.startsWith("`") && trimmed.endsWith("`")) || (trimmed.startsWith("\"") && trimmed.endsWith("\"")))) {
|
|
32
|
+
return trimmed.slice(1, -1)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (trimmed.length >= 2 && trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
36
|
+
return trimmed.slice(1, -1)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return trimmed
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Runs parse from plain table reference.
|
|
44
|
+
* @param {string} fromPlain - FROM clause source.
|
|
45
|
+
* @returns {string | null} - Parsed table reference or null when unsupported.
|
|
46
|
+
*/
|
|
47
|
+
function parseFromPlainTableReference(fromPlain) {
|
|
48
|
+
const trimmed = fromPlain.trim()
|
|
49
|
+
|
|
50
|
+
if (trimmed.length < 1) return null
|
|
51
|
+
|
|
52
|
+
const aliasMatch = trimmed.match(/(?:^|\s)(?:AS\s+)?([`"]?[a-zA-Z_][a-zA-Z0-9_]*[`"]?|\[[a-zA-Z_][a-zA-Z0-9_]*\])\s*$/i)
|
|
53
|
+
|
|
54
|
+
if (!aliasMatch || !aliasMatch[1]) return null
|
|
55
|
+
|
|
56
|
+
return unquoteSqlIdentifier(aliasMatch[1])
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Runs normalize scope path.
|
|
61
|
+
* @param {string | string[]} path - Scope path input.
|
|
62
|
+
* @returns {string[]} - Normalized path.
|
|
63
|
+
*/
|
|
64
|
+
function normalizeScopePath(path) {
|
|
65
|
+
if (typeof path === "string") {
|
|
66
|
+
if (path.length < 1) throw new Error("Scope path strings must be non-empty")
|
|
67
|
+
|
|
68
|
+
return [path]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!Array.isArray(path)) {
|
|
72
|
+
throw new Error(`Invalid scope path type: ${typeof path}`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const entry of path) {
|
|
76
|
+
if (typeof entry !== "string" || entry.length < 1) {
|
|
77
|
+
throw new Error("Scope path entries must be non-empty strings")
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return [...path]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Deep-copies a preload select map (keyed by model name with attribute arrays)
|
|
86
|
+
* so a cloned query's selections can be mutated without affecting the original.
|
|
87
|
+
* @param {Record<string, string[]>} map - Preload select map to copy.
|
|
88
|
+
* @returns {Record<string, string[]>} - A copy with independent arrays.
|
|
89
|
+
*/
|
|
90
|
+
function clonePreloadSelectMap(map) {
|
|
91
|
+
/**
|
|
92
|
+
* Result.
|
|
93
|
+
@type {Record<string, string[]>} */
|
|
94
|
+
const result = {}
|
|
95
|
+
|
|
96
|
+
for (const [modelName, attributes] of Object.entries(map)) {
|
|
97
|
+
result[modelName] = [...attributes]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Runs normalize preload record.
|
|
105
|
+
* @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} preload - Preload data in shorthand or nested form.
|
|
106
|
+
* @returns {import("./index.js").NestedPreloadRecord} - Normalized preload record.
|
|
107
|
+
*/
|
|
108
|
+
function normalizePreloadRecord(preload) {
|
|
109
|
+
if (!preload) return {}
|
|
110
|
+
|
|
111
|
+
if (typeof preload == "string") {
|
|
112
|
+
return {[preload]: true}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (Array.isArray(preload)) {
|
|
116
|
+
/**
|
|
117
|
+
* Result.
|
|
118
|
+
@type {import("./index.js").NestedPreloadRecord} */
|
|
119
|
+
const result = {}
|
|
120
|
+
|
|
121
|
+
for (const entry of preload) {
|
|
122
|
+
if (typeof entry == "string") {
|
|
123
|
+
result[entry] = true
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (isPlainObject(entry)) {
|
|
128
|
+
incorporate(result, normalizePreloadRecord(entry))
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
throw new Error(`Invalid preload entry type: ${typeof entry}`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return result
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!isPlainObject(preload)) {
|
|
139
|
+
throw new Error(`Invalid preload type: ${typeof preload}`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Result.
|
|
144
|
+
@type {import("./index.js").NestedPreloadRecord} */
|
|
145
|
+
const result = {}
|
|
146
|
+
|
|
147
|
+
for (const [key, value] of Object.entries(preload)) {
|
|
148
|
+
if (value === true || value === false) {
|
|
149
|
+
result[key] = value
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (typeof value == "string" || Array.isArray(value) || isPlainObject(value)) {
|
|
154
|
+
result[key] = normalizePreloadRecord(value)
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
throw new Error(`Invalid preload value for ${key}: ${typeof value}`)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Defines this typedef.
|
|
166
|
+
* @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
|
|
167
|
+
*/
|
|
168
|
+
/**
|
|
169
|
+
* Defines this typedef.
|
|
170
|
+
* @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
|
|
171
|
+
* @typedef {import("./index.js").QueryArgsType & {modelClass: MC, joinBasePath?: string[], joinTracker?: import("./join-tracker.js").default, forceQualifyBaseTable?: boolean, withCount?: import("./with-count.js").WithCountEntry[], queryData?: import("./query-data.js").QueryDataEntry[]}} ModelClassQueryArgsType
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* A generic query over some model type.
|
|
176
|
+
* @template {typeof import("../record/index.js").default} [MC=typeof import("../record/index.js").default]
|
|
177
|
+
*/
|
|
178
|
+
export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery {
|
|
179
|
+
/**
|
|
180
|
+
* Runs constructor.
|
|
181
|
+
* @param {ModelClassQueryArgsType<MC>} args - Query constructor arguments.
|
|
182
|
+
*/
|
|
183
|
+
constructor(args) {
|
|
184
|
+
const {modelClass} = args
|
|
185
|
+
|
|
186
|
+
if (!modelClass) throw new Error(`No modelClass given in ${Object.keys(args).join(", ")}`)
|
|
187
|
+
|
|
188
|
+
super(args)
|
|
189
|
+
this.logger = new Logger(this)
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Narrows the runtime value to the documented type.
|
|
193
|
+
@type {MC} */
|
|
194
|
+
this.modelClass = modelClass
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Narrows the runtime value to the documented type.
|
|
198
|
+
@type {string[]} */
|
|
199
|
+
this._joinBasePath = args.joinBasePath || []
|
|
200
|
+
this._joinTracker = args.joinTracker || new JoinTracker({modelClass: this.modelClass})
|
|
201
|
+
this._forceQualifyBaseTable = Boolean(args.forceQualifyBaseTable)
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Narrows the runtime value to the documented type.
|
|
205
|
+
@type {import("./with-count.js").WithCountEntry[]} */
|
|
206
|
+
this._withCount = args.withCount ? [...args.withCount] : []
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Narrows the runtime value to the documented type.
|
|
210
|
+
@type {import("./query-data.js").QueryDataEntry[]} */
|
|
211
|
+
this._queryData = args.queryData ? [...args.queryData] : []
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Runs clone.
|
|
216
|
+
* @returns {this} - The clone.
|
|
217
|
+
*/
|
|
218
|
+
clone() {
|
|
219
|
+
const newQuery = /**
|
|
220
|
+
* Narrows the runtime value to the documented type.
|
|
221
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (new VelociousDatabaseQueryModelClassQuery({
|
|
222
|
+
driver: this._driverFn,
|
|
223
|
+
froms: [...this._froms],
|
|
224
|
+
handler: this.handler.clone(),
|
|
225
|
+
groups: [...this._groups],
|
|
226
|
+
joins: [...this._joins],
|
|
227
|
+
limit: this._limit,
|
|
228
|
+
modelClass: this.modelClass,
|
|
229
|
+
offset: this._offset,
|
|
230
|
+
orders: [...this._orders],
|
|
231
|
+
page: this._page,
|
|
232
|
+
perPage: this._perPage,
|
|
233
|
+
preload: {...this._preload},
|
|
234
|
+
preloadSelects: clonePreloadSelectMap(this._preloadSelects),
|
|
235
|
+
preloadSelectsExtra: clonePreloadSelectMap(this._preloadSelectsExtra),
|
|
236
|
+
distinct: this._distinct,
|
|
237
|
+
selects: [...this._selects],
|
|
238
|
+
wheres: [...this._wheres],
|
|
239
|
+
joinBasePath: [...this._joinBasePath],
|
|
240
|
+
joinTracker: this._joinTracker.clone(),
|
|
241
|
+
forceQualifyBaseTable: this._forceQualifyBaseTable,
|
|
242
|
+
withCount: [...this._withCount],
|
|
243
|
+
queryData: [...this._queryData]
|
|
244
|
+
}))
|
|
245
|
+
|
|
246
|
+
// @ts-expect-error
|
|
247
|
+
return newQuery
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Tell the query to attach one or more association counts onto every
|
|
252
|
+
* loaded record. The counts land as regular attributes on each record;
|
|
253
|
+
* read them with `model.readAttribute("<name>Count")`.
|
|
254
|
+
* @param {import("./with-count.js").WithCountSpec} spec - Count spec in shorthand or nested form.
|
|
255
|
+
* @returns {this} - This query, for chaining.
|
|
256
|
+
*/
|
|
257
|
+
withCount(spec) {
|
|
258
|
+
for (const entry of normalizeWithCount(spec)) {
|
|
259
|
+
this._withCount.push(entry)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return this
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Attach one or more consumer-defined, per-row computed values onto
|
|
267
|
+
* every loaded root record. Leaf strings in the spec are names of
|
|
268
|
+
* functions previously registered via `Model.queryData(name, fn)`.
|
|
269
|
+
* Nested object keys are relationship names traced from the root to
|
|
270
|
+
* the model that declares the fn. Every resulting SELECT alias is
|
|
271
|
+
* attached to the **root** record (not to the intermediate joined
|
|
272
|
+
* rows); read values with `record.queryData(aliasName)`.
|
|
273
|
+
*
|
|
274
|
+
* See also `src/database/query/query-data.js`.
|
|
275
|
+
* @param {import("./query-data.js").QueryDataSpec} spec - Spec in shorthand or nested form.
|
|
276
|
+
* @returns {this} - This query, for chaining.
|
|
277
|
+
*/
|
|
278
|
+
queryData(spec) {
|
|
279
|
+
for (const entry of normalizeQueryDataSpec(spec)) {
|
|
280
|
+
this._queryData.push(entry)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return this
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Return the table reference (alias or table name) registered for the
|
|
288
|
+
* given relationship chain, relative to the query's current join base
|
|
289
|
+
* path. Convenience wrapper around `getTableReferenceForJoin` for use
|
|
290
|
+
* inside `queryData` callbacks where the writer's intent reads more
|
|
291
|
+
* naturally as "give me the table name for 'tasks'".
|
|
292
|
+
* @param {...string} path - Relationship path segments.
|
|
293
|
+
* @returns {string} - Unquoted table reference.
|
|
294
|
+
*/
|
|
295
|
+
tableNameFor(...path) {
|
|
296
|
+
return this.getTableReferenceForJoin(...path)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Runs count.
|
|
301
|
+
* @returns {Promise<number>} - Resolves with the count.
|
|
302
|
+
*/
|
|
303
|
+
async count() {
|
|
304
|
+
if (this._limit !== null || this._offset !== null) {
|
|
305
|
+
return await this.paginatedCount()
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Generate count SQL
|
|
309
|
+
const primaryKey = `${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().primaryKey())}`
|
|
310
|
+
const distinctPrefix = this._distinct ? "DISTINCT " : ""
|
|
311
|
+
let sql = `COUNT(${distinctPrefix}${primaryKey})`
|
|
312
|
+
|
|
313
|
+
if (this.driver.getType() == "pgsql") sql += "::int"
|
|
314
|
+
|
|
315
|
+
sql += " AS count"
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
// Clone query and execute count
|
|
319
|
+
const countQuery = this.clone()
|
|
320
|
+
|
|
321
|
+
countQuery._distinct = false
|
|
322
|
+
countQuery._selects = []
|
|
323
|
+
countQuery.select(sql)
|
|
324
|
+
|
|
325
|
+
const results = /**
|
|
326
|
+
* Narrows the runtime value to the documented type.
|
|
327
|
+
@type {{count: number}[]} */ (await countQuery._executeQuery({
|
|
328
|
+
logName: countQuery.queryLogName("Count")
|
|
329
|
+
}))
|
|
330
|
+
|
|
331
|
+
// The query isn't grouped and a single result has been given
|
|
332
|
+
if (results.length == 1) {
|
|
333
|
+
return results[0].count
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// The query may be grouped and a lot of different counts a given
|
|
337
|
+
let countResult = 0
|
|
338
|
+
|
|
339
|
+
for (const result of results) {
|
|
340
|
+
if (!("count" in result)) {
|
|
341
|
+
throw new Error("Invalid count result")
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
countResult += result.count
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return countResult
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Runs paginated count.
|
|
352
|
+
* @returns {Promise<number>} - Resolves with the count after pagination is applied.
|
|
353
|
+
*/
|
|
354
|
+
async paginatedCount() {
|
|
355
|
+
const countQuery = this.clone()
|
|
356
|
+
const countSql = this.driver.getType() == "pgsql" ? "COUNT(*)::int" : "COUNT(*)"
|
|
357
|
+
const sql = [
|
|
358
|
+
`SELECT ${countSql} AS ${this.driver.quoteColumn("count")}`,
|
|
359
|
+
`FROM (${countQuery.toSql()}) AS ${this.driver.quoteTable("paginated_count_rows")}`
|
|
360
|
+
].join(" ")
|
|
361
|
+
const results = /**
|
|
362
|
+
* Narrows the runtime value to the documented type.
|
|
363
|
+
@type {{count: number}[]} */ (await this.driver.query(
|
|
364
|
+
sql,
|
|
365
|
+
{logName: this.queryLogName("Count")}
|
|
366
|
+
))
|
|
367
|
+
|
|
368
|
+
if (results.length != 1 || !("count" in results[0])) {
|
|
369
|
+
throw new Error("Invalid count result")
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return results[0].count
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Runs select.
|
|
377
|
+
* @param {import("./index.js").SelectArgumentType} select - Select.
|
|
378
|
+
* @returns {this} - The select.
|
|
379
|
+
*/
|
|
380
|
+
select(select) {
|
|
381
|
+
if (Array.isArray(select)) {
|
|
382
|
+
for (const selectEntry of select) {
|
|
383
|
+
this.select(selectEntry)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return this
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof select === "string") {
|
|
390
|
+
const trimmedSelect = select.trim()
|
|
391
|
+
|
|
392
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmedSelect)) {
|
|
393
|
+
const modelClass = this.getModelClass()
|
|
394
|
+
const attributeMap = modelClass.getAttributeNameToColumnNameMap()
|
|
395
|
+
const columnName = attributeMap[trimmedSelect] || trimmedSelect
|
|
396
|
+
const tableReference = this.rootTableReference()
|
|
397
|
+
const qualifiedColumn = `${this.driver.quoteTable(tableReference)}.${this.driver.quoteColumn(columnName)}`
|
|
398
|
+
|
|
399
|
+
return super.select(qualifiedColumn)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Object form keyed by target model name, e.g. `.select({Account: ["id"]})`.
|
|
404
|
+
// These limit the attributes loaded for preloaded relationship targets
|
|
405
|
+
// rather than the root query's SELECT clause.
|
|
406
|
+
if (isPlainObject(select)) {
|
|
407
|
+
this._mergePreloadSelect(this._preloadSelects, select)
|
|
408
|
+
|
|
409
|
+
return this
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return super.select(select)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Loads the default columns plus the given extra selects for preloaded
|
|
417
|
+
* relationship targets, keyed by target model name, e.g.
|
|
418
|
+
* `.selectsExtra({Account: ["(SELECT count(*) FROM projects) AS projects_count"]})`.
|
|
419
|
+
* Unlike `select({...})`, which narrows to only the listed columns, this keeps
|
|
420
|
+
* the default `SELECT *` columns and adds the extras on top.
|
|
421
|
+
* @param {Record<string, string | string[]>} select - Extra selects keyed by target model name.
|
|
422
|
+
* @returns {this} - This query, for chaining.
|
|
423
|
+
*/
|
|
424
|
+
selectsExtra(select) {
|
|
425
|
+
this._mergePreloadSelect(this._preloadSelectsExtra, select)
|
|
426
|
+
|
|
427
|
+
return this
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Merges an object-form preload select (keyed by target model name) into the
|
|
432
|
+
* given target map, de-duplicating attribute/expression entries.
|
|
433
|
+
* @param {Record<string, string[]>} target - Map to merge into.
|
|
434
|
+
* @param {Record<string, string | string[]>} select - Object-form select.
|
|
435
|
+
* @returns {void} - No return value.
|
|
436
|
+
*/
|
|
437
|
+
_mergePreloadSelect(target, select) {
|
|
438
|
+
for (const [modelName, attributes] of Object.entries(select)) {
|
|
439
|
+
const normalizedAttributes = Array.isArray(attributes) ? attributes : [attributes]
|
|
440
|
+
|
|
441
|
+
if (!target[modelName]) target[modelName] = []
|
|
442
|
+
|
|
443
|
+
for (const attribute of normalizedAttributes) {
|
|
444
|
+
if (!target[modelName].includes(attribute)) target[modelName].push(attribute)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Runs root table reference.
|
|
451
|
+
* @returns {string} - Root table reference for query select qualification.
|
|
452
|
+
*/
|
|
453
|
+
rootTableReference() {
|
|
454
|
+
const froms = this.getFroms()
|
|
455
|
+
const lastFrom = froms[froms.length - 1]
|
|
456
|
+
|
|
457
|
+
if (lastFrom && typeof /**
|
|
458
|
+
* Narrows the runtime value to the documented type.
|
|
459
|
+
@type {?} */ (lastFrom).tableName === "string") {
|
|
460
|
+
return /** Narrows the runtime value to the documented type. @type {?} */ (lastFrom).tableName
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (lastFrom && typeof /**
|
|
464
|
+
* Narrows the runtime value to the documented type.
|
|
465
|
+
@type {?} */ (lastFrom).plain === "string") {
|
|
466
|
+
const parsedReference = parseFromPlainTableReference(/**
|
|
467
|
+
* Narrows the runtime value to the documented type.
|
|
468
|
+
@type {?} */ (lastFrom).plain)
|
|
469
|
+
|
|
470
|
+
if (parsedReference) return parsedReference
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return this.getTableReferenceForJoin()
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Runs get model class.
|
|
478
|
+
* @returns {MC} - The model class.
|
|
479
|
+
*/
|
|
480
|
+
getModelClass() {
|
|
481
|
+
if (!this.modelClass) throw new Error("modelClass not set")
|
|
482
|
+
|
|
483
|
+
return this.modelClass
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Runs get join base path.
|
|
488
|
+
* @returns {string[]} - The join base path.
|
|
489
|
+
*/
|
|
490
|
+
getJoinBasePath() {
|
|
491
|
+
return this._joinBasePath
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Runs get join tracker.
|
|
496
|
+
* @returns {import("./join-tracker.js").default} - The join tracker.
|
|
497
|
+
*/
|
|
498
|
+
getJoinTracker() {
|
|
499
|
+
return this._joinTracker
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Runs get force qualify base table.
|
|
504
|
+
* @returns {boolean} - Whether to qualify base table.
|
|
505
|
+
*/
|
|
506
|
+
getForceQualifyBaseTable() {
|
|
507
|
+
return this._forceQualifyBaseTable
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Runs set join base path.
|
|
512
|
+
* @param {string[]} joinBasePath - Join base path.
|
|
513
|
+
* @returns {this} - The query with updated base path.
|
|
514
|
+
*/
|
|
515
|
+
setJoinBasePath(joinBasePath) {
|
|
516
|
+
this._joinBasePath = joinBasePath
|
|
517
|
+
return this
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Runs with join path.
|
|
522
|
+
* @param {string[]} joinBasePath - Join base path.
|
|
523
|
+
* @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped query.
|
|
524
|
+
*/
|
|
525
|
+
withJoinPath(joinBasePath) {
|
|
526
|
+
const scopedQuery = /**
|
|
527
|
+
* Narrows the runtime value to the documented type.
|
|
528
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
|
|
529
|
+
|
|
530
|
+
scopedQuery._joinBasePath = joinBasePath
|
|
531
|
+
scopedQuery._joinTracker = this._joinTracker
|
|
532
|
+
|
|
533
|
+
return scopedQuery
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Runs resolve table name for join path.
|
|
538
|
+
* @param {string[]} path - Join path.
|
|
539
|
+
* @returns {string} - Table name for path.
|
|
540
|
+
*/
|
|
541
|
+
_resolveTableNameForJoinPath(path) {
|
|
542
|
+
return this._resolveModelClassForJoinPath(path).tableName()
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Runs resolve model class for join path.
|
|
547
|
+
* @param {string[]} path - Join path.
|
|
548
|
+
* @returns {typeof import("../record/index.js").default} - Target model class.
|
|
549
|
+
*/
|
|
550
|
+
_resolveModelClassForJoinPath(path) {
|
|
551
|
+
let modelClass = this._joinTracker.getRootModelClass()
|
|
552
|
+
|
|
553
|
+
for (const relationshipName of path) {
|
|
554
|
+
const relationship = modelClass.getRelationshipByName(relationshipName)
|
|
555
|
+
const targetModelClass = relationship.getTargetModelClass()
|
|
556
|
+
|
|
557
|
+
if (!targetModelClass) {
|
|
558
|
+
throw new Error(`No target model class for ${modelClass.name}#${relationshipName}`)
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
modelClass = targetModelClass
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return modelClass
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Runs register join path.
|
|
569
|
+
* @param {string[]} path - Join path.
|
|
570
|
+
* @returns {{tableName: string, alias: string | undefined}} - The entry.
|
|
571
|
+
*/
|
|
572
|
+
_registerJoinPath(path) {
|
|
573
|
+
const tableName = this._resolveTableNameForJoinPath(path)
|
|
574
|
+
|
|
575
|
+
return this._joinTracker.registerPath(path, tableName)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Runs get join table reference.
|
|
580
|
+
* @param {string[]} path - Join path.
|
|
581
|
+
* @returns {string} - Unquoted table reference (alias or table name).
|
|
582
|
+
*/
|
|
583
|
+
getJoinTableReference(path) {
|
|
584
|
+
const entry = this._joinTracker.getEntry(path) || this._registerJoinPath(path)
|
|
585
|
+
|
|
586
|
+
return entry.alias || entry.tableName
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Runs get table reference for join.
|
|
591
|
+
* @param {...string} path - Join path segments.
|
|
592
|
+
* @returns {string} - Unquoted table reference (alias or table name).
|
|
593
|
+
*/
|
|
594
|
+
getTableReferenceForJoin(...path) {
|
|
595
|
+
const fullPath = this._joinBasePath.concat(path)
|
|
596
|
+
|
|
597
|
+
return this.getJoinTableReference(fullPath)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Runs get table for join.
|
|
602
|
+
* @param {...string} path - Join path segments.
|
|
603
|
+
* @returns {string} - Quoted table name for join path.
|
|
604
|
+
*/
|
|
605
|
+
getTableForJoin(...path) {
|
|
606
|
+
return this.driver.quoteTable(this.getTableReferenceForJoin(...path))
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Runs scope.
|
|
611
|
+
* @param {import("../../utils/model-scope.js").ModelScopeDescriptor | string | string[]} pathOrScopeDescriptor - Scope descriptor or join path.
|
|
612
|
+
* @param {import("../../utils/model-scope.js").ModelScopeDescriptor} [maybeScopeDescriptor] - Scope descriptor when path is given.
|
|
613
|
+
* @returns {this} - Scoped query.
|
|
614
|
+
*/
|
|
615
|
+
scope(pathOrScopeDescriptor, maybeScopeDescriptor) {
|
|
616
|
+
if (isModelScopeDescriptor(pathOrScopeDescriptor) && !maybeScopeDescriptor) {
|
|
617
|
+
return this._applyRootScope(pathOrScopeDescriptor)
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (!maybeScopeDescriptor) {
|
|
621
|
+
throw new Error("scope(path, descriptor) requires a scope descriptor")
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return this._applyJoinPathScope({
|
|
625
|
+
joinPath: normalizeScopePath(/**
|
|
626
|
+
* Narrows the runtime value to the documented type.
|
|
627
|
+
@type {string | string[]} */ (pathOrScopeDescriptor)),
|
|
628
|
+
scopeDescriptor: maybeScopeDescriptor
|
|
629
|
+
})
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Runs apply root scope.
|
|
634
|
+
* @param {import("../../utils/model-scope.js").ModelScopeDescriptor} scopeDescriptor - Scope descriptor.
|
|
635
|
+
* @returns {this} - Scoped query.
|
|
636
|
+
*/
|
|
637
|
+
_applyRootScope(scopeDescriptor) {
|
|
638
|
+
if (!isModelScopeDescriptor(scopeDescriptor)) {
|
|
639
|
+
throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)")
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (scopeDescriptor.modelClass !== this.getModelClass()) {
|
|
643
|
+
throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to ${this.getModelClass().name} query`)
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const scopedQuery = /**
|
|
647
|
+
* Narrows the runtime value to the documented type.
|
|
648
|
+
@type {this | void} */ (scopeDescriptor.callback({
|
|
649
|
+
driver: this.driver,
|
|
650
|
+
modelClass: this.getModelClass(),
|
|
651
|
+
query: this,
|
|
652
|
+
table: this.rootTableReference()
|
|
653
|
+
}, ...scopeDescriptor.scopeArgs))
|
|
654
|
+
|
|
655
|
+
return scopedQuery || this
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Runs apply join path scope.
|
|
660
|
+
* @param {object} args - Join-path scope options.
|
|
661
|
+
* @param {string[]} args.joinPath - Join path relative to the current query.
|
|
662
|
+
* @param {import("../../utils/model-scope.js").ModelScopeDescriptor} args.scopeDescriptor - Scope descriptor.
|
|
663
|
+
* @returns {this} - Scoped query.
|
|
664
|
+
*/
|
|
665
|
+
_applyJoinPathScope({joinPath, scopeDescriptor}) {
|
|
666
|
+
if (!isModelScopeDescriptor(scopeDescriptor)) {
|
|
667
|
+
throw new Error("scope() expects a descriptor returned by defineScope(...).scope(...)")
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
const fullJoinPath = this.getJoinBasePath().concat(joinPath)
|
|
671
|
+
const targetModelClass = this._resolveModelClassForJoinPath(fullJoinPath)
|
|
672
|
+
|
|
673
|
+
if (scopeDescriptor.modelClass !== targetModelClass) {
|
|
674
|
+
throw new Error(`Cannot apply ${scopeDescriptor.modelClass.name} scope to join path ${fullJoinPath.join(".")} (${targetModelClass.name})`)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const scopedQuery = this.buildJoinScopeQuery(targetModelClass, fullJoinPath)
|
|
678
|
+
const originalJoinCount = scopedQuery._joins.length
|
|
679
|
+
const originalWhereCount = scopedQuery._wheres.length
|
|
680
|
+
const appliedQuery = /**
|
|
681
|
+
* Narrows the runtime value to the documented type.
|
|
682
|
+
@type {typeof scopedQuery | void} */ (scopeDescriptor.callback({
|
|
683
|
+
driver: scopedQuery.driver,
|
|
684
|
+
modelClass: targetModelClass,
|
|
685
|
+
path: [...fullJoinPath],
|
|
686
|
+
query: scopedQuery,
|
|
687
|
+
table: scopedQuery.getTableReferenceForJoin()
|
|
688
|
+
}, ...scopeDescriptor.scopeArgs)) || scopedQuery
|
|
689
|
+
|
|
690
|
+
if (appliedQuery.getFroms().length !== scopedQuery.getFroms().length ||
|
|
691
|
+
appliedQuery.getGroups().length !== scopedQuery.getGroups().length ||
|
|
692
|
+
appliedQuery.getSelects().length !== scopedQuery.getSelects().length ||
|
|
693
|
+
appliedQuery._orders.length !== scopedQuery._orders.length ||
|
|
694
|
+
appliedQuery._limit !== scopedQuery._limit ||
|
|
695
|
+
appliedQuery._offset !== scopedQuery._offset ||
|
|
696
|
+
appliedQuery._page !== scopedQuery._page ||
|
|
697
|
+
appliedQuery._perPage !== scopedQuery._perPage ||
|
|
698
|
+
appliedQuery._distinct !== scopedQuery._distinct ||
|
|
699
|
+
Object.keys(appliedQuery._preload).length !== Object.keys(scopedQuery._preload).length) {
|
|
700
|
+
throw new Error("Joined-path scopes may only add where(...) and joins(...) clauses")
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (appliedQuery._joins.length > originalJoinCount) {
|
|
704
|
+
for (const join of appliedQuery._joins.slice(originalJoinCount)) {
|
|
705
|
+
if (join instanceof JoinObject) {
|
|
706
|
+
this._joins.push(new JoinObject(join.object, fullJoinPath))
|
|
707
|
+
} else if (join instanceof JoinPlain) {
|
|
708
|
+
this._joins.push(join)
|
|
709
|
+
} else {
|
|
710
|
+
this._joins.push(join)
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (appliedQuery._wheres.length > originalWhereCount) {
|
|
716
|
+
this._wheres.push(...appliedQuery._wheres.slice(originalWhereCount))
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return this
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Runs build join scope query.
|
|
724
|
+
* @param {typeof import("../record/index.js").default} targetModelClass - Target model class.
|
|
725
|
+
* @param {string[]} joinPath - Join path.
|
|
726
|
+
* @returns {VelociousDatabaseQueryModelClassQuery<MC>} - The scoped join query.
|
|
727
|
+
*/
|
|
728
|
+
buildJoinScopeQuery(targetModelClass, joinPath) {
|
|
729
|
+
const scopedQuery = /**
|
|
730
|
+
* Narrows the runtime value to the documented type.
|
|
731
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (targetModelClass._newQuery())
|
|
732
|
+
|
|
733
|
+
scopedQuery._joinTracker = this._joinTracker
|
|
734
|
+
scopedQuery._joinBasePath = joinPath
|
|
735
|
+
scopedQuery._forceQualifyBaseTable = true
|
|
736
|
+
|
|
737
|
+
return scopedQuery
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Runs destroy all.
|
|
742
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
743
|
+
*/
|
|
744
|
+
async destroyAll() {
|
|
745
|
+
const records = await this.toArray()
|
|
746
|
+
|
|
747
|
+
for (const record of records) {
|
|
748
|
+
await record.destroy()
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Executes a bulk UPDATE on all rows matching the query's WHERE
|
|
754
|
+
* clause. Bypasses model lifecycle callbacks — use this for
|
|
755
|
+
* efficient batch updates where per-row hooks aren't needed.
|
|
756
|
+
* @param {Record<string, ?>} data - camelCase attribute names → values.
|
|
757
|
+
* @returns {Promise<void>} - Resolves when the update completes.
|
|
758
|
+
*/
|
|
759
|
+
async updateAll(data) {
|
|
760
|
+
const driver = this.driver
|
|
761
|
+
const tableName = this.getModelClass().tableName()
|
|
762
|
+
const entries = Object.entries(data)
|
|
763
|
+
|
|
764
|
+
if (entries.length === 0) return
|
|
765
|
+
|
|
766
|
+
const setCols = entries.map(([key, value]) => {
|
|
767
|
+
const columnName = inflection.underscore(key)
|
|
768
|
+
const quoted = value === null ? "NULL" : driver.quote(value)
|
|
769
|
+
|
|
770
|
+
return `${driver.quoteColumn(columnName)} = ${quoted}`
|
|
771
|
+
}).join(", ")
|
|
772
|
+
|
|
773
|
+
const joinsSql = new JoinsParser({pretty: false, query: this}).toSql()
|
|
774
|
+
const whereSql = new WhereParser({pretty: false, query: this}).toSql()
|
|
775
|
+
let sql
|
|
776
|
+
|
|
777
|
+
if (joinsSql.length > 0) {
|
|
778
|
+
// Use a subquery for cross-driver compatibility (SQLite
|
|
779
|
+
// doesn't support UPDATE ... JOIN).
|
|
780
|
+
const pk = driver.quoteColumn(this.getModelClass().primaryKey())
|
|
781
|
+
const qt = driver.quoteTable(tableName)
|
|
782
|
+
|
|
783
|
+
sql = `UPDATE ${qt} SET ${setCols} WHERE ${pk} IN (SELECT ${qt}.${pk} FROM ${qt}${joinsSql}${whereSql})`
|
|
784
|
+
} else {
|
|
785
|
+
sql = `UPDATE ${driver.quoteTable(tableName)} SET ${setCols}${whereSql}`
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
await driver.query(sql, {logName: this.queryLogName("Update All")})
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Runs find.
|
|
793
|
+
* @param {number|string} recordId - Record id.
|
|
794
|
+
* @returns {Promise<InstanceType<MC>>} - Resolves with the find.
|
|
795
|
+
*/
|
|
796
|
+
async find(recordId) {
|
|
797
|
+
/**
|
|
798
|
+
* Conditions.
|
|
799
|
+
@type {{[key: string]: number | string}} */
|
|
800
|
+
const conditions = {}
|
|
801
|
+
|
|
802
|
+
conditions[this.getModelClass().primaryKey()] = recordId
|
|
803
|
+
|
|
804
|
+
const newQuery = /**
|
|
805
|
+
* Narrows the runtime value to the documented type.
|
|
806
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
|
|
807
|
+
|
|
808
|
+
newQuery.where(conditions)
|
|
809
|
+
|
|
810
|
+
const record = (await newQuery.first())
|
|
811
|
+
|
|
812
|
+
if (!record) {
|
|
813
|
+
throw new RecordNotFoundError(`Couldn't find ${this.getModelClass().name} with '${this.getModelClass().primaryKey()}'=${recordId}`)
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
return record
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Runs find by.
|
|
821
|
+
* @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
|
|
822
|
+
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the by.
|
|
823
|
+
*/
|
|
824
|
+
async findBy(conditions) {
|
|
825
|
+
const newQuery = /**
|
|
826
|
+
* Narrows the runtime value to the documented type.
|
|
827
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
|
|
828
|
+
|
|
829
|
+
newQuery.where(conditions)
|
|
830
|
+
|
|
831
|
+
return await newQuery.first()
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Runs find or create by.
|
|
836
|
+
* @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
|
|
837
|
+
* @param {function(InstanceType<MC>) : void} [callback] - Callback function.
|
|
838
|
+
* @returns {Promise<InstanceType<MC>>} - Resolves with the or create by.
|
|
839
|
+
*/
|
|
840
|
+
async findOrCreateBy(conditions, callback) {
|
|
841
|
+
const record = await this.findOrInitializeBy(conditions, callback)
|
|
842
|
+
|
|
843
|
+
if (record.isNewRecord()) {
|
|
844
|
+
await record.save()
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
return record
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Runs find by or fail.
|
|
852
|
+
* @param {{[key: string]: string | number}} conditions - Conditions hash keyed by attribute name.
|
|
853
|
+
* @returns {Promise<InstanceType<MC>>} - Resolves with the by or fail.
|
|
854
|
+
*/
|
|
855
|
+
async findByOrFail(conditions) {
|
|
856
|
+
const record = await this.findBy(conditions)
|
|
857
|
+
|
|
858
|
+
if (!record) {
|
|
859
|
+
throw new Error("Record not found")
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return record
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Runs find or initialize by.
|
|
867
|
+
* @param {Record<string, ?>} conditions - Conditions.
|
|
868
|
+
* @param {function(InstanceType<MC>) : void} [callback] - Callback function.
|
|
869
|
+
* @returns {Promise<InstanceType<MC>>} - Resolves with the or initialize by.
|
|
870
|
+
*/
|
|
871
|
+
async findOrInitializeBy(conditions, callback) {
|
|
872
|
+
const record = await this.findBy(conditions)
|
|
873
|
+
|
|
874
|
+
if (record) return record
|
|
875
|
+
|
|
876
|
+
const ModelClass = this.getModelClass()
|
|
877
|
+
const newRecord = /**
|
|
878
|
+
* Narrows the runtime value to the documented type.
|
|
879
|
+
@type {InstanceType<MC>} */ (new ModelClass(conditions))
|
|
880
|
+
|
|
881
|
+
if (callback) {
|
|
882
|
+
callback(newRecord)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return newRecord
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Runs first.
|
|
890
|
+
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
|
|
891
|
+
*/
|
|
892
|
+
async first() {
|
|
893
|
+
const newQuery = this.clone().limit(1).reorder(`${this.driver.quoteTable(this.getModelClass().tableName())}.${this.driver.quoteColumn(this.getModelClass().orderableColumn())}`)
|
|
894
|
+
const results = await newQuery.toArray()
|
|
895
|
+
|
|
896
|
+
return results[0] || null
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Runs last.
|
|
901
|
+
* @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
|
|
902
|
+
*/
|
|
903
|
+
async last() {
|
|
904
|
+
const primaryKey = this.getModelClass().primaryKey()
|
|
905
|
+
const tableName = this.getModelClass().tableName()
|
|
906
|
+
const results = await this.clone().reorder(`${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(primaryKey)} DESC`).limit(1).toArray()
|
|
907
|
+
|
|
908
|
+
return results[0] || null
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Runs preload.
|
|
913
|
+
* @param {import("./index.js").NestedPreloadRecord | string | Array<string | import("./index.js").NestedPreloadRecord>} data - Data payload.
|
|
914
|
+
* @returns {this} - The preload.
|
|
915
|
+
*/
|
|
916
|
+
preload(data) {
|
|
917
|
+
const normalizedPreload = normalizePreloadRecord(data)
|
|
918
|
+
incorporate(this._preload, normalizedPreload)
|
|
919
|
+
return this
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Loads query results into model instances.
|
|
924
|
+
* @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
|
|
925
|
+
*/
|
|
926
|
+
async load() {
|
|
927
|
+
const models = []
|
|
928
|
+
const results = await this.results()
|
|
929
|
+
|
|
930
|
+
for (const result of results) {
|
|
931
|
+
const ModelClass = this.getModelClass()
|
|
932
|
+
const model = /**
|
|
933
|
+
* Narrows the runtime value to the documented type.
|
|
934
|
+
@type {InstanceType<MC>} */ (new ModelClass())
|
|
935
|
+
|
|
936
|
+
model.loadExistingRecord(result)
|
|
937
|
+
models.push(model)
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// Share a single cohort reference across every sibling record so that
|
|
941
|
+
// auto-preload can batch lazy relationship access later.
|
|
942
|
+
for (const model of models) {
|
|
943
|
+
model._loadCohort = models
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (Object.keys(this._preload).length > 0 && models.length > 0) {
|
|
947
|
+
const preloader = new Preloader({
|
|
948
|
+
modelClass: this.modelClass,
|
|
949
|
+
models,
|
|
950
|
+
preload: this._preload,
|
|
951
|
+
preloadSelects: this._preloadSelects,
|
|
952
|
+
preloadSelectsExtra: this._preloadSelectsExtra
|
|
953
|
+
})
|
|
954
|
+
|
|
955
|
+
await preloader.run()
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
if (this._withCount.length > 0 && models.length > 0) {
|
|
959
|
+
await runWithCount({
|
|
960
|
+
entries: this._withCount,
|
|
961
|
+
modelClass: this.modelClass,
|
|
962
|
+
models
|
|
963
|
+
})
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (this._queryData.length > 0 && models.length > 0) {
|
|
967
|
+
await runQueryData({
|
|
968
|
+
entries: this._queryData,
|
|
969
|
+
rootModelClass: this.modelClass,
|
|
970
|
+
rootModels: models
|
|
971
|
+
})
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
return models
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Converts query results to array of model instances
|
|
979
|
+
* @returns {Promise<Array<InstanceType<MC>>>} - Resolves with the array.
|
|
980
|
+
*/
|
|
981
|
+
async toArray() {
|
|
982
|
+
return await this.load()
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Plucks one or more columns directly from the database without instantiating models.
|
|
987
|
+
* @param {...string|string[]} columns - Column names.
|
|
988
|
+
* @returns {Promise<Array<?>>} - Resolves with the pluck.
|
|
989
|
+
*/
|
|
990
|
+
async pluck(...columns) {
|
|
991
|
+
const flatColumns = columns.flat()
|
|
992
|
+
|
|
993
|
+
if (flatColumns.length === 0) throw new Error("No columns given to pluck")
|
|
994
|
+
|
|
995
|
+
const modelClass = this.getModelClass()
|
|
996
|
+
const tableName = modelClass.tableName()
|
|
997
|
+
const attributeMap = modelClass.getAttributeNameToColumnNameMap()
|
|
998
|
+
const columnNames = flatColumns.map((column) => attributeMap[column] || column)
|
|
999
|
+
|
|
1000
|
+
const query = /**
|
|
1001
|
+
* Narrows the runtime value to the documented type.
|
|
1002
|
+
@type {VelociousDatabaseQueryModelClassQuery<MC>} */ (this.clone())
|
|
1003
|
+
|
|
1004
|
+
query._preload = {}
|
|
1005
|
+
query._selects = []
|
|
1006
|
+
|
|
1007
|
+
columnNames.forEach((columnName) => {
|
|
1008
|
+
const selectSql = `${this.driver.quoteTable(tableName)}.${this.driver.quoteColumn(columnName)}`
|
|
1009
|
+
|
|
1010
|
+
query.select(selectSql)
|
|
1011
|
+
})
|
|
1012
|
+
|
|
1013
|
+
const rows = await query._executeQuery({logName: query.queryLogName("Pluck")})
|
|
1014
|
+
|
|
1015
|
+
if (columnNames.length === 1) {
|
|
1016
|
+
const [columnName] = columnNames
|
|
1017
|
+
return rows.map((row) => /**
|
|
1018
|
+
* Narrows the runtime value to the documented type.
|
|
1019
|
+
@type {Record<string, ?>} */ (row)[columnName])
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return rows.map((row) => {
|
|
1023
|
+
const rowHash = /**
|
|
1024
|
+
* Narrows the runtime value to the documented type.
|
|
1025
|
+
@type {Record<string, ?>} */ (row)
|
|
1026
|
+
|
|
1027
|
+
return columnNames.map((columnName) => rowHash[columnName])
|
|
1028
|
+
})
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* Runs where.
|
|
1033
|
+
* @param {import("./index.js").WhereArgumentType} where - Where.
|
|
1034
|
+
* @returns {this} This query instance
|
|
1035
|
+
*/
|
|
1036
|
+
where(where) {
|
|
1037
|
+
if (typeof where == "string") {
|
|
1038
|
+
return super.where(where)
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (isPlainObject(where)) {
|
|
1042
|
+
const {resolvedHash, fallbackHash} = splitWhereHash({hash: where, modelClass: this.getModelClass()})
|
|
1043
|
+
const joinObject = buildJoinObjectFromWhereHash({hash: where, modelClass: this.getModelClass()})
|
|
1044
|
+
|
|
1045
|
+
if (Object.keys(joinObject).length > 0) {
|
|
1046
|
+
this.joins(joinObject)
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
if (Object.keys(resolvedHash).length > 0) {
|
|
1050
|
+
const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0
|
|
1051
|
+
this._wheres.push(new WhereModelClassHash({
|
|
1052
|
+
hash: resolvedHash,
|
|
1053
|
+
modelClass: this.getModelClass(),
|
|
1054
|
+
qualifyBaseTable,
|
|
1055
|
+
query: this
|
|
1056
|
+
}))
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
if (Object.keys(fallbackHash).length > 0) {
|
|
1060
|
+
super.where(fallbackHash)
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
return this
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Runs ransack.
|
|
1071
|
+
* @param {Record<string, ?>} params - Ransack-style params hash. Supports `s` key for sorting (e.g., `{s: "name asc"}`).
|
|
1072
|
+
* @returns {this} - Query with Ransack filters and sort applied.
|
|
1073
|
+
*/
|
|
1074
|
+
ransack(params) {
|
|
1075
|
+
const {s, ...filterParams} = params
|
|
1076
|
+
const group = normalizeRansackGroup(this.getModelClass(), filterParams)
|
|
1077
|
+
|
|
1078
|
+
applyRansackGroup({group, query: this})
|
|
1079
|
+
|
|
1080
|
+
if (typeof s === "string" && s.trim().length > 0) {
|
|
1081
|
+
const sorts = parseRansackSort(this.getModelClass(), s)
|
|
1082
|
+
|
|
1083
|
+
for (const sortDef of sorts) {
|
|
1084
|
+
this.order({column: sortDef.attribute, direction: sortDef.direction})
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
return this
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Runs where not.
|
|
1093
|
+
* @param {import("./index.js").WhereArgumentType} where - Where.
|
|
1094
|
+
* @returns {this} This query instance
|
|
1095
|
+
*/
|
|
1096
|
+
whereNot(where) {
|
|
1097
|
+
if (typeof where == "string") {
|
|
1098
|
+
return super.whereNot(where)
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
if (isPlainObject(where)) {
|
|
1102
|
+
const {resolvedHash, fallbackHash} = splitWhereHash({hash: where, modelClass: this.getModelClass()})
|
|
1103
|
+
const joinObject = buildJoinObjectFromWhereHash({hash: where, modelClass: this.getModelClass()})
|
|
1104
|
+
|
|
1105
|
+
if (Object.keys(joinObject).length > 0) {
|
|
1106
|
+
this.joins(joinObject)
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
if (Object.keys(resolvedHash).length > 0) {
|
|
1110
|
+
const qualifyBaseTable = this.getForceQualifyBaseTable() || Object.keys(joinObject).length > 0
|
|
1111
|
+
this._wheres.push(new WhereNot(new WhereModelClassHash({
|
|
1112
|
+
hash: resolvedHash,
|
|
1113
|
+
modelClass: this.getModelClass(),
|
|
1114
|
+
qualifyBaseTable,
|
|
1115
|
+
query: this
|
|
1116
|
+
})))
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
if (Object.keys(fallbackHash).length > 0) {
|
|
1120
|
+
super.whereNot(fallbackHash)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
return this
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Runs query log name.
|
|
1131
|
+
* @param {string} operation - Query operation.
|
|
1132
|
+
* @returns {string} - Query log name.
|
|
1133
|
+
*/
|
|
1134
|
+
queryLogName(operation) {
|
|
1135
|
+
return `${this.getModelClass().name} ${operation}`
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Runs apply ransack group.
|
|
1141
|
+
* @param {object} args - Options.
|
|
1142
|
+
* @param {import("../../utils/ransack.js").RansackGroup} args.group - Normalized Ransack group.
|
|
1143
|
+
* @param {import("./model-class-query.js").default<?>} args.query - Query instance.
|
|
1144
|
+
* @returns {void}
|
|
1145
|
+
*/
|
|
1146
|
+
function applyRansackGroup({group, query}) {
|
|
1147
|
+
const where = buildRansackGroupWhere({group, query})
|
|
1148
|
+
|
|
1149
|
+
if (where) {
|
|
1150
|
+
query._wheres.push(where)
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* Runs build ransack group where.
|
|
1156
|
+
* @param {object} args - Options.
|
|
1157
|
+
* @param {import("../../utils/ransack.js").RansackGroup} args.group - Normalized Ransack group.
|
|
1158
|
+
* @param {import("./model-class-query.js").default<?>} args.query - Query instance.
|
|
1159
|
+
* @returns {import("./where-base.js").default | null} - Combined where clause.
|
|
1160
|
+
*/
|
|
1161
|
+
function buildRansackGroupWhere({group, query}) {
|
|
1162
|
+
/**
|
|
1163
|
+
* Wheres.
|
|
1164
|
+
@type {import("./where-base.js").default[]} */
|
|
1165
|
+
const wheres = []
|
|
1166
|
+
|
|
1167
|
+
for (const condition of group.conditions) {
|
|
1168
|
+
const where = buildRansackConditionWhere({condition, query})
|
|
1169
|
+
|
|
1170
|
+
if (where) wheres.push(where)
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
for (const grouping of group.groupings) {
|
|
1174
|
+
const where = buildRansackGroupWhere({group: grouping, query})
|
|
1175
|
+
|
|
1176
|
+
if (where) wheres.push(where)
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (wheres.length < 1) return null
|
|
1180
|
+
if (wheres.length === 1) return wheres[0]
|
|
1181
|
+
|
|
1182
|
+
return new WhereCombinator({
|
|
1183
|
+
combinator: group.combinator,
|
|
1184
|
+
query,
|
|
1185
|
+
wheres
|
|
1186
|
+
})
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Runs build ransack condition where.
|
|
1191
|
+
* @param {object} args - Options.
|
|
1192
|
+
* @param {import("../../utils/ransack.js").RansackCondition} args.condition - Normalized Ransack condition.
|
|
1193
|
+
* @param {import("./model-class-query.js").default<?>} args.query - Query instance.
|
|
1194
|
+
* @returns {import("./where-base.js").default | null} - Condition where clause.
|
|
1195
|
+
*/
|
|
1196
|
+
function buildRansackConditionWhere({condition, query}) {
|
|
1197
|
+
/**
|
|
1198
|
+
* Wheres.
|
|
1199
|
+
@type {import("./where-base.js").default[]} */
|
|
1200
|
+
const wheres = []
|
|
1201
|
+
|
|
1202
|
+
for (const attribute of condition.attributes) {
|
|
1203
|
+
wheres.push(buildRansackAttributeWhere({attribute, condition, query}))
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
if (wheres.length < 1) return null
|
|
1207
|
+
if (wheres.length === 1) return wheres[0]
|
|
1208
|
+
|
|
1209
|
+
return new WhereCombinator({
|
|
1210
|
+
combinator: condition.combinator,
|
|
1211
|
+
query,
|
|
1212
|
+
wheres
|
|
1213
|
+
})
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* Runs build ransack attribute where.
|
|
1218
|
+
* @param {object} args - Options.
|
|
1219
|
+
* @param {import("../../utils/ransack.js").RansackAttribute} args.attribute - Normalized Ransack attribute.
|
|
1220
|
+
* @param {import("../../utils/ransack.js").RansackCondition} args.condition - Normalized Ransack condition.
|
|
1221
|
+
* @param {import("./model-class-query.js").default<?>} args.query - Query instance.
|
|
1222
|
+
* @returns {import("./where-base.js").default} - Attribute where clause.
|
|
1223
|
+
*/
|
|
1224
|
+
function buildRansackAttributeWhere({attribute, condition, query}) {
|
|
1225
|
+
const hash = buildRansackAttributeHash({attribute, condition})
|
|
1226
|
+
const joinObject = buildJoinObjectFromWhereHash({hash, modelClass: query.getModelClass()})
|
|
1227
|
+
|
|
1228
|
+
if (Object.keys(joinObject).length > 0) {
|
|
1229
|
+
query.joins(joinObject)
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
const where = new WhereModelClassHash({
|
|
1233
|
+
hash,
|
|
1234
|
+
modelClass: query.getModelClass(),
|
|
1235
|
+
qualifyBaseTable: true,
|
|
1236
|
+
query
|
|
1237
|
+
})
|
|
1238
|
+
|
|
1239
|
+
if (condition.predicate === "not_eq" || condition.predicate === "not_in") {
|
|
1240
|
+
return new WhereNot(where)
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (condition.predicate === "null" && !condition.value) {
|
|
1244
|
+
return new WhereNot(where)
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
return where
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Runs build ransack attribute hash.
|
|
1252
|
+
* @param {object} args - Options.
|
|
1253
|
+
* @param {import("../../utils/ransack.js").RansackAttribute} args.attribute - Normalized Ransack attribute.
|
|
1254
|
+
* @param {import("../../utils/ransack.js").RansackCondition} args.condition - Normalized Ransack condition.
|
|
1255
|
+
* @returns {Record<string, ?>} - Nested hash suitable for query where nodes.
|
|
1256
|
+
*/
|
|
1257
|
+
function buildRansackAttributeHash({attribute, condition}) {
|
|
1258
|
+
if (condition.predicate === "eq" || condition.predicate === "in" || condition.predicate === "not_eq" || condition.predicate === "not_in") {
|
|
1259
|
+
return buildNestedRansackHash({attribute, value: condition.value})
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
if (condition.predicate === "null") {
|
|
1263
|
+
return buildNestedRansackHash({attribute, value: null})
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
return buildNestedRansackTupleHash({
|
|
1267
|
+
attribute,
|
|
1268
|
+
operator: ransackTupleOperator(condition.predicate),
|
|
1269
|
+
value: ransackTupleValue(condition)
|
|
1270
|
+
})
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Runs build nested ransack hash.
|
|
1275
|
+
* @param {object} args - Options.
|
|
1276
|
+
* @param {import("../../utils/ransack.js").RansackAttribute} args.attribute - Normalized Ransack attribute.
|
|
1277
|
+
* @param {?} args.value - Final value.
|
|
1278
|
+
* @returns {Record<string, ?>} - Nested hash suitable for query where nodes.
|
|
1279
|
+
*/
|
|
1280
|
+
function buildNestedRansackHash({attribute, value}) {
|
|
1281
|
+
/**
|
|
1282
|
+
* Hash.
|
|
1283
|
+
@type {Record<string, ?>} */
|
|
1284
|
+
let hash = {[attribute.attributeName]: value}
|
|
1285
|
+
|
|
1286
|
+
for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
|
|
1287
|
+
hash = {[attribute.path[index]]: hash}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return hash
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Runs build nested ransack tuple hash.
|
|
1295
|
+
* @param {object} args - Options.
|
|
1296
|
+
* @param {import("../../utils/ransack.js").RansackAttribute} args.attribute - Normalized Ransack attribute.
|
|
1297
|
+
* @param {"gt" | "gteq" | "lt" | "lteq" | "like"} args.operator - Tuple operator.
|
|
1298
|
+
* @param {?} args.value - Final value.
|
|
1299
|
+
* @returns {Record<string, ?>} - Nested tuple hash suitable for query.where.
|
|
1300
|
+
*/
|
|
1301
|
+
function buildNestedRansackTupleHash({attribute, operator, value}) {
|
|
1302
|
+
/**
|
|
1303
|
+
* Hash.
|
|
1304
|
+
@type {Record<string, ?>} */
|
|
1305
|
+
let hash = {
|
|
1306
|
+
[attribute.attributeName]: [[attribute.attributeName, operator, value]]
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
for (let index = attribute.path.length - 1; index >= 0; index -= 1) {
|
|
1310
|
+
hash = {[attribute.path[index]]: hash}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
return hash
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Runs ransack tuple operator.
|
|
1318
|
+
* @param {import("../../utils/ransack.js").RansackPredicate} predicate - Ransack predicate.
|
|
1319
|
+
* @returns {"gt" | "gteq" | "lt" | "lteq" | "like"} - Query tuple operator.
|
|
1320
|
+
*/
|
|
1321
|
+
function ransackTupleOperator(predicate) {
|
|
1322
|
+
if (predicate === "gt" || predicate === "gteq" || predicate === "lt" || predicate === "lteq") {
|
|
1323
|
+
return predicate
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
return "like"
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/**
|
|
1330
|
+
* Runs ransack tuple value.
|
|
1331
|
+
* @param {import("../../utils/ransack.js").RansackCondition} condition - Ransack condition.
|
|
1332
|
+
* @returns {?} - Query tuple value.
|
|
1333
|
+
*/
|
|
1334
|
+
function ransackTupleValue(condition) {
|
|
1335
|
+
if (condition.predicate === "cont") return `%${condition.value}%`
|
|
1336
|
+
if (condition.predicate === "start") return `${condition.value}%`
|
|
1337
|
+
if (condition.predicate === "end") return `%${condition.value}`
|
|
1338
|
+
|
|
1339
|
+
return condition.value
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Runs get relationship by name.
|
|
1344
|
+
* @param {typeof import("../record/index.js").default} modelClass - Model class.
|
|
1345
|
+
* @param {string} relationshipName - Relationship name.
|
|
1346
|
+
* @returns {import("../record/relationships/base.js").default | undefined} - The relationship.
|
|
1347
|
+
*/
|
|
1348
|
+
function getRelationshipByName(modelClass, relationshipName) {
|
|
1349
|
+
return modelClass.getRelationshipsMap()[relationshipName]
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* Runs resolve column name.
|
|
1354
|
+
* @param {typeof import("../record/index.js").default} modelClass - Model class.
|
|
1355
|
+
* @param {string} key - Attribute or column name.
|
|
1356
|
+
* @returns {string | undefined} - The resolved column name.
|
|
1357
|
+
*/
|
|
1358
|
+
function resolveColumnName(modelClass, key) {
|
|
1359
|
+
const attributeMap = modelClass.getAttributeNameToColumnNameMap()
|
|
1360
|
+
|
|
1361
|
+
if (attributeMap[key]) return attributeMap[key]
|
|
1362
|
+
|
|
1363
|
+
const columnMap = modelClass.getColumnNameToAttributeNameMap()
|
|
1364
|
+
const underscored = inflection.underscore(key)
|
|
1365
|
+
|
|
1366
|
+
return columnMap[key] || columnMap[underscored] || undefined
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* Runs split where hash.
|
|
1371
|
+
* @param {object} args - Options.
|
|
1372
|
+
* @param {Record<string, ?>} args.hash - Where hash.
|
|
1373
|
+
* @param {typeof import("../record/index.js").default} args.modelClass - Model class.
|
|
1374
|
+
* @returns {{resolvedHash: Record<string, ?>, fallbackHash: Record<string, ?>}} - Split hashes.
|
|
1375
|
+
*/
|
|
1376
|
+
function splitWhereHash({hash, modelClass}) {
|
|
1377
|
+
/**
|
|
1378
|
+
* Resolved hash.
|
|
1379
|
+
@type {Record<string, ?>} */
|
|
1380
|
+
const resolvedHash = {}
|
|
1381
|
+
/**
|
|
1382
|
+
* Fallback hash.
|
|
1383
|
+
@type {Record<string, ?>} */
|
|
1384
|
+
const fallbackHash = {}
|
|
1385
|
+
|
|
1386
|
+
for (const key in hash) {
|
|
1387
|
+
const value = hash[key]
|
|
1388
|
+
const isNested = isPlainObject(value)
|
|
1389
|
+
const relationship = getRelationshipByName(modelClass, key)
|
|
1390
|
+
|
|
1391
|
+
if (isNested) {
|
|
1392
|
+
if (relationship) {
|
|
1393
|
+
const targetModelClass = relationship.getTargetModelClass()
|
|
1394
|
+
if (!targetModelClass) {
|
|
1395
|
+
fallbackHash[key] = value
|
|
1396
|
+
continue
|
|
1397
|
+
}
|
|
1398
|
+
const nestedResult = splitWhereHash({hash: value, modelClass: targetModelClass})
|
|
1399
|
+
const nestedResolvedKeys = Object.keys(nestedResult.resolvedHash)
|
|
1400
|
+
const nestedFallbackKeys = Object.keys(nestedResult.fallbackHash)
|
|
1401
|
+
|
|
1402
|
+
if (nestedResolvedKeys.length > 0) {
|
|
1403
|
+
resolvedHash[key] = nestedResult.resolvedHash
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
if (nestedFallbackKeys.length > 0) {
|
|
1407
|
+
const tableName = targetModelClass.tableName()
|
|
1408
|
+
|
|
1409
|
+
if (!fallbackHash[tableName]) fallbackHash[tableName] = {}
|
|
1410
|
+
Object.assign(fallbackHash[tableName], nestedResult.fallbackHash)
|
|
1411
|
+
}
|
|
1412
|
+
} else {
|
|
1413
|
+
fallbackHash[key] = value
|
|
1414
|
+
}
|
|
1415
|
+
} else if (relationship && hasRelationshipWhereOperatorTuples(value)) {
|
|
1416
|
+
resolvedHash[key] = normalizeRelationshipWhereOperatorTuples(value)
|
|
1417
|
+
} else {
|
|
1418
|
+
const columnName = resolveColumnName(modelClass, key)
|
|
1419
|
+
|
|
1420
|
+
if (columnName) {
|
|
1421
|
+
resolvedHash[columnName] = value
|
|
1422
|
+
} else {
|
|
1423
|
+
fallbackHash[key] = value
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
return {resolvedHash, fallbackHash}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* Runs build join object from where hash.
|
|
1433
|
+
* @param {object} args - Options.
|
|
1434
|
+
* @param {Record<string, ?>} args.hash - Where hash.
|
|
1435
|
+
* @param {typeof import("../record/index.js").default} args.modelClass - Model class.
|
|
1436
|
+
* @returns {Record<string, ?>} - Join object.
|
|
1437
|
+
*/
|
|
1438
|
+
function buildJoinObjectFromWhereHash({hash, modelClass}) {
|
|
1439
|
+
/**
|
|
1440
|
+
* Join object.
|
|
1441
|
+
@type {Record<string, ?>} */
|
|
1442
|
+
const joinObject = {}
|
|
1443
|
+
|
|
1444
|
+
for (const key in hash) {
|
|
1445
|
+
const value = hash[key]
|
|
1446
|
+
const relationship = getRelationshipByName(modelClass, key)
|
|
1447
|
+
|
|
1448
|
+
if (!relationship) continue
|
|
1449
|
+
|
|
1450
|
+
if (isPlainObject(value)) {
|
|
1451
|
+
const targetModelClass = relationship.getTargetModelClass()
|
|
1452
|
+
if (!targetModelClass) continue
|
|
1453
|
+
const nestedJoinObject = buildJoinObjectFromWhereHash({hash: value, modelClass: targetModelClass})
|
|
1454
|
+
|
|
1455
|
+
joinObject[key] = Object.keys(nestedJoinObject).length > 0 ? nestedJoinObject : true
|
|
1456
|
+
continue
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if (hasRelationshipWhereOperatorTuples(value)) {
|
|
1460
|
+
joinObject[key] = true
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
return joinObject
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
const relationshipWhereOperators = new Set(["eq", "notEq", "gt", "gteq", "lt", "lteq", "like", ">", ">=", "<", "<="])
|
|
1468
|
+
|
|
1469
|
+
/**
|
|
1470
|
+
* Runs normalize relationship where operator.
|
|
1471
|
+
* @param {string} operator - Raw relationship where operator.
|
|
1472
|
+
* @returns {"eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like"} - Normalized operator.
|
|
1473
|
+
*/
|
|
1474
|
+
function normalizeRelationshipWhereOperator(operator) {
|
|
1475
|
+
const operatorAliases = {
|
|
1476
|
+
"<": "lt",
|
|
1477
|
+
"<=": "lteq",
|
|
1478
|
+
">": "gt",
|
|
1479
|
+
">=": "gteq"
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
return /** Narrows the runtime value to the documented type. @type {"eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like"} */ (
|
|
1483
|
+
operatorAliases[/**
|
|
1484
|
+
* Narrows the runtime value to the documented type.
|
|
1485
|
+
@type {"<" | "<=" | ">" | ">="} */ (operator)] || operator
|
|
1486
|
+
)
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* Runs is relationship where operator tuple.
|
|
1491
|
+
* @param {?} tupleValue - Candidate tuple.
|
|
1492
|
+
* @returns {boolean} - Whether this is a relationship where tuple.
|
|
1493
|
+
*/
|
|
1494
|
+
function isRelationshipWhereOperatorTuple(tupleValue) {
|
|
1495
|
+
if (!Array.isArray(tupleValue) || tupleValue.length < 3) {
|
|
1496
|
+
return false
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
return typeof tupleValue[0] === "string" &&
|
|
1500
|
+
typeof tupleValue[1] === "string" &&
|
|
1501
|
+
relationshipWhereOperators.has(tupleValue[1])
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Runs normalize relationship where operator tuples.
|
|
1506
|
+
* @param {?} value - Candidate value.
|
|
1507
|
+
* @returns {Array<[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like", unknown]>} - Normalized tuples.
|
|
1508
|
+
*/
|
|
1509
|
+
function normalizeRelationshipWhereOperatorTuples(value) {
|
|
1510
|
+
if (!Array.isArray(value)) {
|
|
1511
|
+
throw new Error(`Invalid relationship where tuple container type: ${typeof value}`)
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* Normalized.
|
|
1516
|
+
@type {Array<[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like", unknown]>} */
|
|
1517
|
+
const normalized = []
|
|
1518
|
+
/**
|
|
1519
|
+
* Add condition.
|
|
1520
|
+
* @param {?} conditionValue - Candidate nested condition.
|
|
1521
|
+
*/
|
|
1522
|
+
const addCondition = (conditionValue) => {
|
|
1523
|
+
if (isRelationshipWhereOperatorTuple(conditionValue)) {
|
|
1524
|
+
const tuple = /**
|
|
1525
|
+
* Narrows the runtime value to the documented type.
|
|
1526
|
+
@type {[string, "eq" | "notEq" | "gt" | "gteq" | "lt" | "lteq" | "like" | ">" | ">=" | "<" | "<=", unknown, ...Array<unknown>]} */ (conditionValue)
|
|
1527
|
+
const normalizedOperator = normalizeRelationshipWhereOperator(tuple[1])
|
|
1528
|
+
|
|
1529
|
+
normalized.push([
|
|
1530
|
+
tuple[0],
|
|
1531
|
+
normalizedOperator,
|
|
1532
|
+
tuple[2]
|
|
1533
|
+
])
|
|
1534
|
+
|
|
1535
|
+
if (tuple.length > 3) {
|
|
1536
|
+
for (let index = 3; index < tuple.length; index += 1) {
|
|
1537
|
+
addCondition(tuple[index])
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
return
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
if (!Array.isArray(conditionValue)) {
|
|
1545
|
+
throw new Error("Relationship where conditions must be tuples")
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
/**
|
|
1549
|
+
* Narrows the runtime value to the documented type.
|
|
1550
|
+
@type {Array<?>} */ (conditionValue).forEach((nestedConditionValue) => {
|
|
1551
|
+
addCondition(nestedConditionValue)
|
|
1552
|
+
})
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
addCondition(value)
|
|
1556
|
+
|
|
1557
|
+
if (normalized.length < 1) {
|
|
1558
|
+
throw new Error("Relationship where tuple container cannot be empty")
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
return normalized
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/**
|
|
1565
|
+
* Runs has relationship where operator tuples.
|
|
1566
|
+
* @param {?} value - Candidate relationship where value.
|
|
1567
|
+
* @returns {boolean} - Whether value can be normalized to relationship tuples.
|
|
1568
|
+
*/
|
|
1569
|
+
function hasRelationshipWhereOperatorTuples(value) {
|
|
1570
|
+
try {
|
|
1571
|
+
normalizeRelationshipWhereOperatorTuples(value)
|
|
1572
|
+
|
|
1573
|
+
return true
|
|
1574
|
+
} catch {
|
|
1575
|
+
return false
|
|
1576
|
+
}
|
|
1577
|
+
}
|