typhex 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +417 -0
- package/SECURITY.md +32 -0
- package/dist/arrow/aggregates.d.ts +12 -0
- package/dist/arrow/aggregates.d.ts.map +1 -0
- package/dist/arrow/aggregates.js +32 -0
- package/dist/arrow/aggregates.js.map +1 -0
- package/dist/arrow/constants.d.ts +15 -0
- package/dist/arrow/constants.d.ts.map +1 -0
- package/dist/arrow/constants.js +42 -0
- package/dist/arrow/constants.js.map +1 -0
- package/dist/arrow/index.d.ts +7 -0
- package/dist/arrow/index.d.ts.map +1 -0
- package/dist/arrow/index.js +7 -0
- package/dist/arrow/index.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load-config.d.ts +19 -0
- package/dist/config/load-config.d.ts.map +1 -0
- package/dist/config/load-config.js +84 -0
- package/dist/config/load-config.js.map +1 -0
- package/dist/config/load-env.d.ts +7 -0
- package/dist/config/load-env.d.ts.map +1 -0
- package/dist/config/load-env.js +62 -0
- package/dist/config/load-env.js.map +1 -0
- package/dist/config/types.d.ts +20 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +10 -0
- package/dist/config/types.js.map +1 -0
- package/dist/dbs/base-migrator.d.ts +20 -0
- package/dist/dbs/base-migrator.d.ts.map +1 -0
- package/dist/dbs/base-migrator.js +112 -0
- package/dist/dbs/base-migrator.js.map +1 -0
- package/dist/dbs/index.d.ts +9 -0
- package/dist/dbs/index.d.ts.map +1 -0
- package/dist/dbs/index.js +17 -0
- package/dist/dbs/index.js.map +1 -0
- package/dist/dbs/postgres/dialect.d.ts +8 -0
- package/dist/dbs/postgres/dialect.d.ts.map +1 -0
- package/dist/dbs/postgres/dialect.js +17 -0
- package/dist/dbs/postgres/dialect.js.map +1 -0
- package/dist/dbs/postgres/driver.d.ts +42 -0
- package/dist/dbs/postgres/driver.d.ts.map +1 -0
- package/dist/dbs/postgres/driver.js +111 -0
- package/dist/dbs/postgres/driver.js.map +1 -0
- package/dist/dbs/postgres/index.d.ts +6 -0
- package/dist/dbs/postgres/index.d.ts.map +1 -0
- package/dist/dbs/postgres/index.js +5 -0
- package/dist/dbs/postgres/index.js.map +1 -0
- package/dist/dbs/postgres/migrator.d.ts +13 -0
- package/dist/dbs/postgres/migrator.d.ts.map +1 -0
- package/dist/dbs/postgres/migrator.js +22 -0
- package/dist/dbs/postgres/migrator.js.map +1 -0
- package/dist/dbs/postgres/query-compiler.d.ts +22 -0
- package/dist/dbs/postgres/query-compiler.d.ts.map +1 -0
- package/dist/dbs/postgres/query-compiler.js +140 -0
- package/dist/dbs/postgres/query-compiler.js.map +1 -0
- package/dist/dbs/postgres/trx.d.ts +16 -0
- package/dist/dbs/postgres/trx.d.ts.map +1 -0
- package/dist/dbs/postgres/trx.js +68 -0
- package/dist/dbs/postgres/trx.js.map +1 -0
- package/dist/dbs/query-compiler.d.ts +135 -0
- package/dist/dbs/query-compiler.d.ts.map +1 -0
- package/dist/dbs/query-compiler.js +775 -0
- package/dist/dbs/query-compiler.js.map +1 -0
- package/dist/dbs/sqlite/dialect.d.ts +8 -0
- package/dist/dbs/sqlite/dialect.d.ts.map +1 -0
- package/dist/dbs/sqlite/dialect.js +17 -0
- package/dist/dbs/sqlite/dialect.js.map +1 -0
- package/dist/dbs/sqlite/driver.d.ts +9 -0
- package/dist/dbs/sqlite/driver.d.ts.map +1 -0
- package/dist/dbs/sqlite/driver.js +66 -0
- package/dist/dbs/sqlite/driver.js.map +1 -0
- package/dist/dbs/sqlite/index.d.ts +6 -0
- package/dist/dbs/sqlite/index.d.ts.map +1 -0
- package/dist/dbs/sqlite/index.js +5 -0
- package/dist/dbs/sqlite/index.js.map +1 -0
- package/dist/dbs/sqlite/migrator.d.ts +13 -0
- package/dist/dbs/sqlite/migrator.d.ts.map +1 -0
- package/dist/dbs/sqlite/migrator.js +22 -0
- package/dist/dbs/sqlite/migrator.js.map +1 -0
- package/dist/dbs/sqlite/query-compiler.d.ts +26 -0
- package/dist/dbs/sqlite/query-compiler.d.ts.map +1 -0
- package/dist/dbs/sqlite/query-compiler.js +80 -0
- package/dist/dbs/sqlite/query-compiler.js.map +1 -0
- package/dist/dbs/sqlite/trx.d.ts +13 -0
- package/dist/dbs/sqlite/trx.d.ts.map +1 -0
- package/dist/dbs/sqlite/trx.js +69 -0
- package/dist/dbs/sqlite/trx.js.map +1 -0
- package/dist/dbs/types.d.ts +92 -0
- package/dist/dbs/types.d.ts.map +1 -0
- package/dist/dbs/types.js +26 -0
- package/dist/dbs/types.js.map +1 -0
- package/dist/dialect.d.ts +3 -0
- package/dist/dialect.d.ts.map +1 -0
- package/dist/dialect.js +2 -0
- package/dist/dialect.js.map +1 -0
- package/dist/driver/factory.d.ts +19 -0
- package/dist/driver/factory.d.ts.map +1 -0
- package/dist/driver/factory.js +24 -0
- package/dist/driver/factory.js.map +1 -0
- package/dist/driver/index.d.ts +6 -0
- package/dist/driver/index.d.ts.map +1 -0
- package/dist/driver/index.js +3 -0
- package/dist/driver/index.js.map +1 -0
- package/dist/driver/sqlite.d.ts +15 -0
- package/dist/driver/sqlite.d.ts.map +1 -0
- package/dist/driver/sqlite.js +74 -0
- package/dist/driver/sqlite.js.map +1 -0
- package/dist/driver/types.d.ts +75 -0
- package/dist/driver/types.d.ts.map +1 -0
- package/dist/driver/types.js +2 -0
- package/dist/driver/types.js.map +1 -0
- package/dist/entity/entity.d.ts +67 -0
- package/dist/entity/entity.d.ts.map +1 -0
- package/dist/entity/entity.js +139 -0
- package/dist/entity/entity.js.map +1 -0
- package/dist/entity/global-driver.d.ts +38 -0
- package/dist/entity/global-driver.d.ts.map +1 -0
- package/dist/entity/global-driver.js +109 -0
- package/dist/entity/global-driver.js.map +1 -0
- package/dist/entity/index.d.ts +8 -0
- package/dist/entity/index.d.ts.map +1 -0
- package/dist/entity/index.js +3 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/entity/pk-columns.d.ts +5 -0
- package/dist/entity/pk-columns.d.ts.map +1 -0
- package/dist/entity/pk-columns.js +14 -0
- package/dist/entity/pk-columns.js.map +1 -0
- package/dist/entity/relations.d.ts +134 -0
- package/dist/entity/relations.d.ts.map +1 -0
- package/dist/entity/relations.js +23 -0
- package/dist/entity/relations.js.map +1 -0
- package/dist/entity/schema-inference.d.ts +77 -0
- package/dist/entity/schema-inference.d.ts.map +1 -0
- package/dist/entity/schema-inference.js +6 -0
- package/dist/entity/schema-inference.js.map +1 -0
- package/dist/entity/types.d.ts +30 -0
- package/dist/entity/types.d.ts.map +1 -0
- package/dist/entity/types.js +5 -0
- package/dist/entity/types.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/index.d.ts +2 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +2 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/types.d.ts +148 -0
- package/dist/ir/types.d.ts.map +1 -0
- package/dist/ir/types.js +97 -0
- package/dist/ir/types.js.map +1 -0
- package/dist/migration/cli.d.ts +18 -0
- package/dist/migration/cli.d.ts.map +1 -0
- package/dist/migration/cli.js +236 -0
- package/dist/migration/cli.js.map +1 -0
- package/dist/migration/diff.d.ts +10 -0
- package/dist/migration/diff.d.ts.map +1 -0
- package/dist/migration/diff.js +10 -0
- package/dist/migration/diff.js.map +1 -0
- package/dist/migration/generator.d.ts +12 -0
- package/dist/migration/generator.d.ts.map +1 -0
- package/dist/migration/generator.js +98 -0
- package/dist/migration/generator.js.map +1 -0
- package/dist/migration/index.d.ts +7 -0
- package/dist/migration/index.d.ts.map +1 -0
- package/dist/migration/index.js +5 -0
- package/dist/migration/index.js.map +1 -0
- package/dist/migration/runner.d.ts +32 -0
- package/dist/migration/runner.d.ts.map +1 -0
- package/dist/migration/runner.js +279 -0
- package/dist/migration/runner.js.map +1 -0
- package/dist/migration/topo-sort.d.ts +12 -0
- package/dist/migration/topo-sort.d.ts.map +1 -0
- package/dist/migration/topo-sort.js +42 -0
- package/dist/migration/topo-sort.js.map +1 -0
- package/dist/migration/types.d.ts +45 -0
- package/dist/migration/types.d.ts.map +1 -0
- package/dist/migration/types.js +2 -0
- package/dist/migration/types.js.map +1 -0
- package/dist/orm/aggregates.d.ts +19 -0
- package/dist/orm/aggregates.d.ts.map +1 -0
- package/dist/orm/aggregates.js +32 -0
- package/dist/orm/aggregates.js.map +1 -0
- package/dist/orm/db.d.ts +105 -0
- package/dist/orm/db.d.ts.map +1 -0
- package/dist/orm/db.js +172 -0
- package/dist/orm/db.js.map +1 -0
- package/dist/orm/expr.d.ts +125 -0
- package/dist/orm/expr.d.ts.map +1 -0
- package/dist/orm/expr.js +10 -0
- package/dist/orm/expr.js.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-batch-executor.d.ts +9 -0
- package/dist/orm/helpers/insert-graph/insert-graph-batch-executor.d.ts.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-batch-executor.js +44 -0
- package/dist/orm/helpers/insert-graph/insert-graph-batch-executor.js.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-executor.d.ts +13 -0
- package/dist/orm/helpers/insert-graph/insert-graph-executor.d.ts.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-executor.js +42 -0
- package/dist/orm/helpers/insert-graph/insert-graph-executor.js.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-planner.d.ts +46 -0
- package/dist/orm/helpers/insert-graph/insert-graph-planner.d.ts.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-planner.js +258 -0
- package/dist/orm/helpers/insert-graph/insert-graph-planner.js.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-sequential-executor.d.ts +7 -0
- package/dist/orm/helpers/insert-graph/insert-graph-sequential-executor.d.ts.map +1 -0
- package/dist/orm/helpers/insert-graph/insert-graph-sequential-executor.js +8 -0
- package/dist/orm/helpers/insert-graph/insert-graph-sequential-executor.js.map +1 -0
- package/dist/orm/helpers/insert-graph/sequence-id-assigner.d.ts +15 -0
- package/dist/orm/helpers/insert-graph/sequence-id-assigner.d.ts.map +1 -0
- package/dist/orm/helpers/insert-graph/sequence-id-assigner.js +48 -0
- package/dist/orm/helpers/insert-graph/sequence-id-assigner.js.map +1 -0
- package/dist/orm/helpers/query-plan/expr-builder.d.ts +155 -0
- package/dist/orm/helpers/query-plan/expr-builder.d.ts.map +1 -0
- package/dist/orm/helpers/query-plan/expr-builder.js +297 -0
- package/dist/orm/helpers/query-plan/expr-builder.js.map +1 -0
- package/dist/orm/helpers/query-plan/query-ir-analyzer.d.ts +48 -0
- package/dist/orm/helpers/query-plan/query-ir-analyzer.d.ts.map +1 -0
- package/dist/orm/helpers/query-plan/query-ir-analyzer.js +262 -0
- package/dist/orm/helpers/query-plan/query-ir-analyzer.js.map +1 -0
- package/dist/orm/helpers/query-plan/query-plan.d.ts +164 -0
- package/dist/orm/helpers/query-plan/query-plan.d.ts.map +1 -0
- package/dist/orm/helpers/query-plan/query-plan.js +549 -0
- package/dist/orm/helpers/query-plan/query-plan.js.map +1 -0
- package/dist/orm/helpers/query-plan/select-classifier.d.ts +161 -0
- package/dist/orm/helpers/query-plan/select-classifier.d.ts.map +1 -0
- package/dist/orm/helpers/query-plan/select-classifier.js +359 -0
- package/dist/orm/helpers/query-plan/select-classifier.js.map +1 -0
- package/dist/orm/helpers/relations/relation-assembler.d.ts +21 -0
- package/dist/orm/helpers/relations/relation-assembler.d.ts.map +1 -0
- package/dist/orm/helpers/relations/relation-assembler.js +60 -0
- package/dist/orm/helpers/relations/relation-assembler.js.map +1 -0
- package/dist/orm/helpers/relations/relation-fetcher.d.ts +30 -0
- package/dist/orm/helpers/relations/relation-fetcher.d.ts.map +1 -0
- package/dist/orm/helpers/relations/relation-fetcher.js +128 -0
- package/dist/orm/helpers/relations/relation-fetcher.js.map +1 -0
- package/dist/orm/helpers/relations/relation-joins.d.ts +74 -0
- package/dist/orm/helpers/relations/relation-joins.d.ts.map +1 -0
- package/dist/orm/helpers/relations/relation-joins.js +138 -0
- package/dist/orm/helpers/relations/relation-joins.js.map +1 -0
- package/dist/orm/helpers/relations/relation-resolver.d.ts +14 -0
- package/dist/orm/helpers/relations/relation-resolver.d.ts.map +1 -0
- package/dist/orm/helpers/relations/relation-resolver.js +25 -0
- package/dist/orm/helpers/relations/relation-resolver.js.map +1 -0
- package/dist/orm/index.d.ts +7 -0
- package/dist/orm/index.d.ts.map +1 -0
- package/dist/orm/index.js +5 -0
- package/dist/orm/index.js.map +1 -0
- package/dist/orm/query-builder.d.ts +136 -0
- package/dist/orm/query-builder.d.ts.map +1 -0
- package/dist/orm/query-builder.js +433 -0
- package/dist/orm/query-builder.js.map +1 -0
- package/dist/orm/query-helpers.d.ts +35 -0
- package/dist/orm/query-helpers.d.ts.map +1 -0
- package/dist/orm/query-helpers.js +83 -0
- package/dist/orm/query-helpers.js.map +1 -0
- package/dist/orm/query-state.d.ts +56 -0
- package/dist/orm/query-state.d.ts.map +1 -0
- package/dist/orm/query-state.js +112 -0
- package/dist/orm/query-state.js.map +1 -0
- package/dist/orm/single-row-query-builder.d.ts +18 -0
- package/dist/orm/single-row-query-builder.d.ts.map +1 -0
- package/dist/orm/single-row-query-builder.js +90 -0
- package/dist/orm/single-row-query-builder.js.map +1 -0
- package/dist/orm/trx.d.ts +40 -0
- package/dist/orm/trx.d.ts.map +1 -0
- package/dist/orm/trx.js +118 -0
- package/dist/orm/trx.js.map +1 -0
- package/dist/parser/acorn-helpers.d.ts +43 -0
- package/dist/parser/acorn-helpers.d.ts.map +1 -0
- package/dist/parser/acorn-helpers.js +104 -0
- package/dist/parser/acorn-helpers.js.map +1 -0
- package/dist/parser/acorn-member.d.ts +16 -0
- package/dist/parser/acorn-member.d.ts.map +1 -0
- package/dist/parser/acorn-member.js +31 -0
- package/dist/parser/acorn-member.js.map +1 -0
- package/dist/parser/acorn-types.d.ts +14 -0
- package/dist/parser/acorn-types.d.ts.map +1 -0
- package/dist/parser/acorn-types.js +6 -0
- package/dist/parser/acorn-types.js.map +1 -0
- package/dist/parser/arrow-source.d.ts +23 -0
- package/dist/parser/arrow-source.d.ts.map +1 -0
- package/dist/parser/arrow-source.js +70 -0
- package/dist/parser/arrow-source.js.map +1 -0
- package/dist/parser/group-by.d.ts +17 -0
- package/dist/parser/group-by.d.ts.map +1 -0
- package/dist/parser/group-by.js +62 -0
- package/dist/parser/group-by.js.map +1 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +3 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/parse-arrow.d.ts +10 -0
- package/dist/parser/parse-arrow.d.ts.map +1 -0
- package/dist/parser/parse-arrow.js +9 -0
- package/dist/parser/parse-arrow.js.map +1 -0
- package/dist/parser/predicate-walk.d.ts +24 -0
- package/dist/parser/predicate-walk.d.ts.map +1 -0
- package/dist/parser/predicate-walk.js +247 -0
- package/dist/parser/predicate-walk.js.map +1 -0
- package/dist/parser/resolve.d.ts +25 -0
- package/dist/parser/resolve.d.ts.map +1 -0
- package/dist/parser/resolve.js +134 -0
- package/dist/parser/resolve.js.map +1 -0
- package/dist/parser/select.d.ts +7 -0
- package/dist/parser/select.d.ts.map +1 -0
- package/dist/parser/select.js +333 -0
- package/dist/parser/select.js.map +1 -0
- package/dist/parser/update.d.ts +7 -0
- package/dist/parser/update.d.ts.map +1 -0
- package/dist/parser/update.js +51 -0
- package/dist/parser/update.js.map +1 -0
- package/dist/postgres/aggregates.d.ts +12 -0
- package/dist/postgres/aggregates.d.ts.map +1 -0
- package/dist/postgres/aggregates.js +19 -0
- package/dist/postgres/aggregates.js.map +1 -0
- package/dist/postgres.d.ts +6 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +6 -0
- package/dist/postgres.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/types.d.ts +16 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +40 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/sqlite/aggregates.d.ts +8 -0
- package/dist/sqlite/aggregates.d.ts.map +1 -0
- package/dist/sqlite/aggregates.js +11 -0
- package/dist/sqlite/aggregates.js.map +1 -0
- package/dist/sqlite.d.ts +6 -0
- package/dist/sqlite.d.ts.map +1 -0
- package/dist/sqlite.js +6 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/transformer/bindings.d.ts +18 -0
- package/dist/transformer/bindings.d.ts.map +1 -0
- package/dist/transformer/bindings.js +52 -0
- package/dist/transformer/bindings.js.map +1 -0
- package/dist/transformer/index.d.ts +17 -0
- package/dist/transformer/index.d.ts.map +1 -0
- package/dist/transformer/index.js +75 -0
- package/dist/transformer/index.js.map +1 -0
- package/dist/transformer/ir-emit.d.ts +12 -0
- package/dist/transformer/ir-emit.d.ts.map +1 -0
- package/dist/transformer/ir-emit.js +144 -0
- package/dist/transformer/ir-emit.js.map +1 -0
- package/dist/transformer/join-transformer.d.ts +12 -0
- package/dist/transformer/join-transformer.d.ts.map +1 -0
- package/dist/transformer/join-transformer.js +102 -0
- package/dist/transformer/join-transformer.js.map +1 -0
- package/dist/transformer/orderby-transformer.d.ts +13 -0
- package/dist/transformer/orderby-transformer.d.ts.map +1 -0
- package/dist/transformer/orderby-transformer.js +84 -0
- package/dist/transformer/orderby-transformer.js.map +1 -0
- package/dist/transformer/select-transformer.d.ts +9 -0
- package/dist/transformer/select-transformer.d.ts.map +1 -0
- package/dist/transformer/select-transformer.js +222 -0
- package/dist/transformer/select-transformer.js.map +1 -0
- package/dist/transformer/shared.d.ts +12 -0
- package/dist/transformer/shared.d.ts.map +1 -0
- package/dist/transformer/shared.js +12 -0
- package/dist/transformer/shared.js.map +1 -0
- package/dist/transformer/subquery-transformer.d.ts +15 -0
- package/dist/transformer/subquery-transformer.d.ts.map +1 -0
- package/dist/transformer/subquery-transformer.js +43 -0
- package/dist/transformer/subquery-transformer.js.map +1 -0
- package/dist/transformer/ts-aggregates.d.ts +13 -0
- package/dist/transformer/ts-aggregates.d.ts.map +1 -0
- package/dist/transformer/ts-aggregates.js +83 -0
- package/dist/transformer/ts-aggregates.js.map +1 -0
- package/dist/transformer/ts-binary.d.ts +8 -0
- package/dist/transformer/ts-binary.d.ts.map +1 -0
- package/dist/transformer/ts-binary.js +32 -0
- package/dist/transformer/ts-binary.js.map +1 -0
- package/dist/transformer/ts-member.d.ts +12 -0
- package/dist/transformer/ts-member.d.ts.map +1 -0
- package/dist/transformer/ts-member.js +22 -0
- package/dist/transformer/ts-member.js.map +1 -0
- package/dist/transformer/ts-utils.d.ts +10 -0
- package/dist/transformer/ts-utils.d.ts.map +1 -0
- package/dist/transformer/ts-utils.js +38 -0
- package/dist/transformer/ts-utils.js.map +1 -0
- package/dist/transformer/typhex-type.d.ts +8 -0
- package/dist/transformer/typhex-type.d.ts.map +1 -0
- package/dist/transformer/typhex-type.js +52 -0
- package/dist/transformer/typhex-type.js.map +1 -0
- package/dist/transformer/where-transformer.d.ts +33 -0
- package/dist/transformer/where-transformer.d.ts.map +1 -0
- package/dist/transformer/where-transformer.js +400 -0
- package/dist/transformer/where-transformer.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +30 -0
- package/dist/utils.js.map +1 -0
- package/docs/drivers/postgres.md +54 -0
- package/docs/drivers/sqlite.md +33 -0
- package/docs/guide/aggregations.md +272 -0
- package/docs/guide/bulk-operations.md +204 -0
- package/docs/guide/cte-and-unions.md +270 -0
- package/docs/guide/entities-relations.md +208 -0
- package/docs/guide/expressions.md +98 -0
- package/docs/guide/filtering-by-relations.md +166 -0
- package/docs/guide/getting-started.md +277 -0
- package/docs/guide/querying-relations.md +133 -0
- package/docs/guide/subqueries.md +152 -0
- package/docs/guide/transactions.md +146 -0
- package/docs/guide/typescript-transformer.md +138 -0
- package/docs/index.md +33 -0
- package/docs/migrations/overview.md +143 -0
- package/docs/public-api.md +133 -0
- package/docs/reference/api.md +665 -0
- package/docs/reference/architecture.md +83 -0
- package/docs/release-checklist.md +55 -0
- package/etc/typhex.api.md +774 -0
- package/package.json +137 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# CTEs and Unions
|
|
2
|
+
|
|
3
|
+
Common table expressions let you name an inner query and reuse it from an outer query. Typhex exposes them through `.withCte()`, `.withRecursiveCte()`, `.from()`, and `.unionAll()`.
|
|
4
|
+
|
|
5
|
+
## Basic CTE
|
|
6
|
+
|
|
7
|
+
Register a query with `.withCte(name, query)`, then read from it with `.from(name)`:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const adults = User.query().where((u) => u.age >= 18);
|
|
11
|
+
|
|
12
|
+
const workingAge = await User.query()
|
|
13
|
+
.withCte("adults", adults)
|
|
14
|
+
.from("adults")
|
|
15
|
+
.where((u) => u.age < 65)
|
|
16
|
+
.toArray();
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```sql
|
|
20
|
+
WITH "adults" AS (
|
|
21
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
22
|
+
FROM "users" AS "t0"
|
|
23
|
+
WHERE ("t0"."age" >= ?)
|
|
24
|
+
)
|
|
25
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
26
|
+
FROM "adults" AS "t0"
|
|
27
|
+
WHERE ("t0"."age" < ?)
|
|
28
|
+
-- params: [18, 65]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Referencing Earlier CTEs
|
|
32
|
+
|
|
33
|
+
Later CTEs can read from earlier CTEs by using `.from("earlier_name")`:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const adults = User.query().where((u) => u.age >= 18);
|
|
37
|
+
const ukAdults = User.query()
|
|
38
|
+
.from("adults")
|
|
39
|
+
.where((u) => u.country === "UK");
|
|
40
|
+
|
|
41
|
+
const rows = await User.query()
|
|
42
|
+
.withCte("adults", adults)
|
|
43
|
+
.withCte("uk_adults", ukAdults)
|
|
44
|
+
.from("uk_adults")
|
|
45
|
+
.toArray();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```sql
|
|
49
|
+
WITH "adults" AS (
|
|
50
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
51
|
+
FROM "users" AS "t0"
|
|
52
|
+
WHERE ("t0"."age" >= ?)
|
|
53
|
+
), "uk_adults" AS (
|
|
54
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
55
|
+
FROM "adults" AS "t0"
|
|
56
|
+
WHERE ("t0"."country" = ?)
|
|
57
|
+
)
|
|
58
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
59
|
+
FROM "uk_adults" AS "t0"
|
|
60
|
+
WHERE 1=1
|
|
61
|
+
-- params: [18, "UK"]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use this when the later CTE is a filtered subset of an earlier one. The inner query reads directly from the earlier CTE name.
|
|
65
|
+
|
|
66
|
+
## Correlating with `ctes.*` in WHERE
|
|
67
|
+
|
|
68
|
+
Sometimes the later CTE should scan the **base entity table** and correlate to an earlier CTE in `WHERE`, instead of using `.from("earlier_name")`. Typhex exposes earlier registered CTEs through a `ctes` context.
|
|
69
|
+
|
|
70
|
+
Typical shape:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const adults = User.query().where((u) => u.age >= 18);
|
|
74
|
+
|
|
75
|
+
await User.query()
|
|
76
|
+
.withCte("adults", adults)
|
|
77
|
+
.withCte("uk_adults", (ctes) =>
|
|
78
|
+
User.query().where((u) => u.country === "UK" && u.id === ctes.adults.id),
|
|
79
|
+
)
|
|
80
|
+
.from("uk_adults")
|
|
81
|
+
.toArray();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```sql
|
|
85
|
+
WITH "adults" AS (
|
|
86
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
87
|
+
FROM "users" AS "t0"
|
|
88
|
+
WHERE ("t0"."age" >= ?)
|
|
89
|
+
), "uk_adults" AS (
|
|
90
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
91
|
+
FROM "users" AS "t0", "adults"
|
|
92
|
+
WHERE ("t0"."country" = ?) AND ("t0"."id" = "adults"."id")
|
|
93
|
+
)
|
|
94
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
95
|
+
FROM "uk_adults" AS "t0"
|
|
96
|
+
WHERE 1=1
|
|
97
|
+
-- params: [18, "UK"]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The important difference from `.from("adults")`:
|
|
101
|
+
|
|
102
|
+
| Approach | Inner `FROM` | Typical use |
|
|
103
|
+
| -------------------------- | ------------------------ | --------------------------------------------------- |
|
|
104
|
+
| `.from("adults")` | `"adults"` | Filter rows already materialized in the earlier CTE |
|
|
105
|
+
| `ctes.adults.*` in `WHERE` | base table + earlier CTE | Match base-table rows against earlier CTE rows |
|
|
106
|
+
|
|
107
|
+
### Transformer: `ctes.*` in a single-arg `where`
|
|
108
|
+
|
|
109
|
+
When the Typhex transformer is enabled, reference earlier CTE columns directly inside a one-argument `where()` lambda. The transformer captures `ctes` from the `.withCte()` callback:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
.withCte("uk_adults", (ctes) =>
|
|
113
|
+
User.query().where((u) => u.country === "UK" && u.id === ctes.adults.id),
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This is the pattern used in `examples/cte/cte.ts` section 3b.
|
|
118
|
+
|
|
119
|
+
### Runtime: two-arg `where((row, ctes) => ...)`
|
|
120
|
+
|
|
121
|
+
Without the transformer, pass the `ctes` object explicitly as the second parameter to `where()`. This works when building a later CTE body and when correlating mutations on the outer builder:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
// Later CTE body — runtime-friendly
|
|
125
|
+
.withCte("uk_adults", () =>
|
|
126
|
+
User.query().where(
|
|
127
|
+
(u, ctes) => u.country === "UK" && u.id === ctes.adults.id,
|
|
128
|
+
),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
// Outer UPDATE/DELETE on the same builder
|
|
132
|
+
await User.query()
|
|
133
|
+
.withCte("adults", adults)
|
|
134
|
+
.where((u, ctes) => u.age === 35 && u.id === ctes.adults.id)
|
|
135
|
+
.update({ name: "Robert" });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```sql
|
|
139
|
+
WITH "adults" AS (
|
|
140
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
141
|
+
FROM "users" AS "t0"
|
|
142
|
+
WHERE ("t0"."age" >= ?)
|
|
143
|
+
)
|
|
144
|
+
UPDATE "users" AS "t0"
|
|
145
|
+
SET "name" = ?
|
|
146
|
+
FROM "adults"
|
|
147
|
+
WHERE ("t0"."age" = ?) AND ("t0"."id" = "adults"."id")
|
|
148
|
+
-- params: [18, "Robert", 35]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The two-arg form is the reliable way to correlate registered CTEs at runtime. The single-arg `ctes.adults.id` form inside a `.withCte()` callback requires the transformer.
|
|
152
|
+
|
|
153
|
+
## `UNION ALL`
|
|
154
|
+
|
|
155
|
+
Use `.unionAll()` to combine compatible SELECT branches, often inside a CTE:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const young = User.query().where((u) => u.age < 25);
|
|
159
|
+
const senior = User.query().where((u) => u.age >= 65);
|
|
160
|
+
|
|
161
|
+
const rows = await User.query()
|
|
162
|
+
.withCte("ends", young.unionAll(senior))
|
|
163
|
+
.from("ends")
|
|
164
|
+
.orderBy("name", "asc")
|
|
165
|
+
.toArray();
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```sql
|
|
169
|
+
WITH "ends" AS (
|
|
170
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
171
|
+
FROM "users" AS "t0"
|
|
172
|
+
WHERE ("t0"."age" < ?)
|
|
173
|
+
UNION ALL
|
|
174
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
175
|
+
FROM "users" AS "t0"
|
|
176
|
+
WHERE ("t0"."age" >= ?)
|
|
177
|
+
)
|
|
178
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
179
|
+
FROM "ends" AS "t0"
|
|
180
|
+
WHERE 1=1
|
|
181
|
+
ORDER BY "t0"."name" ASC
|
|
182
|
+
-- params: [25, 65]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Recursive CTEs
|
|
186
|
+
|
|
187
|
+
Recursive CTEs combine an anchor query with a recursive branch. The recursive branch refers to the CTE name via `.from(name)`:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const anchor = Category.query().where((c) => c.parentId === null);
|
|
191
|
+
const recursive = Category.query()
|
|
192
|
+
.from("tree")
|
|
193
|
+
.innerJoin(Category, (child, parent) => child.parentId === parent.id);
|
|
194
|
+
|
|
195
|
+
const tree = await Category.query()
|
|
196
|
+
.withRecursiveCte("tree", anchor.unionAll(recursive))
|
|
197
|
+
.from("tree")
|
|
198
|
+
.toArray();
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```sql
|
|
202
|
+
WITH RECURSIVE "tree" AS (
|
|
203
|
+
SELECT "t0"."id", "t0"."name", "t0"."parentId"
|
|
204
|
+
FROM "categories" AS "t0"
|
|
205
|
+
WHERE ("t0"."parentId" IS NULL)
|
|
206
|
+
UNION ALL
|
|
207
|
+
SELECT "t0"."id", "t0"."name", "t0"."parentId"
|
|
208
|
+
FROM "tree" AS "t0"
|
|
209
|
+
INNER JOIN "categories" AS "t1"
|
|
210
|
+
ON ("t1"."parentId" = "t0"."id")
|
|
211
|
+
)
|
|
212
|
+
SELECT "t0"."id", "t0"."name", "t0"."parentId"
|
|
213
|
+
FROM "tree" AS "t0"
|
|
214
|
+
WHERE 1=1
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Entity-table joins such as `.innerJoin(Category, on)` are useful in recursive branches and self-joins.
|
|
218
|
+
|
|
219
|
+
## CTEs with Mutations
|
|
220
|
+
|
|
221
|
+
Registered CTEs can also constrain updates and deletes on the outer builder. Use the two-argument `where((row, ctes) => ...)` form to correlate the mutation target to a registered CTE:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
const adults = User.query().where((u) => u.age >= 18);
|
|
225
|
+
|
|
226
|
+
await User.query()
|
|
227
|
+
.withCte("adults", adults)
|
|
228
|
+
.where((u, ctes) => u.id === ctes.adults.id && u.age === 35)
|
|
229
|
+
.update({ name: "Robert" });
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```sql
|
|
233
|
+
WITH "adults" AS (
|
|
234
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
235
|
+
FROM "users" AS "t0"
|
|
236
|
+
WHERE ("t0"."age" >= ?)
|
|
237
|
+
)
|
|
238
|
+
UPDATE "users" AS "t0"
|
|
239
|
+
SET "name" = ?
|
|
240
|
+
FROM "adults"
|
|
241
|
+
WHERE ("t0"."age" = ?) AND ("t0"."id" = "adults"."id")
|
|
242
|
+
-- params: [18, "Robert", 35]
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
For deletes, Typhex correlates through `EXISTS`:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const ukAdults = User.query().where((u) => u.country === "UK" && u.age >= 18);
|
|
249
|
+
|
|
250
|
+
await User.query()
|
|
251
|
+
.withCte("uk_adults", ukAdults)
|
|
252
|
+
.where((u, ctes) => u.age >= 65 && u.id === ctes.uk_adults.id)
|
|
253
|
+
.delete();
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
```sql
|
|
257
|
+
WITH "uk_adults" AS (
|
|
258
|
+
SELECT "t0"."id", "t0"."name", "t0"."age", "t0"."country"
|
|
259
|
+
FROM "users" AS "t0"
|
|
260
|
+
WHERE (("t0"."country" = ?) AND ("t0"."age" >= ?))
|
|
261
|
+
)
|
|
262
|
+
DELETE FROM "users" AS "t0"
|
|
263
|
+
WHERE EXISTS (
|
|
264
|
+
SELECT 1 FROM "uk_adults"
|
|
265
|
+
WHERE ("t0"."age" >= ?) AND ("t0"."id" = "uk_adults"."id")
|
|
266
|
+
)
|
|
267
|
+
-- params: ["UK", 18, 65]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
See the [API reference](/reference/api#withcte-name-query) for method signatures and run `npm run cte` from `examples/` for end-to-end output.
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Entities & Relations
|
|
2
|
+
|
|
3
|
+
## The `Entity()` Factory
|
|
4
|
+
|
|
5
|
+
`Entity()` creates a base class for a database table. The second argument is the schema — a map from column name to SQL type string.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Entity, rel } from "typhex";
|
|
9
|
+
|
|
10
|
+
const User = Entity("users", {
|
|
11
|
+
id: "integer primary key autoincrement",
|
|
12
|
+
name: "text not null",
|
|
13
|
+
email: "text",
|
|
14
|
+
age: "integer",
|
|
15
|
+
createdAt: "datetime not null",
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
TypeScript infers the row shape from the schema, so `User` instances are typed — no separate interface declaration required.
|
|
20
|
+
|
|
21
|
+
## Defining Relations
|
|
22
|
+
|
|
23
|
+
Pass a third argument to `Entity()` to declare relations. Use the `rel` helper:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const Post = Entity(
|
|
27
|
+
"posts",
|
|
28
|
+
{
|
|
29
|
+
id: "integer primary key autoincrement",
|
|
30
|
+
title: "text not null",
|
|
31
|
+
authorId: "integer not null",
|
|
32
|
+
createdAt: "datetime not null",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
author: rel.manyToOne(() => User, { foreignKey: "authorId" }), // [!code highlight]
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The target entity is passed as a thunk (`() => User`) to allow forward-references when entities are defined in separate files or have circular references.
|
|
41
|
+
|
|
42
|
+
### Relation helpers
|
|
43
|
+
|
|
44
|
+
| Helper | Direction | What it means |
|
|
45
|
+
| ---------------------------------------------------------------------- | --------- | -------------------------------------------- |
|
|
46
|
+
| `rel.manyToOne(() => Target, { foreignKey })` | N:1 | This table holds the foreign key |
|
|
47
|
+
| `rel.oneToMany(() => Target, { foreignKey })` | 1:N | The other table holds the foreign key |
|
|
48
|
+
| `rel.oneToOne(() => Target, { foreignKey })` | 1:1 | FK on this table; loads a single related row |
|
|
49
|
+
| `rel.manyToMany(() => Target, { junction, foreignKey, referenceKey })` | M:N | Via a junction table |
|
|
50
|
+
|
|
51
|
+
## One-to-One Relations
|
|
52
|
+
|
|
53
|
+
Use `rel.oneToOne()` when each row has at most one related row. The FK lives on this entity's table:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const UserProfile = Entity("user_profiles", {
|
|
57
|
+
id: "integer primary key autoincrement",
|
|
58
|
+
userId: "integer not null unique",
|
|
59
|
+
bio: "text",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const User = Entity(
|
|
63
|
+
"users",
|
|
64
|
+
{ id: "integer primary key autoincrement", name: "text not null" },
|
|
65
|
+
{ profile: rel.oneToOne(() => UserProfile, { foreignKey: "userId" }) },
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Load the profile alongside the user
|
|
69
|
+
const users = await User.query()
|
|
70
|
+
.select((u) => ({ id: u.id, name: u.name, profile: u.profile }))
|
|
71
|
+
.toArray();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
-- 1. Main query
|
|
76
|
+
SELECT id AS id, name AS name FROM users
|
|
77
|
+
|
|
78
|
+
-- 2. Relation fetch (one round-trip, regardless of result count)
|
|
79
|
+
SELECT id, userId, bio FROM user_profiles WHERE userId IN (?, ?, ...)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Many-to-Many Relations
|
|
83
|
+
|
|
84
|
+
A `manyToMany` relation works through a junction table that you manage directly in SQL (Typhex doesn't auto-migrate junction tables):
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { Entity, rel, type ManyToMany } from "typhex";
|
|
88
|
+
import { Tag } from "./tag.js";
|
|
89
|
+
|
|
90
|
+
export class Post extends Entity(
|
|
91
|
+
"posts",
|
|
92
|
+
{ id: "integer primary key autoincrement", title: "text not null" },
|
|
93
|
+
{
|
|
94
|
+
tags: rel.manyToMany(() => Tag, {
|
|
95
|
+
junction: "post_tags", // junction table name
|
|
96
|
+
foreignKey: "postId", // column pointing to this entity
|
|
97
|
+
referenceKey: "tagId", // column pointing to the target
|
|
98
|
+
}),
|
|
99
|
+
},
|
|
100
|
+
) {
|
|
101
|
+
declare tags: ManyToMany<Tag>; // needed when Post and Tag are in separate files
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Create the junction table manually (once):
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
await db.run("CREATE TABLE post_tags (postId INTEGER NOT NULL, tagId INTEGER NOT NULL)");
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Then use it like any other relation in `select()`:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const posts = await Post.query()
|
|
115
|
+
.select((p) => ({
|
|
116
|
+
id: p.id,
|
|
117
|
+
title: p.title,
|
|
118
|
+
tags: p.tags
|
|
119
|
+
.query()
|
|
120
|
+
.select((t) => ({ name: t.name }))
|
|
121
|
+
.orderBy((t) => t.name, "asc"),
|
|
122
|
+
}))
|
|
123
|
+
.toArray();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```sql
|
|
127
|
+
-- 1. Main query
|
|
128
|
+
SELECT id AS id, title AS title FROM posts
|
|
129
|
+
|
|
130
|
+
-- 2. Junction + target fetched together
|
|
131
|
+
SELECT post_tags.postId, tags.name AS name
|
|
132
|
+
FROM post_tags
|
|
133
|
+
JOIN tags ON tags.id = post_tags.tagId
|
|
134
|
+
WHERE post_tags.postId IN (?, ?, ...)
|
|
135
|
+
ORDER BY tags.name ASC
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Composite Primary Keys
|
|
139
|
+
|
|
140
|
+
When a table's primary key spans multiple columns, mark each column with `"primary key"` in the schema. Relations accept an array for composite foreign keys:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const Project = Entity(
|
|
144
|
+
"projects",
|
|
145
|
+
{
|
|
146
|
+
tenantId: "text primary key",
|
|
147
|
+
projectId: "text primary key",
|
|
148
|
+
name: "text not null",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
tasks: rel.oneToMany(() => Task, { foreignKey: ["tenantId", "projectId"] }),
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const Task = Entity(
|
|
156
|
+
"tasks",
|
|
157
|
+
{
|
|
158
|
+
id: "integer primary key autoincrement",
|
|
159
|
+
tenantId: "text not null",
|
|
160
|
+
projectId: "text not null",
|
|
161
|
+
title: "text not null",
|
|
162
|
+
},
|
|
163
|
+
{ project: rel.manyToOne(() => Project, { foreignKey: ["tenantId", "projectId"] }) },
|
|
164
|
+
);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`findById` accepts an object for composite keys:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const project = await Project.query().findById({ tenantId: "acme", projectId: "p1" });
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```sql
|
|
174
|
+
SELECT tenantId, projectId, name FROM projects
|
|
175
|
+
WHERE tenantId = ? AND projectId = ?
|
|
176
|
+
LIMIT 1
|
|
177
|
+
-- params: ["acme", "p1"]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
::: warning SQLite DDL
|
|
181
|
+
SQLite doesn't allow two `PRIMARY KEY` column constraints in one `CREATE TABLE`. Use `db.run()` with a table-level `PRIMARY KEY (col1, col2)` clause instead of `db.migrate()` for composite-PK tables.
|
|
182
|
+
:::
|
|
183
|
+
|
|
184
|
+
## Custom Entity Classes
|
|
185
|
+
|
|
186
|
+
Subclass the `Entity()` result to add computed properties and lifecycle hooks. The subclass inherits all ORM methods (`.query()`, `.where()`, `.insert()`, etc.) and instances are returned by query methods.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
class UserEntity extends User {
|
|
190
|
+
// Computed property
|
|
191
|
+
get displayName() {
|
|
192
|
+
return this.name ?? this.email ?? "Anonymous";
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Lifecycle hook — called before every save()
|
|
196
|
+
beforeSave() {
|
|
197
|
+
if (!this.createdAt) this.createdAt = new Date();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Query and use the computed property
|
|
202
|
+
const user = await UserEntity.query()
|
|
203
|
+
.where((u) => u.age > 18)
|
|
204
|
+
.first();
|
|
205
|
+
console.log(user?.displayName);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`beforeSave()` is the only lifecycle hook. Use it to set defaults or enforce invariants — it runs before both inserts and updates.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Expressions in Queries
|
|
2
|
+
|
|
3
|
+
Typhex accepts a practical expression subset anywhere a query lambda expects a value: `where()`, `having()`, `select()`, aggregate arguments, and `orderBy()`.
|
|
4
|
+
|
|
5
|
+
## Conditional and Arithmetic Expressions
|
|
6
|
+
|
|
7
|
+
Use JavaScript ternaries for SQL `CASE` expressions, and arithmetic operators for derived values:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const lineItems = await Order.query()
|
|
11
|
+
.select((o) => ({
|
|
12
|
+
id: o.id,
|
|
13
|
+
revenue: o.price * o.qty,
|
|
14
|
+
bucket: o.qty < 5 ? "small" : "large",
|
|
15
|
+
}))
|
|
16
|
+
.orderBy((o) => (o.qty < 5 ? 1 : 0))
|
|
17
|
+
.toArray();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```sql
|
|
21
|
+
SELECT id AS id,
|
|
22
|
+
(price * qty) AS revenue,
|
|
23
|
+
CASE WHEN qty < ? THEN ? ELSE ? END AS bucket
|
|
24
|
+
FROM orders
|
|
25
|
+
ORDER BY CASE WHEN qty < ? THEN ? ELSE ? END ASC
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Supported arithmetic operators are `+`, `-`, `*`, `/`, and `%`. Bitwise operators `&`, `|`, `^`, `<<`, `>>`, and unary `~` are also supported; PostgreSQL emits `#` for XOR.
|
|
29
|
+
|
|
30
|
+
## Null Checks
|
|
31
|
+
|
|
32
|
+
Strict null comparisons compile to SQL null semantics:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const liveCount = await Order.query()
|
|
36
|
+
.where((o) => o.deletedAt === null)
|
|
37
|
+
.count();
|
|
38
|
+
|
|
39
|
+
const deletedCount = await Order.query()
|
|
40
|
+
.where((o) => o.deletedAt !== null)
|
|
41
|
+
.count();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```sql
|
|
45
|
+
WHERE deletedAt IS NULL
|
|
46
|
+
WHERE deletedAt IS NOT NULL
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Computed Select Columns
|
|
50
|
+
|
|
51
|
+
Projection fields can be expressions, not just direct columns:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const prices = await Order.query()
|
|
55
|
+
.select((o) => ({
|
|
56
|
+
id: o.id,
|
|
57
|
+
cents: o.price * 100,
|
|
58
|
+
activeLabel: o.active ? "active" : "inactive",
|
|
59
|
+
}))
|
|
60
|
+
.toArray();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If the lambda returns a single scalar expression, Typhex aliases it as `expr`:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const cents = await Order.query()
|
|
67
|
+
.select((o) => o.price * 100)
|
|
68
|
+
.toArray();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Expressions Inside Aggregates
|
|
72
|
+
|
|
73
|
+
Aggregate arguments can include ternaries and arithmetic, which is useful for conditional counts and revenue totals:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { sum } from "typhex";
|
|
77
|
+
|
|
78
|
+
const cutoff = 5;
|
|
79
|
+
const buckets = await Order.query()
|
|
80
|
+
.select(
|
|
81
|
+
(o) => ({
|
|
82
|
+
category: o.category,
|
|
83
|
+
revenue: sum(o.price * o.qty),
|
|
84
|
+
smalls: sum(o.qty < cutoff ? 1 : 0),
|
|
85
|
+
}),
|
|
86
|
+
{ cutoff },
|
|
87
|
+
)
|
|
88
|
+
.groupBy("category")
|
|
89
|
+
.toArray();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
In runtime mode, pass closure variables used by `.select()` as the second argument. With the TypeScript transformer, those variables are captured automatically.
|
|
93
|
+
|
|
94
|
+
## Runtime and Transformer Boundaries
|
|
95
|
+
|
|
96
|
+
Ternaries, arithmetic, bitwise operators, null checks, computed projections, and expression `orderBy()` work in runtime mode and transformer mode.
|
|
97
|
+
|
|
98
|
+
Scalar correlated subqueries in `.select()`, comparison `.where()` predicates, and `.orderBy()` are transformer-only. See [Subqueries](/guide/subqueries) for those shapes.
|