adorn-api 1.0.22 → 1.0.24
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/.eslintignore +3 -0
- package/.eslintrc.cjs +30 -0
- package/README.md +375 -531
- package/dist/core/express-adapter.d.ts +27 -0
- package/dist/core/express-adapter.d.ts.map +1 -0
- package/dist/core/express-adapter.js +146 -0
- package/dist/core/express-adapter.js.map +1 -0
- package/dist/core/http-error.d.ts +7 -0
- package/dist/core/http-error.d.ts.map +1 -0
- package/dist/core/http-error.js +14 -0
- package/dist/core/http-error.js.map +1 -0
- package/dist/decorators/controller.decorator.d.ts +2 -0
- package/dist/decorators/controller.decorator.d.ts.map +1 -0
- package/dist/decorators/controller.decorator.js +26 -0
- package/dist/decorators/controller.decorator.js.map +1 -0
- package/dist/decorators/create.decorator.d.ts +8 -0
- package/dist/decorators/create.decorator.d.ts.map +1 -0
- package/dist/decorators/create.decorator.js +67 -0
- package/dist/decorators/create.decorator.js.map +1 -0
- package/dist/decorators/http-method.decorator.d.ts +16 -0
- package/dist/decorators/http-method.decorator.d.ts.map +1 -0
- package/dist/decorators/http-method.decorator.js +117 -0
- package/dist/decorators/http-method.decorator.js.map +1 -0
- package/dist/decorators/http-params.d.ts +17 -0
- package/dist/decorators/http-params.d.ts.map +1 -0
- package/dist/decorators/http-params.js +26 -0
- package/dist/decorators/http-params.js.map +1 -0
- package/dist/decorators/index.d.ts +10 -5
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +14 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/list.decorator.d.ts +18 -0
- package/dist/decorators/list.decorator.d.ts.map +1 -0
- package/dist/decorators/list.decorator.js +99 -0
- package/dist/decorators/list.decorator.js.map +1 -0
- package/dist/decorators/middleware.decorator.d.ts +4 -0
- package/dist/decorators/middleware.decorator.d.ts.map +1 -0
- package/dist/decorators/middleware.decorator.js +34 -0
- package/dist/decorators/middleware.decorator.js.map +1 -0
- package/dist/decorators/response.decorator.d.ts +8 -0
- package/dist/decorators/response.decorator.d.ts.map +1 -0
- package/dist/decorators/response.decorator.js +44 -0
- package/dist/decorators/response.decorator.js.map +1 -0
- package/dist/decorators/route-options.d.ts +14 -0
- package/dist/decorators/route-options.d.ts.map +1 -0
- package/dist/decorators/route-options.js +22 -0
- package/dist/decorators/route-options.js.map +1 -0
- package/dist/decorators/schema.decorator.d.ts +82 -0
- package/dist/decorators/schema.decorator.d.ts.map +1 -0
- package/dist/decorators/schema.decorator.js +123 -0
- package/dist/decorators/schema.decorator.js.map +1 -0
- package/dist/decorators/update.decorator.d.ts +8 -0
- package/dist/decorators/update.decorator.d.ts.map +1 -0
- package/dist/decorators/update.decorator.js +63 -0
- package/dist/decorators/update.decorator.js.map +1 -0
- package/dist/index.d.ts +11 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -637
- package/dist/index.js.map +1 -1
- package/dist/metadata/metadata-storage.d.ts +38 -0
- package/dist/metadata/metadata-storage.d.ts.map +1 -0
- package/dist/metadata/metadata-storage.js +102 -0
- package/dist/metadata/metadata-storage.js.map +1 -0
- package/dist/metal-orm-integration/dto-helper.d.ts +5 -0
- package/dist/metal-orm-integration/dto-helper.d.ts.map +1 -0
- package/dist/metal-orm-integration/dto-helper.js +48 -0
- package/dist/metal-orm-integration/dto-helper.js.map +1 -0
- package/dist/metal-orm-integration/dto-response.decorator.d.ts +4 -0
- package/dist/metal-orm-integration/dto-response.decorator.d.ts.map +1 -0
- package/dist/metal-orm-integration/dto-response.decorator.js +69 -0
- package/dist/metal-orm-integration/dto-response.decorator.js.map +1 -0
- package/dist/metal-orm-integration/entity-schema-builder.d.ts +20 -0
- package/dist/metal-orm-integration/entity-schema-builder.d.ts.map +1 -0
- package/dist/metal-orm-integration/entity-schema-builder.js +356 -0
- package/dist/metal-orm-integration/entity-schema-builder.js.map +1 -0
- package/dist/metal-orm-integration/index.d.ts +5 -0
- package/dist/metal-orm-integration/index.d.ts.map +1 -0
- package/dist/metal-orm-integration/index.js +5 -0
- package/dist/metal-orm-integration/index.js.map +1 -0
- package/dist/metal-orm-integration/schema-modifier.d.ts +11 -0
- package/dist/metal-orm-integration/schema-modifier.d.ts.map +1 -0
- package/dist/metal-orm-integration/schema-modifier.js +62 -0
- package/dist/metal-orm-integration/schema-modifier.js.map +1 -0
- package/dist/openapi/index.d.ts +4 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +4 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/openapi-generator.d.ts +22 -0
- package/dist/openapi/openapi-generator.d.ts.map +1 -0
- package/dist/openapi/openapi-generator.js +428 -0
- package/dist/openapi/openapi-generator.js.map +1 -0
- package/dist/openapi/swagger-ui.d.ts +11 -0
- package/dist/openapi/swagger-ui.d.ts.map +1 -0
- package/dist/openapi/swagger-ui.js +20 -0
- package/dist/openapi/swagger-ui.js.map +1 -0
- package/dist/openapi/zod-to-openapi.d.ts +4 -0
- package/dist/openapi/zod-to-openapi.d.ts.map +1 -0
- package/dist/openapi/zod-to-openapi.js +184 -0
- package/dist/openapi/zod-to-openapi.js.map +1 -0
- package/dist/types/common.d.ts +4 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/controller.d.ts +14 -0
- package/dist/types/controller.d.ts.map +1 -0
- package/dist/types/controller.js +2 -0
- package/dist/types/controller.js.map +1 -0
- package/dist/types/metadata.d.ts +48 -0
- package/dist/types/metadata.d.ts.map +1 -0
- package/dist/types/metadata.js +2 -0
- package/dist/types/metadata.js.map +1 -0
- package/dist/types/openapi.d.ts +30 -0
- package/dist/types/openapi.d.ts.map +1 -0
- package/dist/types/openapi.js +2 -0
- package/dist/types/openapi.js.map +1 -0
- package/dist/validation/zod-adapter.d.ts +15 -0
- package/dist/validation/zod-adapter.d.ts.map +1 -0
- package/dist/validation/zod-adapter.js +61 -0
- package/dist/validation/zod-adapter.js.map +1 -0
- package/examples/basic/app.ts +15 -0
- package/examples/basic/index.ts +6 -0
- package/examples/basic/user.controller.ts +35 -0
- package/examples/basic/user.dtos.ts +23 -0
- package/examples/metal-orm-sqlite/app.ts +18 -0
- package/examples/metal-orm-sqlite/db.ts +90 -0
- package/examples/metal-orm-sqlite/index.ts +6 -0
- package/examples/metal-orm-sqlite/post.controller.ts +209 -0
- package/examples/metal-orm-sqlite/post.dtos.ts +78 -0
- package/examples/metal-orm-sqlite/post.entity.ts +24 -0
- package/examples/metal-orm-sqlite/user.controller.helpers.ts +305 -0
- package/examples/metal-orm-sqlite/user.controller.ts +231 -0
- package/examples/metal-orm-sqlite/user.dtos.ts +88 -0
- package/examples/metal-orm-sqlite/user.entity.ts +21 -0
- package/examples/metal-orm-sqlite-music/album.controller.ts +278 -0
- package/examples/metal-orm-sqlite-music/album.dtos.ts +85 -0
- package/examples/metal-orm-sqlite-music/album.entity.ts +28 -0
- package/examples/metal-orm-sqlite-music/app.ts +19 -0
- package/examples/metal-orm-sqlite-music/artist.controller.ts +272 -0
- package/examples/metal-orm-sqlite-music/artist.dtos.ts +68 -0
- package/examples/metal-orm-sqlite-music/artist.entity.ts +27 -0
- package/examples/metal-orm-sqlite-music/db.ts +148 -0
- package/examples/metal-orm-sqlite-music/index.ts +6 -0
- package/examples/metal-orm-sqlite-music/track.controller.ts +221 -0
- package/examples/metal-orm-sqlite-music/track.dtos.ts +82 -0
- package/examples/metal-orm-sqlite-music/track.entity.ts +27 -0
- package/examples/openapi/health.controller.ts +11 -0
- package/examples/openapi/health.dto.ts +7 -0
- package/examples/openapi/index.ts +12 -0
- package/examples/restful/app.ts +15 -0
- package/examples/restful/index.ts +9 -0
- package/examples/restful/task.controller.ts +118 -0
- package/examples/restful/task.dtos.ts +66 -0
- package/examples/restful/task.store.ts +95 -0
- package/examples/tsconfig.json +8 -0
- package/examples/utils/start-server.ts +56 -0
- package/package.json +33 -97
- package/scripts/run-example.js +29 -0
- package/src/adapter/express.ts +589 -0
- package/src/adapter/metal-orm/convention-overrides.ts +115 -0
- package/src/adapter/metal-orm/crud-dtos.ts +141 -0
- package/src/adapter/metal-orm/dto.ts +20 -0
- package/src/adapter/metal-orm/error-dtos.ts +51 -0
- package/src/adapter/metal-orm/field-builder.ts +185 -0
- package/src/adapter/metal-orm/filters.ts +52 -0
- package/src/adapter/metal-orm/index.ts +66 -0
- package/src/adapter/metal-orm/paged-dtos.ts +94 -0
- package/src/adapter/metal-orm/pagination.ts +28 -0
- package/src/adapter/metal-orm/types.ts +250 -0
- package/src/adapter/metal-orm/utils.ts +36 -0
- package/src/adapter/metal-orm.test.ts +439 -0
- package/src/core/__tests__/coerce.test.ts +39 -0
- package/src/core/__tests__/dto-compose.test.ts +68 -0
- package/src/core/__tests__/schema-builder.test.ts +82 -0
- package/src/core/coerce.ts +190 -0
- package/src/core/decorators.ts +645 -0
- package/src/core/errors.ts +55 -0
- package/src/core/metadata.ts +110 -0
- package/src/core/openapi.ts +282 -0
- package/src/core/schema-builder.ts +287 -0
- package/src/core/schema.ts +400 -0
- package/src/core/types.ts +14 -0
- package/src/e2e/http-error.e2e.test.ts +52 -0
- package/src/e2e/sqlite-metal-orm.e2e.test.ts +174 -0
- package/src/e2e/sqlite.e2e.test.ts +126 -0
- package/src/index.ts +8 -0
- package/tsconfig.eslint.json +7 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +8 -0
- package/dist/adapter/express/auth.d.ts +0 -13
- package/dist/adapter/express/auth.d.ts.map +0 -1
- package/dist/adapter/express/bootstrap.d.ts +0 -40
- package/dist/adapter/express/bootstrap.d.ts.map +0 -1
- package/dist/adapter/express/coercion.d.ts +0 -102
- package/dist/adapter/express/coercion.d.ts.map +0 -1
- package/dist/adapter/express/index.d.ts +0 -6
- package/dist/adapter/express/index.d.ts.map +0 -1
- package/dist/adapter/express/merge.d.ts +0 -45
- package/dist/adapter/express/merge.d.ts.map +0 -1
- package/dist/adapter/express/openapi.d.ts +0 -66
- package/dist/adapter/express/openapi.d.ts.map +0 -1
- package/dist/adapter/express/router.d.ts +0 -10
- package/dist/adapter/express/router.d.ts.map +0 -1
- package/dist/adapter/express/swagger.d.ts +0 -18
- package/dist/adapter/express/swagger.d.ts.map +0 -1
- package/dist/adapter/express/types.d.ts +0 -110
- package/dist/adapter/express/types.d.ts.map +0 -1
- package/dist/adapter/express/validation.d.ts +0 -27
- package/dist/adapter/express/validation.d.ts.map +0 -1
- package/dist/cli/progress.d.ts +0 -122
- package/dist/cli/progress.d.ts.map +0 -1
- package/dist/cli.cjs +0 -4390
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -4371
- package/dist/cli.js.map +0 -1
- package/dist/compiler/analyze/index.d.ts +0 -5
- package/dist/compiler/analyze/index.d.ts.map +0 -1
- package/dist/compiler/analyze/scanControllers.d.ts +0 -88
- package/dist/compiler/analyze/scanControllers.d.ts.map +0 -1
- package/dist/compiler/cache/isStale.d.ts +0 -46
- package/dist/compiler/cache/isStale.d.ts.map +0 -1
- package/dist/compiler/cache/loadArtifacts.d.ts +0 -149
- package/dist/compiler/cache/loadArtifacts.d.ts.map +0 -1
- package/dist/compiler/cache/schema.d.ts +0 -32
- package/dist/compiler/cache/schema.d.ts.map +0 -1
- package/dist/compiler/cache/writeCache.d.ts +0 -14
- package/dist/compiler/cache/writeCache.d.ts.map +0 -1
- package/dist/compiler/gems.d.ts +0 -75
- package/dist/compiler/gems.d.ts.map +0 -1
- package/dist/compiler/generator/index.d.ts +0 -7
- package/dist/compiler/generator/index.d.ts.map +0 -1
- package/dist/compiler/generator/manifest.d.ts +0 -23
- package/dist/compiler/generator/manifest.d.ts.map +0 -1
- package/dist/compiler/generator/openapi.d.ts +0 -118
- package/dist/compiler/generator/openapi.d.ts.map +0 -1
- package/dist/compiler/graph/builder.d.ts +0 -24
- package/dist/compiler/graph/builder.d.ts.map +0 -1
- package/dist/compiler/graph/index.d.ts +0 -7
- package/dist/compiler/graph/index.d.ts.map +0 -1
- package/dist/compiler/graph/schemaGraph.d.ts +0 -67
- package/dist/compiler/graph/schemaGraph.d.ts.map +0 -1
- package/dist/compiler/graph/types.d.ts +0 -203
- package/dist/compiler/graph/types.d.ts.map +0 -1
- package/dist/compiler/index.d.ts +0 -12
- package/dist/compiler/index.d.ts.map +0 -1
- package/dist/compiler/ir/index.d.ts +0 -7
- package/dist/compiler/ir/index.d.ts.map +0 -1
- package/dist/compiler/ir/pipeline.d.ts +0 -82
- package/dist/compiler/ir/pipeline.d.ts.map +0 -1
- package/dist/compiler/ir/stages.d.ts +0 -40
- package/dist/compiler/ir/stages.d.ts.map +0 -1
- package/dist/compiler/ir/visitor.d.ts +0 -98
- package/dist/compiler/ir/visitor.d.ts.map +0 -1
- package/dist/compiler/manifest/emit.d.ts +0 -21
- package/dist/compiler/manifest/emit.d.ts.map +0 -1
- package/dist/compiler/manifest/format.d.ts +0 -119
- package/dist/compiler/manifest/format.d.ts.map +0 -1
- package/dist/compiler/manifest/index.d.ts +0 -6
- package/dist/compiler/manifest/index.d.ts.map +0 -1
- package/dist/compiler/runner/createProgram.d.ts +0 -24
- package/dist/compiler/runner/createProgram.d.ts.map +0 -1
- package/dist/compiler/runner/index.d.ts +0 -5
- package/dist/compiler/runner/index.d.ts.map +0 -1
- package/dist/compiler/schema/extractAnnotations.d.ts +0 -57
- package/dist/compiler/schema/extractAnnotations.d.ts.map +0 -1
- package/dist/compiler/schema/index.d.ts +0 -8
- package/dist/compiler/schema/index.d.ts.map +0 -1
- package/dist/compiler/schema/intersectionHandler.d.ts +0 -44
- package/dist/compiler/schema/intersectionHandler.d.ts.map +0 -1
- package/dist/compiler/schema/objectHandler.d.ts +0 -146
- package/dist/compiler/schema/objectHandler.d.ts.map +0 -1
- package/dist/compiler/schema/openapi.d.ts +0 -71
- package/dist/compiler/schema/openapi.d.ts.map +0 -1
- package/dist/compiler/schema/parameters.d.ts +0 -90
- package/dist/compiler/schema/parameters.d.ts.map +0 -1
- package/dist/compiler/schema/partitioner.d.ts +0 -85
- package/dist/compiler/schema/partitioner.d.ts.map +0 -1
- package/dist/compiler/schema/primitives.d.ts +0 -68
- package/dist/compiler/schema/primitives.d.ts.map +0 -1
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts +0 -76
- package/dist/compiler/schema/queryBuilderAnalyzer.d.ts.map +0 -1
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts +0 -13
- package/dist/compiler/schema/queryBuilderSchemaBuilder.d.ts.map +0 -1
- package/dist/compiler/schema/splitOpenapi.d.ts +0 -46
- package/dist/compiler/schema/splitOpenapi.d.ts.map +0 -1
- package/dist/compiler/schema/typeToJsonSchema.d.ts +0 -26
- package/dist/compiler/schema/typeToJsonSchema.d.ts.map +0 -1
- package/dist/compiler/schema/types.d.ts +0 -70
- package/dist/compiler/schema/types.d.ts.map +0 -1
- package/dist/compiler/schema/unionHandler.d.ts +0 -70
- package/dist/compiler/schema/unionHandler.d.ts.map +0 -1
- package/dist/compiler/transform/dedup.d.ts +0 -35
- package/dist/compiler/transform/dedup.d.ts.map +0 -1
- package/dist/compiler/transform/flatten.d.ts +0 -50
- package/dist/compiler/transform/flatten.d.ts.map +0 -1
- package/dist/compiler/transform/index.d.ts +0 -7
- package/dist/compiler/transform/index.d.ts.map +0 -1
- package/dist/compiler/transform/inline.d.ts +0 -46
- package/dist/compiler/transform/inline.d.ts.map +0 -1
- package/dist/compiler/validation/emitPrecompiledValidators.d.ts +0 -62
- package/dist/compiler/validation/emitPrecompiledValidators.d.ts.map +0 -1
- package/dist/compiler/validation/index.d.ts +0 -5
- package/dist/compiler/validation/index.d.ts.map +0 -1
- package/dist/decorators/Auth.d.ts +0 -22
- package/dist/decorators/Auth.d.ts.map +0 -1
- package/dist/decorators/Controller.d.ts +0 -17
- package/dist/decorators/Controller.d.ts.map +0 -1
- package/dist/decorators/Public.d.ts +0 -15
- package/dist/decorators/Public.d.ts.map +0 -1
- package/dist/decorators/Use.d.ts +0 -23
- package/dist/decorators/Use.d.ts.map +0 -1
- package/dist/decorators/methods.d.ts +0 -26
- package/dist/decorators/methods.d.ts.map +0 -1
- package/dist/express.cjs +0 -1186
- package/dist/express.cjs.map +0 -1
- package/dist/express.d.ts +0 -8
- package/dist/express.d.ts.map +0 -1
- package/dist/express.js +0 -1150
- package/dist/express.js.map +0 -1
- package/dist/http.d.ts +0 -33
- package/dist/http.d.ts.map +0 -1
- package/dist/index.cjs +0 -724
- package/dist/index.cjs.map +0 -1
- package/dist/metal/applyListQuery.d.ts +0 -100
- package/dist/metal/applyListQuery.d.ts.map +0 -1
- package/dist/metal/index.cjs +0 -278
- package/dist/metal/index.cjs.map +0 -1
- package/dist/metal/index.d.ts +0 -15
- package/dist/metal/index.d.ts.map +0 -1
- package/dist/metal/index.js +0 -243
- package/dist/metal/index.js.map +0 -1
- package/dist/metal/listQuery.d.ts +0 -26
- package/dist/metal/listQuery.d.ts.map +0 -1
- package/dist/metal/queryOptions.d.ts +0 -16
- package/dist/metal/queryOptions.d.ts.map +0 -1
- package/dist/metal/readMetalBag.d.ts +0 -69
- package/dist/metal/readMetalBag.d.ts.map +0 -1
- package/dist/metal/registerMetalEntities.d.ts +0 -26
- package/dist/metal/registerMetalEntities.d.ts.map +0 -1
- package/dist/metal/schemaFromEntity.d.ts +0 -41
- package/dist/metal/schemaFromEntity.d.ts.map +0 -1
- package/dist/metal/searchWhere.d.ts +0 -97
- package/dist/metal/searchWhere.d.ts.map +0 -1
- package/dist/metal/symbolMetadata.d.ts +0 -8
- package/dist/metal/symbolMetadata.d.ts.map +0 -1
- package/dist/runtime/auth/runtime.d.ts +0 -183
- package/dist/runtime/auth/runtime.d.ts.map +0 -1
- package/dist/runtime/metadata/bucket.d.ts +0 -2
- package/dist/runtime/metadata/bucket.d.ts.map +0 -1
- package/dist/runtime/metadata/key.d.ts +0 -2
- package/dist/runtime/metadata/key.d.ts.map +0 -1
- package/dist/runtime/metadata/read.d.ts +0 -2
- package/dist/runtime/metadata/read.d.ts.map +0 -1
- package/dist/runtime/metadata/types.d.ts +0 -95
- package/dist/runtime/metadata/types.d.ts.map +0 -1
- package/dist/runtime/polyfill.d.ts +0 -2
- package/dist/runtime/polyfill.d.ts.map +0 -1
- package/dist/runtime/upload.d.ts +0 -44
- package/dist/runtime/upload.d.ts.map +0 -1
- package/dist/runtime/validation/ajv.d.ts +0 -120
- package/dist/runtime/validation/ajv.d.ts.map +0 -1
- package/dist/runtime/validation/index.d.ts +0 -11
- package/dist/runtime/validation/index.d.ts.map +0 -1
- package/dist/schema/decorators.d.ts +0 -37
- package/dist/schema/decorators.d.ts.map +0 -1
- package/dist/schema/index.cjs +0 -214
- package/dist/schema/index.cjs.map +0 -1
- package/dist/schema/index.d.ts +0 -2
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js +0 -163
- package/dist/schema/index.js.map +0 -1
- package/dist/scripts/adorn-example.cjs +0 -404
- package/dist/scripts/adorn-example.cjs.map +0 -1
- package/dist/utils/operationId.d.ts +0 -2
- package/dist/utils/operationId.d.ts.map +0 -1
- package/dist/utils/path.d.ts +0 -2
- package/dist/utils/path.d.ts.map +0 -1
- package/dist/utils/port.d.ts +0 -9
- package/dist/utils/port.d.ts.map +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BelongsTo, Column, Entity, HasMany, PrimaryKey, col } from "metal-orm";
|
|
2
|
+
import type { BelongsToReference, HasManyCollection } from "metal-orm";
|
|
3
|
+
import { Artist } from "./artist.entity";
|
|
4
|
+
import { Track } from "./track.entity";
|
|
5
|
+
|
|
6
|
+
@Entity({ tableName: "albums" })
|
|
7
|
+
export class Album {
|
|
8
|
+
@PrimaryKey(col.autoIncrement(col.int()))
|
|
9
|
+
id!: number;
|
|
10
|
+
|
|
11
|
+
@Column(col.notNull(col.text()))
|
|
12
|
+
title!: string;
|
|
13
|
+
|
|
14
|
+
@Column(col.int())
|
|
15
|
+
releaseYear?: number | null;
|
|
16
|
+
|
|
17
|
+
@Column(col.notNull(col.int()))
|
|
18
|
+
artistId!: number;
|
|
19
|
+
|
|
20
|
+
@Column(col.notNull(col.text()))
|
|
21
|
+
createdAt!: string;
|
|
22
|
+
|
|
23
|
+
@BelongsTo({ target: () => Artist, foreignKey: "artistId" })
|
|
24
|
+
artist!: BelongsToReference<Artist>;
|
|
25
|
+
|
|
26
|
+
@HasMany({ target: () => Track, foreignKey: "albumId" })
|
|
27
|
+
tracks!: HasManyCollection<Track>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createExpressApp } from "../../src";
|
|
2
|
+
import { initializeDatabase } from "./db";
|
|
3
|
+
import { AlbumController } from "./album.controller";
|
|
4
|
+
import { ArtistController } from "./artist.controller";
|
|
5
|
+
import { TrackController } from "./track.controller";
|
|
6
|
+
import { startExampleServer } from "../utils/start-server";
|
|
7
|
+
|
|
8
|
+
export async function start() {
|
|
9
|
+
await initializeDatabase();
|
|
10
|
+
|
|
11
|
+
const app = createExpressApp({
|
|
12
|
+
controllers: [ArtistController, AlbumController, TrackController],
|
|
13
|
+
openApi: {
|
|
14
|
+
info: { title: "Music Library API", version: "1.0.0" },
|
|
15
|
+
docs: true
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
startExampleServer(app, { name: "Music Library API" });
|
|
19
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Body,
|
|
3
|
+
Controller,
|
|
4
|
+
Delete,
|
|
5
|
+
Get,
|
|
6
|
+
HttpError,
|
|
7
|
+
Params,
|
|
8
|
+
Patch,
|
|
9
|
+
Post,
|
|
10
|
+
Put,
|
|
11
|
+
Query,
|
|
12
|
+
Returns,
|
|
13
|
+
parsePagination,
|
|
14
|
+
type RequestContext
|
|
15
|
+
} from "../../src";
|
|
16
|
+
import { applyFilter, toPagedResponse } from "metal-orm";
|
|
17
|
+
import type { SimpleWhereInput } from "metal-orm";
|
|
18
|
+
import { entityRef, selectFromEntity } from "metal-orm";
|
|
19
|
+
import { createSession } from "./db";
|
|
20
|
+
import {
|
|
21
|
+
CreateArtistDto,
|
|
22
|
+
ReplaceArtistDto,
|
|
23
|
+
UpdateArtistDto,
|
|
24
|
+
AlbumDto,
|
|
25
|
+
ArtistDto,
|
|
26
|
+
ArtistErrors,
|
|
27
|
+
ArtistParamsDto,
|
|
28
|
+
ArtistPagedResponseDto,
|
|
29
|
+
ArtistQueryDto,
|
|
30
|
+
ArtistQueryDtoClass
|
|
31
|
+
} from "./artist.dtos";
|
|
32
|
+
import {
|
|
33
|
+
CreateArtistAlbumDto,
|
|
34
|
+
CreateArtistAlbumDtoClass,
|
|
35
|
+
AlbumQueryDto,
|
|
36
|
+
AlbumQueryDtoClass,
|
|
37
|
+
AlbumPagedResponseDto
|
|
38
|
+
} from "./album.dtos";
|
|
39
|
+
import { Album as AlbumEntity } from "./album.entity";
|
|
40
|
+
import { Artist } from "./artist.entity";
|
|
41
|
+
|
|
42
|
+
type IntegerOptions = {
|
|
43
|
+
min?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
clamp?: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function parseInteger(value: unknown, options: IntegerOptions = {}): number | undefined {
|
|
49
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const result = value;
|
|
53
|
+
if (options.min !== undefined && result < options.min) {
|
|
54
|
+
return options.clamp ? options.min : undefined;
|
|
55
|
+
}
|
|
56
|
+
if (options.max !== undefined && result > options.max) {
|
|
57
|
+
return options.clamp ? options.max : undefined;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function requireArtistId(value: unknown): number {
|
|
63
|
+
const id = parseInteger(value, { min: 1 });
|
|
64
|
+
if (id === undefined) {
|
|
65
|
+
const message = "Invalid artist id.";
|
|
66
|
+
throw new HttpError(
|
|
67
|
+
400,
|
|
68
|
+
message,
|
|
69
|
+
buildErrorBody(message, "INVALID_ARTIST_ID", [{ field: "id", message }])
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return id;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const artistRef = entityRef(Artist);
|
|
76
|
+
const albumRef = entityRef(AlbumEntity);
|
|
77
|
+
|
|
78
|
+
type ArtistFilter = SimpleWhereInput<typeof Artist, "name" | "genre">;
|
|
79
|
+
type ArtistAlbumFilter = SimpleWhereInput<typeof AlbumEntity, "artistId">;
|
|
80
|
+
type OrmSession = ReturnType<typeof createSession>;
|
|
81
|
+
|
|
82
|
+
type ErrorDetail = { field: string; message: string };
|
|
83
|
+
|
|
84
|
+
function buildErrorBody(message: string, code: string, errors?: ErrorDetail[]) {
|
|
85
|
+
return { message, code, errors };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function withSession<T>(handler: (session: OrmSession) => Promise<T>) {
|
|
89
|
+
const session = createSession();
|
|
90
|
+
try {
|
|
91
|
+
return await handler(session);
|
|
92
|
+
} finally {
|
|
93
|
+
await session.dispose();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function getArtistOrThrow(session: OrmSession, id: number): Promise<Artist> {
|
|
98
|
+
const artist = await session.find(Artist, id);
|
|
99
|
+
if (!artist) {
|
|
100
|
+
const message = "Artist not found.";
|
|
101
|
+
throw new HttpError(404, message, buildErrorBody(message, "ARTIST_NOT_FOUND"));
|
|
102
|
+
}
|
|
103
|
+
return artist;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function buildArtistFilter(query?: ArtistQueryDto): ArtistFilter | undefined {
|
|
107
|
+
if (!query) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
const filter: ArtistFilter = {};
|
|
111
|
+
if (query.nameContains) {
|
|
112
|
+
filter.name = { contains: query.nameContains };
|
|
113
|
+
}
|
|
114
|
+
if (query.genreContains) {
|
|
115
|
+
filter.genre = { contains: query.genreContains };
|
|
116
|
+
}
|
|
117
|
+
return Object.keys(filter).length ? filter : undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@Controller("/artists")
|
|
121
|
+
export class ArtistController {
|
|
122
|
+
@Get("/")
|
|
123
|
+
@Query(ArtistQueryDtoClass)
|
|
124
|
+
@Returns(ArtistPagedResponseDto)
|
|
125
|
+
async list(ctx: RequestContext<unknown, ArtistQueryDto>) {
|
|
126
|
+
const paginationQuery = (ctx.query ?? {}) as Record<string, unknown>;
|
|
127
|
+
const { page, pageSize } = parsePagination(paginationQuery);
|
|
128
|
+
return withSession(async (session) => {
|
|
129
|
+
const filters = buildArtistFilter(ctx.query);
|
|
130
|
+
const query = applyFilter(
|
|
131
|
+
selectFromEntity(Artist).orderBy(artistRef.id, "ASC"),
|
|
132
|
+
Artist,
|
|
133
|
+
filters
|
|
134
|
+
);
|
|
135
|
+
const paged = await query.executePaged(session, { page, pageSize });
|
|
136
|
+
return toPagedResponse(paged);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@Get("/:id")
|
|
141
|
+
@Params(ArtistParamsDto)
|
|
142
|
+
@Returns(ArtistDto)
|
|
143
|
+
@ArtistErrors
|
|
144
|
+
async getOne(ctx: RequestContext<unknown, undefined, ArtistParamsDto>) {
|
|
145
|
+
const id = requireArtistId(ctx.params.id);
|
|
146
|
+
return withSession(async (session) => {
|
|
147
|
+
const artist = await getArtistOrThrow(session, id);
|
|
148
|
+
return artist as ArtistDto;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@Post("/")
|
|
153
|
+
@Body(CreateArtistDto)
|
|
154
|
+
@Returns({ status: 201, schema: ArtistDto })
|
|
155
|
+
async create(ctx: RequestContext<CreateArtistDto>) {
|
|
156
|
+
return withSession(async (session) => {
|
|
157
|
+
const artist = new Artist();
|
|
158
|
+
artist.name = ctx.body.name;
|
|
159
|
+
artist.genre = ctx.body.genre ?? null;
|
|
160
|
+
artist.country = ctx.body.country ?? null;
|
|
161
|
+
artist.formedYear = ctx.body.formedYear ?? null;
|
|
162
|
+
artist.createdAt = new Date().toISOString();
|
|
163
|
+
await session.persist(artist);
|
|
164
|
+
await session.commit();
|
|
165
|
+
return artist as ArtistDto;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Put("/:id")
|
|
170
|
+
@Params(ArtistParamsDto)
|
|
171
|
+
@Body(ReplaceArtistDto)
|
|
172
|
+
@Returns(ArtistDto)
|
|
173
|
+
@ArtistErrors
|
|
174
|
+
async replace(ctx: RequestContext<ReplaceArtistDto, undefined, ArtistParamsDto>) {
|
|
175
|
+
const id = requireArtistId(ctx.params.id);
|
|
176
|
+
return withSession(async (session) => {
|
|
177
|
+
const entity = await getArtistOrThrow(session, id);
|
|
178
|
+
entity.name = ctx.body.name;
|
|
179
|
+
entity.genre = ctx.body.genre ?? null;
|
|
180
|
+
entity.country = ctx.body.country ?? null;
|
|
181
|
+
entity.formedYear = ctx.body.formedYear ?? null;
|
|
182
|
+
await session.commit();
|
|
183
|
+
return entity as ArtistDto;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@Patch("/:id")
|
|
188
|
+
@Params(ArtistParamsDto)
|
|
189
|
+
@Body(UpdateArtistDto)
|
|
190
|
+
@Returns(ArtistDto)
|
|
191
|
+
@ArtistErrors
|
|
192
|
+
async update(ctx: RequestContext<UpdateArtistDto, undefined, ArtistParamsDto>) {
|
|
193
|
+
const id = requireArtistId(ctx.params.id);
|
|
194
|
+
return withSession(async (session) => {
|
|
195
|
+
const entity = await getArtistOrThrow(session, id);
|
|
196
|
+
if (ctx.body.name !== undefined) {
|
|
197
|
+
entity.name = ctx.body.name;
|
|
198
|
+
}
|
|
199
|
+
if (ctx.body.genre !== undefined) {
|
|
200
|
+
entity.genre = ctx.body.genre ?? null;
|
|
201
|
+
}
|
|
202
|
+
if (ctx.body.country !== undefined) {
|
|
203
|
+
entity.country = ctx.body.country ?? null;
|
|
204
|
+
}
|
|
205
|
+
if (ctx.body.formedYear !== undefined) {
|
|
206
|
+
entity.formedYear = ctx.body.formedYear ?? null;
|
|
207
|
+
}
|
|
208
|
+
await session.commit();
|
|
209
|
+
return entity as ArtistDto;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@Get("/:id/albums")
|
|
214
|
+
@Params(ArtistParamsDto)
|
|
215
|
+
@Query(AlbumQueryDtoClass)
|
|
216
|
+
@Returns(AlbumPagedResponseDto)
|
|
217
|
+
@ArtistErrors
|
|
218
|
+
async listAlbums(
|
|
219
|
+
ctx: RequestContext<unknown, AlbumQueryDto, ArtistParamsDto>
|
|
220
|
+
) {
|
|
221
|
+
const id = requireArtistId(ctx.params.id);
|
|
222
|
+
const paginationQuery = (ctx.query ?? {}) as Record<string, unknown>;
|
|
223
|
+
const { page, pageSize } = parsePagination(paginationQuery);
|
|
224
|
+
return withSession(async (session) => {
|
|
225
|
+
await getArtistOrThrow(session, id);
|
|
226
|
+
const filters: ArtistAlbumFilter = {
|
|
227
|
+
artistId: { equals: id }
|
|
228
|
+
};
|
|
229
|
+
const query = applyFilter(
|
|
230
|
+
selectFromEntity(AlbumEntity).orderBy(albumRef.id, "ASC"),
|
|
231
|
+
AlbumEntity,
|
|
232
|
+
filters
|
|
233
|
+
);
|
|
234
|
+
const paged = await query.executePaged(session, { page, pageSize });
|
|
235
|
+
return toPagedResponse(paged);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@Post("/:id/albums")
|
|
240
|
+
@Params(ArtistParamsDto)
|
|
241
|
+
@Body(CreateArtistAlbumDtoClass)
|
|
242
|
+
@Returns({ status: 201, schema: AlbumDto })
|
|
243
|
+
@ArtistErrors
|
|
244
|
+
async createAlbum(
|
|
245
|
+
ctx: RequestContext<CreateArtistAlbumDto, undefined, ArtistParamsDto>
|
|
246
|
+
) {
|
|
247
|
+
const id = requireArtistId(ctx.params.id);
|
|
248
|
+
return withSession(async (session) => {
|
|
249
|
+
const artist = await getArtistOrThrow(session, id);
|
|
250
|
+
const album = artist.albums.add({
|
|
251
|
+
title: ctx.body.title,
|
|
252
|
+
releaseYear: ctx.body.releaseYear ?? null,
|
|
253
|
+
createdAt: new Date().toISOString()
|
|
254
|
+
});
|
|
255
|
+
await session.commit();
|
|
256
|
+
return album as AlbumDto;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@Delete("/:id")
|
|
261
|
+
@Params(ArtistParamsDto)
|
|
262
|
+
@Returns({ status: 204 })
|
|
263
|
+
@ArtistErrors
|
|
264
|
+
async remove(ctx: RequestContext<unknown, undefined, ArtistParamsDto>) {
|
|
265
|
+
const id = requireArtistId(ctx.params.id);
|
|
266
|
+
return withSession(async (session) => {
|
|
267
|
+
const artist = await getArtistOrThrow(session, id);
|
|
268
|
+
await session.remove(artist);
|
|
269
|
+
await session.commit();
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Errors,
|
|
3
|
+
createMetalCrudDtoClasses,
|
|
4
|
+
createMetalDtoOverrides,
|
|
5
|
+
createPagedResponseDtoClass,
|
|
6
|
+
createPagedFilterQueryDtoClass,
|
|
7
|
+
StandardErrorDto,
|
|
8
|
+
t
|
|
9
|
+
} from "../../src";
|
|
10
|
+
import { Artist } from "./artist.entity";
|
|
11
|
+
import { AlbumDto, CreateArtistAlbumDto } from "./album.dtos";
|
|
12
|
+
|
|
13
|
+
const artistOverrides = createMetalDtoOverrides(Artist, {
|
|
14
|
+
overrides: {
|
|
15
|
+
genre: t.nullable(t.string()),
|
|
16
|
+
country: t.nullable(t.string()),
|
|
17
|
+
formedYear: t.nullable(t.integer({ minimum: 1000, maximum: 9999 }))
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const artistCrud = createMetalCrudDtoClasses(Artist, {
|
|
22
|
+
overrides: artistOverrides,
|
|
23
|
+
response: { description: "Artist returned by API." },
|
|
24
|
+
mutationExclude: ["id", "createdAt"]
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const {
|
|
28
|
+
response: ArtistDto,
|
|
29
|
+
create: CreateArtistDto,
|
|
30
|
+
replace: ReplaceArtistDto,
|
|
31
|
+
update: UpdateArtistDto,
|
|
32
|
+
params: ArtistParamsDto
|
|
33
|
+
} = artistCrud;
|
|
34
|
+
|
|
35
|
+
export type ArtistDto = Omit<Artist, "albums">;
|
|
36
|
+
type ArtistMutationDto = Omit<ArtistDto, "id" | "createdAt">;
|
|
37
|
+
export type CreateArtistDto = ArtistMutationDto;
|
|
38
|
+
export type ReplaceArtistDto = ArtistMutationDto;
|
|
39
|
+
export type UpdateArtistDto = Partial<ArtistMutationDto>;
|
|
40
|
+
export type ArtistParamsDto = InstanceType<typeof ArtistParamsDto>;
|
|
41
|
+
|
|
42
|
+
export const ArtistQueryDtoClass = createPagedFilterQueryDtoClass({
|
|
43
|
+
name: "ArtistQueryDto",
|
|
44
|
+
filters: {
|
|
45
|
+
nameContains: { schema: t.string({ minLength: 1 }), operator: "contains" },
|
|
46
|
+
genreContains: { schema: t.string({ minLength: 1 }), operator: "contains" }
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export interface ArtistQueryDto {
|
|
51
|
+
page?: number;
|
|
52
|
+
pageSize?: number;
|
|
53
|
+
nameContains?: string;
|
|
54
|
+
genreContains?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const ArtistPagedResponseDto = createPagedResponseDtoClass({
|
|
58
|
+
name: "ArtistPagedResponseDto",
|
|
59
|
+
itemDto: ArtistDto,
|
|
60
|
+
description: "Paged artist list response."
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const ArtistErrors = Errors(StandardErrorDto, [
|
|
64
|
+
{ status: 400, description: "Invalid artist id." },
|
|
65
|
+
{ status: 404, description: "Artist not found." }
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
export { AlbumDto, CreateArtistAlbumDto };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Column, Entity, HasMany, PrimaryKey, col } from "metal-orm";
|
|
2
|
+
import type { HasManyCollection } from "metal-orm";
|
|
3
|
+
import { Album } from "./album.entity";
|
|
4
|
+
|
|
5
|
+
@Entity({ tableName: "artists" })
|
|
6
|
+
export class Artist {
|
|
7
|
+
@PrimaryKey(col.autoIncrement(col.int()))
|
|
8
|
+
id!: number;
|
|
9
|
+
|
|
10
|
+
@Column(col.notNull(col.text()))
|
|
11
|
+
name!: string;
|
|
12
|
+
|
|
13
|
+
@Column(col.text())
|
|
14
|
+
genre?: string | null;
|
|
15
|
+
|
|
16
|
+
@Column(col.text())
|
|
17
|
+
country?: string | null;
|
|
18
|
+
|
|
19
|
+
@Column(col.int())
|
|
20
|
+
formedYear?: number | null;
|
|
21
|
+
|
|
22
|
+
@Column(col.notNull(col.text()))
|
|
23
|
+
createdAt!: string;
|
|
24
|
+
|
|
25
|
+
@HasMany({ target: () => Album, foreignKey: "artistId" })
|
|
26
|
+
albums!: HasManyCollection<Album>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import sqlite3 from "sqlite3";
|
|
2
|
+
import {
|
|
3
|
+
Orm,
|
|
4
|
+
SqliteDialect,
|
|
5
|
+
createSqliteExecutor,
|
|
6
|
+
type SqliteClientLike
|
|
7
|
+
} from "metal-orm";
|
|
8
|
+
|
|
9
|
+
let db: sqlite3.Database | null = null;
|
|
10
|
+
let orm: Orm | null = null;
|
|
11
|
+
|
|
12
|
+
function execSql(database: sqlite3.Database, sql: string): Promise<void> {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
database.exec(sql, (err) => {
|
|
15
|
+
if (err) {
|
|
16
|
+
reject(err);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
resolve();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function createSqliteClient(database: sqlite3.Database): SqliteClientLike {
|
|
25
|
+
return {
|
|
26
|
+
all(sql, params = []) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
database.all(sql, params, (err, rows) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
reject(err);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
resolve(rows as Record<string, unknown>[]);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
beginTransaction() {
|
|
38
|
+
return execSql(database, "BEGIN");
|
|
39
|
+
},
|
|
40
|
+
commitTransaction() {
|
|
41
|
+
return execSql(database, "COMMIT");
|
|
42
|
+
},
|
|
43
|
+
rollbackTransaction() {
|
|
44
|
+
return execSql(database, "ROLLBACK");
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function initializeDatabase() {
|
|
50
|
+
db = new sqlite3.Database(":memory:");
|
|
51
|
+
await execSql(db, "pragma foreign_keys = ON");
|
|
52
|
+
await execSql(
|
|
53
|
+
db,
|
|
54
|
+
"create table artists (id integer primary key autoincrement, name text not null, genre text, country text, formedYear integer, createdAt text not null)"
|
|
55
|
+
);
|
|
56
|
+
await execSql(
|
|
57
|
+
db,
|
|
58
|
+
"create table albums (id integer primary key autoincrement, title text not null, releaseYear integer, artistId integer not null, createdAt text not null, foreign key(artistId) references artists(id))"
|
|
59
|
+
);
|
|
60
|
+
await execSql(
|
|
61
|
+
db,
|
|
62
|
+
"create table tracks (id integer primary key autoincrement, title text not null, durationSeconds integer, trackNumber integer, albumId integer not null, createdAt text not null, foreign key(albumId) references albums(id))"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
await execSql(db, `
|
|
66
|
+
INSERT INTO artists (name, genre, country, formedYear, createdAt) VALUES
|
|
67
|
+
('The Beatles', 'Rock', 'United Kingdom', 1960, '2026-01-17T00:00:00.000Z'),
|
|
68
|
+
('Led Zeppelin', 'Rock', 'United Kingdom', 1968, '2026-01-17T00:00:00.000Z'),
|
|
69
|
+
('Pink Floyd', 'Progressive Rock', 'United Kingdom', 1965, '2026-01-17T00:00:00.000Z')
|
|
70
|
+
`);
|
|
71
|
+
|
|
72
|
+
await execSql(db, `
|
|
73
|
+
INSERT INTO albums (title, releaseYear, artistId, createdAt) VALUES
|
|
74
|
+
('Abbey Road', 1969, 1, '2026-01-17T00:00:00.000Z'),
|
|
75
|
+
('Led Zeppelin IV', 1971, 2, '2026-01-17T00:00:00.000Z'),
|
|
76
|
+
('The Dark Side of the Moon', 1973, 3, '2026-01-17T00:00:00.000Z'),
|
|
77
|
+
('Sgt. Pepper''s Lonely Hearts Club Band', 1967, 1, '2026-01-17T00:00:00.000Z')
|
|
78
|
+
`);
|
|
79
|
+
|
|
80
|
+
await execSql(db, `
|
|
81
|
+
INSERT INTO tracks (title, durationSeconds, trackNumber, albumId, createdAt) VALUES
|
|
82
|
+
('Come Together', 259, 1, 1, '2026-01-17T00:00:00.000Z'),
|
|
83
|
+
('Something', 182, 2, 1, '2026-01-17T00:00:00.000Z'),
|
|
84
|
+
('Maxwell''s Silver Hammer', 207, 3, 1, '2026-01-17T00:00:00.000Z'),
|
|
85
|
+
('Oh! Darling', 207, 4, 1, '2026-01-17T00:00:00.000Z'),
|
|
86
|
+
('Octopus''s Garden', 169, 5, 1, '2026-01-17T00:00:00.000Z'),
|
|
87
|
+
('I Want You (She''s So Heavy)', 467, 6, 1, '2026-01-17T00:00:00.000Z'),
|
|
88
|
+
('Here Comes the Sun', 185, 7, 1, '2026-01-17T00:00:00.000Z'),
|
|
89
|
+
('Because', 165, 8, 1, '2026-01-17T00:00:00.000Z'),
|
|
90
|
+
('You Never Give Me Your Money', 239, 9, 1, '2026-01-17T00:00:00.000Z'),
|
|
91
|
+
('Sun King', 146, 10, 1, '2026-01-17T00:00:00.000Z'),
|
|
92
|
+
('Mean Mr. Mustard', 68, 11, 1, '2026-01-17T00:00:00.000Z'),
|
|
93
|
+
('Polythene Pam', 75, 12, 1, '2026-01-17T00:00:00.000Z'),
|
|
94
|
+
('She Came In Through the Bathroom Window', 119, 13, 1, '2026-01-17T00:00:00.000Z'),
|
|
95
|
+
('Golden Slumbers', 90, 14, 1, '2026-01-17T00:00:00.000Z'),
|
|
96
|
+
('Carry That Weight', 97, 15, 1, '2026-01-17T00:00:00.000Z'),
|
|
97
|
+
('The End', 130, 16, 1, '2026-01-17T00:00:00.000Z'),
|
|
98
|
+
('Her Majesty', 23, 17, 1, '2026-01-17T00:00:00.000Z'),
|
|
99
|
+
('Black Dog', 296, 1, 2, '2026-01-17T00:00:00.000Z'),
|
|
100
|
+
('Rock and Roll', 219, 2, 2, '2026-01-17T00:00:00.000Z'),
|
|
101
|
+
('The Battle of Evermore', 354, 3, 2, '2026-01-17T00:00:00.000Z'),
|
|
102
|
+
('Stairway to Heaven', 482, 4, 2, '2026-01-17T00:00:00.000Z'),
|
|
103
|
+
('Misty Mountain Hop', 285, 5, 2, '2026-01-17T00:00:00.000Z'),
|
|
104
|
+
('Four Sticks', 284, 6, 2, '2026-01-17T00:00:00.000Z'),
|
|
105
|
+
('Going to California', 209, 7, 2, '2026-01-17T00:00:00.000Z'),
|
|
106
|
+
('When the Levee Breaks', 427, 8, 2, '2026-01-17T00:00:00.000Z'),
|
|
107
|
+
('Speak to Me', 90, 1, 3, '2026-01-17T00:00:00.000Z'),
|
|
108
|
+
('Breathe', 156, 2, 3, '2026-01-17T00:00:00.000Z'),
|
|
109
|
+
('On the Run', 216, 3, 3, '2026-01-17T00:00:00.000Z'),
|
|
110
|
+
('Time', 404, 4, 3, '2026-01-17T00:00:00.000Z'),
|
|
111
|
+
('The Great Gig in the Sky', 274, 5, 3, '2026-01-17T00:00:00.000Z'),
|
|
112
|
+
('Money', 382, 6, 3, '2026-01-17T00:00:00.000Z'),
|
|
113
|
+
('Us and Them', 462, 7, 3, '2026-01-17T00:00:00.000Z'),
|
|
114
|
+
('Any Colour You Like', 206, 8, 3, '2026-01-17T00:00:00.000Z'),
|
|
115
|
+
('Brain Damage', 228, 9, 3, '2026-01-17T00:00:00.000Z'),
|
|
116
|
+
('Eclipse', 123, 10, 3, '2026-01-17T00:00:00.000Z'),
|
|
117
|
+
('Sgt. Pepper''s Lonely Hearts Club Band', 120, 1, 4, '2026-01-17T00:00:00.000Z'),
|
|
118
|
+
('With a Little Help from My Friends', 159, 2, 4, '2026-01-17T00:00:00.000Z'),
|
|
119
|
+
('Lucy in the Sky with Diamonds', 209, 3, 4, '2026-01-17T00:00:00.000Z'),
|
|
120
|
+
('Getting Better', 149, 4, 4, '2026-01-17T00:00:00.000Z'),
|
|
121
|
+
('Fixing a Hole', 136, 5, 4, '2026-01-17T00:00:00.000Z'),
|
|
122
|
+
('She''s Leaving Home', 271, 6, 4, '2026-01-17T00:00:00.000Z'),
|
|
123
|
+
('Being for the Benefit of Mr. Kite!', 184, 7, 4, '2026-01-17T00:00:00.000Z'),
|
|
124
|
+
('Within You Without You', 311, 8, 4, '2026-01-17T00:00:00.000Z'),
|
|
125
|
+
('When I''m Sixty-Four', 161, 9, 4, '2026-01-17T00:00:00.000Z'),
|
|
126
|
+
('Lovely Rita', 172, 10, 4, '2026-01-17T00:00:00.000Z'),
|
|
127
|
+
('Good Morning Good Morning', 158, 11, 4, '2026-01-17T00:00:00.000Z'),
|
|
128
|
+
('Sgt. Pepper''s Lonely Hearts Club Band (Reprise)', 61, 12, 4, '2026-01-17T00:00:00.000Z'),
|
|
129
|
+
('A Day in the Life', 334, 13, 4, '2026-01-17T00:00:00.000Z')
|
|
130
|
+
`);
|
|
131
|
+
|
|
132
|
+
const executor = createSqliteExecutor(createSqliteClient(db));
|
|
133
|
+
orm = new Orm({
|
|
134
|
+
dialect: new SqliteDialect(),
|
|
135
|
+
executorFactory: {
|
|
136
|
+
createExecutor: () => executor,
|
|
137
|
+
createTransactionalExecutor: () => executor,
|
|
138
|
+
dispose: async () => {}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function createSession() {
|
|
144
|
+
if (!orm) {
|
|
145
|
+
throw new Error("ORM not initialized");
|
|
146
|
+
}
|
|
147
|
+
return orm.createSession();
|
|
148
|
+
}
|