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,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Select-list classification.
|
|
3
|
+
*
|
|
4
|
+
* A user-written `.select(...)` body can mix three kinds of references:
|
|
5
|
+
* plain columns (`u.name`), relation roots (`u.author`), and members of
|
|
6
|
+
* relations (`u.author.name`). How each is rendered depends on whether
|
|
7
|
+
* its relation is *joined* into the main SELECT (and therefore its
|
|
8
|
+
* columns can ride along) or *not joined* (and so the data has to be
|
|
9
|
+
* fetched separately by the relation pipeline).
|
|
10
|
+
*
|
|
11
|
+
* `SelectClassifier.classify()` walks the IR select once and produces a
|
|
12
|
+
* `ClassifiedSelect` that tells the rest of the planner how to handle
|
|
13
|
+
* each entry:
|
|
14
|
+
*
|
|
15
|
+
* - **`columnPaths` / `columnAliases`** — column references that should
|
|
16
|
+
* appear in the SQL SELECT list, as `<alias>.<col>` references. These
|
|
17
|
+
* include leaf columns, joined-relation members, and any join-key
|
|
18
|
+
* columns that need to be added so the row hydrator can pair fetched
|
|
19
|
+
* relation rows with their parents.
|
|
20
|
+
* - **`relationFetches`** — relations that need a separate eager-load
|
|
21
|
+
* query (one-to-many, many-to-many, or non-joined many-to-one). The
|
|
22
|
+
* relation-fetcher reads this list to produce the WHERE-IN secondary
|
|
23
|
+
* queries.
|
|
24
|
+
* - **`joinedProjections`** — relations whose data came in via the JOIN
|
|
25
|
+
* and needs to be re-shaped from flat result columns back into nested
|
|
26
|
+
* objects. Drives `RelationAssembler.assembleJoined`.
|
|
27
|
+
* - **`skipLoadFor`** — relation keys whose data is already in the
|
|
28
|
+
* SELECT-list via the JOIN; the eager-loader skips re-fetching these.
|
|
29
|
+
*
|
|
30
|
+
* The classifier is constructed once with the inputs that all five
|
|
31
|
+
* helper methods share, so the methods can be small and read directly
|
|
32
|
+
* from `this.*` rather than threading a context object.
|
|
33
|
+
*/
|
|
34
|
+
import type { IrSelect } from "../../../ir/types.js";
|
|
35
|
+
import type { RelationsMap } from "../../../entity/relations.js";
|
|
36
|
+
import type { RelationFetchMetadata, JoinedProjection } from "./query-plan.js";
|
|
37
|
+
/**
|
|
38
|
+
* Result of classifying an IrSelect.
|
|
39
|
+
*
|
|
40
|
+
* `columnPaths` / `columnAliases` carry `null` when the original IR's
|
|
41
|
+
* paths/aliases should be used verbatim — that's the no-relations
|
|
42
|
+
* fast-path. Otherwise both are non-null and parallel: `columnPaths[i]`
|
|
43
|
+
* is the path, `columnAliases[i]` is its SELECT-list alias.
|
|
44
|
+
*/
|
|
45
|
+
export interface ClassifiedSelect {
|
|
46
|
+
columnPaths: string[][] | null;
|
|
47
|
+
columnAliases: string[] | null;
|
|
48
|
+
relationFetches: RelationFetchMetadata[];
|
|
49
|
+
joinedProjections: JoinedProjection[];
|
|
50
|
+
skipLoadFor: Set<string>;
|
|
51
|
+
reusableJoinKeys: Set<string>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sentinel used by the planner when classification isn't needed (e.g.
|
|
55
|
+
* mutations like UPDATE/DELETE that have no SELECT list to classify).
|
|
56
|
+
* Identity-shared so equality checks stay cheap.
|
|
57
|
+
*/
|
|
58
|
+
export declare const EMPTY_CLASSIFIED: ClassifiedSelect;
|
|
59
|
+
/**
|
|
60
|
+
* Classifies an `IrSelect` against the known relation map.
|
|
61
|
+
*
|
|
62
|
+
* Constructor inputs:
|
|
63
|
+
* - `select` — the IR select tree from `state.selectIr`.
|
|
64
|
+
* - `relations` — the relation map of the entity being queried; used to
|
|
65
|
+
* recognise relation keys in the IR and build fetch metadata.
|
|
66
|
+
* - `pkColumns` — primary-key columns of the parent entity. Used for
|
|
67
|
+
* `parentPkColumns` on to-many fetches and to ensure key columns are
|
|
68
|
+
* included for to-many parents.
|
|
69
|
+
* - `reusableJoinKeys` — relation keys that the planner has decided to
|
|
70
|
+
* join into the main SELECT because the where/orderBy already need
|
|
71
|
+
* that join. When non-empty, members of these relations stay in the
|
|
72
|
+
* SELECT list rather than triggering a separate fetch.
|
|
73
|
+
*/
|
|
74
|
+
export declare class SelectClassifier {
|
|
75
|
+
private readonly select;
|
|
76
|
+
private readonly relations;
|
|
77
|
+
private readonly pkColumns;
|
|
78
|
+
private readonly reusableJoinKeys;
|
|
79
|
+
constructor(select: IrSelect, relations: RelationsMap, pkColumns: string[], reusableJoinKeys: Set<string>);
|
|
80
|
+
/**
|
|
81
|
+
* Run the classification pipeline:
|
|
82
|
+
*
|
|
83
|
+
* 1. Fast-path: if neither the select's paths nor its `relations` field
|
|
84
|
+
* references any known relation, return a no-op classification (the
|
|
85
|
+
* planner falls back to the IR's own paths/aliases).
|
|
86
|
+
* 2. Walk `select.paths` once, populating column lists, fetch metadata,
|
|
87
|
+
* joined-projection entries, and the skip-load set as we go.
|
|
88
|
+
* 3. Walk `select.relations` once, doing the same for nested-relation
|
|
89
|
+
* projections (e.g. `{ posts: p => ({ id: p.id, title: p.title }) }`).
|
|
90
|
+
* 4. Add any join-key columns that fetches need but the user didn't
|
|
91
|
+
* explicitly select — the row hydrator can't pair fetched rows with
|
|
92
|
+
* parents without them.
|
|
93
|
+
* 5. Stamp `parentPkColumns` onto to-many fetches.
|
|
94
|
+
*
|
|
95
|
+
* `joinedProjections` and `skipLoadFor` are populated incrementally
|
|
96
|
+
* inside the path/relation walks rather than via two extra passes
|
|
97
|
+
* because the matching condition (`reusableJoinKeys.has(...)` plus a
|
|
98
|
+
* length check) is exactly the same as the one that decides whether
|
|
99
|
+
* a member rides along the JOIN.
|
|
100
|
+
*/
|
|
101
|
+
classify(): ClassifiedSelect;
|
|
102
|
+
/**
|
|
103
|
+
* Walk the IR `select.paths` array — every member-access in the user's
|
|
104
|
+
* select body lands here as a `string[]` path. Three cases:
|
|
105
|
+
*
|
|
106
|
+
* - **Leaf column** (`p.col`) — path doesn't start with a relation key,
|
|
107
|
+
* so it goes straight into the SELECT list as `<alias>.<col>`.
|
|
108
|
+
* - **Relation root** (`p.author`) — path is exactly `[relKey]`. Means
|
|
109
|
+
* "fetch the whole related entity"; produces a `relationFetch`.
|
|
110
|
+
* - **Relation member** (`p.author.name`) — depends on whether the
|
|
111
|
+
* relation is in `joinedRelationKeys`:
|
|
112
|
+
* - Joined → emit a column path on the JOIN's alias (rendered as
|
|
113
|
+
* e.g. `t1.name AS author_name`), record a projection entry on
|
|
114
|
+
* `joinedByKey` so the assembler can reshape the flat row, and
|
|
115
|
+
* add the relation key to `skipLoadFor` so the eager-loader
|
|
116
|
+
* doesn't redundantly fetch it.
|
|
117
|
+
* - Not joined → produce a `relationFetch` carrying just that
|
|
118
|
+
* sub-path so the eager-loader's secondary query selects only
|
|
119
|
+
* what was asked for.
|
|
120
|
+
*
|
|
121
|
+
* Side effects on `joinedByKey` and `skipLoadFor` mean we don't need a
|
|
122
|
+
* second pass over `select.paths` to compute those outputs.
|
|
123
|
+
*/
|
|
124
|
+
private classifyPathEntries;
|
|
125
|
+
/**
|
|
126
|
+
* Walk the IR `select.relations` array — these come from explicit
|
|
127
|
+
* nested-relation projections (e.g. selecting `posts: p => ({ id, title })`
|
|
128
|
+
* means the IR carries a `{ name: "posts", outputKey: "posts",
|
|
129
|
+
* subPaths: [["id"], ["title"]] }` entry).
|
|
130
|
+
*
|
|
131
|
+
* `seenOutputKeys` is the set of `outputKey`s already produced by
|
|
132
|
+
* `classifyPathEntries` — duplicates here would cause the relation
|
|
133
|
+
* pipeline to fetch the same data twice or produce ambiguous result
|
|
134
|
+
* shapes, so we just skip them.
|
|
135
|
+
*
|
|
136
|
+
* Joined relation with non-empty subPaths → emit each subPath as a
|
|
137
|
+
* column-list entry (column names like `posts_title`), record a
|
|
138
|
+
* `joinedByKey` entry (overriding `outputKey` when the user aliased
|
|
139
|
+
* the relation), and add the relation to `skipLoadFor`. Non-joined or
|
|
140
|
+
* no subPaths → produce a relationFetch, the eager-loader handles it.
|
|
141
|
+
*/
|
|
142
|
+
private classifyRelationEntries;
|
|
143
|
+
/**
|
|
144
|
+
* Make sure every join-key column a `relationFetch` needs is in the
|
|
145
|
+
* parent's SELECT list. Without this, the relation-fetcher would have
|
|
146
|
+
* the secondary query's rows but no way to pair them back to the
|
|
147
|
+
* correct parent row.
|
|
148
|
+
*
|
|
149
|
+
* The "key" columns differ by relation kind:
|
|
150
|
+
* - **to-many** (one-to-many, many-to-many): the parent's PK columns —
|
|
151
|
+
* the secondary query joins the child's FK against this.
|
|
152
|
+
* - **to-one** (many-to-one, one-to-one): the parent's FK columns
|
|
153
|
+
* stored on this row.
|
|
154
|
+
*
|
|
155
|
+
* Returns only the *missing* keys. Anything already in `existingPaths`
|
|
156
|
+
* is skipped to avoid duplicate SELECT entries (which would also break
|
|
157
|
+
* the row hydrator since aliases would clash).
|
|
158
|
+
*/
|
|
159
|
+
private missingJoinKeyColumns;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=select-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-classifier.d.ts","sourceRoot":"","sources":["../../../../src/orm/helpers/query-plan/select-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,8BAA8B,CAAC;AAItC,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,qBAAqB,EAAE,CAAC;IACzC,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,gBAO9B,CAAC;AAcF;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAHhB,MAAM,EAAE,QAAQ,EAChB,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,MAAM,EAAE,EACnB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC;IAGhD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,IAAI,gBAAgB;IAyD5B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,uBAAuB;IAoD/B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,qBAAqB;CA0B9B"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Select-list classification.
|
|
3
|
+
*
|
|
4
|
+
* A user-written `.select(...)` body can mix three kinds of references:
|
|
5
|
+
* plain columns (`u.name`), relation roots (`u.author`), and members of
|
|
6
|
+
* relations (`u.author.name`). How each is rendered depends on whether
|
|
7
|
+
* its relation is *joined* into the main SELECT (and therefore its
|
|
8
|
+
* columns can ride along) or *not joined* (and so the data has to be
|
|
9
|
+
* fetched separately by the relation pipeline).
|
|
10
|
+
*
|
|
11
|
+
* `SelectClassifier.classify()` walks the IR select once and produces a
|
|
12
|
+
* `ClassifiedSelect` that tells the rest of the planner how to handle
|
|
13
|
+
* each entry:
|
|
14
|
+
*
|
|
15
|
+
* - **`columnPaths` / `columnAliases`** — column references that should
|
|
16
|
+
* appear in the SQL SELECT list, as `<alias>.<col>` references. These
|
|
17
|
+
* include leaf columns, joined-relation members, and any join-key
|
|
18
|
+
* columns that need to be added so the row hydrator can pair fetched
|
|
19
|
+
* relation rows with their parents.
|
|
20
|
+
* - **`relationFetches`** — relations that need a separate eager-load
|
|
21
|
+
* query (one-to-many, many-to-many, or non-joined many-to-one). The
|
|
22
|
+
* relation-fetcher reads this list to produce the WHERE-IN secondary
|
|
23
|
+
* queries.
|
|
24
|
+
* - **`joinedProjections`** — relations whose data came in via the JOIN
|
|
25
|
+
* and needs to be re-shaped from flat result columns back into nested
|
|
26
|
+
* objects. Drives `RelationAssembler.assembleJoined`.
|
|
27
|
+
* - **`skipLoadFor`** — relation keys whose data is already in the
|
|
28
|
+
* SELECT-list via the JOIN; the eager-loader skips re-fetching these.
|
|
29
|
+
*
|
|
30
|
+
* The classifier is constructed once with the inputs that all five
|
|
31
|
+
* helper methods share, so the methods can be small and read directly
|
|
32
|
+
* from `this.*` rather than threading a context object.
|
|
33
|
+
*/
|
|
34
|
+
import { getPkColumnsFromSchema } from "../../../entity/pk-columns.js";
|
|
35
|
+
import { toArray } from "../../../utils.js";
|
|
36
|
+
/**
|
|
37
|
+
* Sentinel used by the planner when classification isn't needed (e.g.
|
|
38
|
+
* mutations like UPDATE/DELETE that have no SELECT list to classify).
|
|
39
|
+
* Identity-shared so equality checks stay cheap.
|
|
40
|
+
*/
|
|
41
|
+
export const EMPTY_CLASSIFIED = {
|
|
42
|
+
columnPaths: null,
|
|
43
|
+
columnAliases: null,
|
|
44
|
+
relationFetches: [],
|
|
45
|
+
joinedProjections: [],
|
|
46
|
+
skipLoadFor: new Set(),
|
|
47
|
+
reusableJoinKeys: new Set(),
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Classifies an `IrSelect` against the known relation map.
|
|
51
|
+
*
|
|
52
|
+
* Constructor inputs:
|
|
53
|
+
* - `select` — the IR select tree from `state.selectIr`.
|
|
54
|
+
* - `relations` — the relation map of the entity being queried; used to
|
|
55
|
+
* recognise relation keys in the IR and build fetch metadata.
|
|
56
|
+
* - `pkColumns` — primary-key columns of the parent entity. Used for
|
|
57
|
+
* `parentPkColumns` on to-many fetches and to ensure key columns are
|
|
58
|
+
* included for to-many parents.
|
|
59
|
+
* - `reusableJoinKeys` — relation keys that the planner has decided to
|
|
60
|
+
* join into the main SELECT because the where/orderBy already need
|
|
61
|
+
* that join. When non-empty, members of these relations stay in the
|
|
62
|
+
* SELECT list rather than triggering a separate fetch.
|
|
63
|
+
*/
|
|
64
|
+
export class SelectClassifier {
|
|
65
|
+
select;
|
|
66
|
+
relations;
|
|
67
|
+
pkColumns;
|
|
68
|
+
reusableJoinKeys;
|
|
69
|
+
constructor(select, relations, pkColumns, reusableJoinKeys) {
|
|
70
|
+
this.select = select;
|
|
71
|
+
this.relations = relations;
|
|
72
|
+
this.pkColumns = pkColumns;
|
|
73
|
+
this.reusableJoinKeys = reusableJoinKeys;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run the classification pipeline:
|
|
77
|
+
*
|
|
78
|
+
* 1. Fast-path: if neither the select's paths nor its `relations` field
|
|
79
|
+
* references any known relation, return a no-op classification (the
|
|
80
|
+
* planner falls back to the IR's own paths/aliases).
|
|
81
|
+
* 2. Walk `select.paths` once, populating column lists, fetch metadata,
|
|
82
|
+
* joined-projection entries, and the skip-load set as we go.
|
|
83
|
+
* 3. Walk `select.relations` once, doing the same for nested-relation
|
|
84
|
+
* projections (e.g. `{ posts: p => ({ id: p.id, title: p.title }) }`).
|
|
85
|
+
* 4. Add any join-key columns that fetches need but the user didn't
|
|
86
|
+
* explicitly select — the row hydrator can't pair fetched rows with
|
|
87
|
+
* parents without them.
|
|
88
|
+
* 5. Stamp `parentPkColumns` onto to-many fetches.
|
|
89
|
+
*
|
|
90
|
+
* `joinedProjections` and `skipLoadFor` are populated incrementally
|
|
91
|
+
* inside the path/relation walks rather than via two extra passes
|
|
92
|
+
* because the matching condition (`reusableJoinKeys.has(...)` plus a
|
|
93
|
+
* length check) is exactly the same as the one that decides whether
|
|
94
|
+
* a member rides along the JOIN.
|
|
95
|
+
*/
|
|
96
|
+
classify() {
|
|
97
|
+
const { select, relations, reusableJoinKeys } = this;
|
|
98
|
+
const hasRelations = select.relations?.length || select.paths.some((p) => p.length >= 1 && relations[p[0]]);
|
|
99
|
+
if (!hasRelations) {
|
|
100
|
+
return {
|
|
101
|
+
columnPaths: null,
|
|
102
|
+
columnAliases: null,
|
|
103
|
+
relationFetches: [],
|
|
104
|
+
joinedProjections: [],
|
|
105
|
+
skipLoadFor: new Set(),
|
|
106
|
+
reusableJoinKeys,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const joinedKeys = reusableJoinKeys.size > 0 ? reusableJoinKeys : undefined;
|
|
110
|
+
const joinedByKey = new Map();
|
|
111
|
+
const skipLoadFor = new Set();
|
|
112
|
+
const fromPaths = this.classifyPathEntries(joinedKeys, joinedByKey, skipLoadFor);
|
|
113
|
+
const seenOutputKeys = new Set(fromPaths.relationFetches.map((m) => m.relation.outputKey));
|
|
114
|
+
const fromRelations = this.classifyRelationEntries(joinedKeys, seenOutputKeys, joinedByKey, skipLoadFor);
|
|
115
|
+
const columnPaths = [...fromPaths.columnPaths, ...fromRelations.columnPaths];
|
|
116
|
+
const columnAliases = [...fromPaths.columnAliases, ...fromRelations.columnAliases];
|
|
117
|
+
const relationFetches = [...fromPaths.relationFetches, ...fromRelations.relationFetches];
|
|
118
|
+
const { paths: keyPaths, aliases: keyAliases } = this.missingJoinKeyColumns(relationFetches, columnPaths);
|
|
119
|
+
columnPaths.push(...keyPaths);
|
|
120
|
+
columnAliases.push(...keyAliases);
|
|
121
|
+
for (const f of relationFetches) {
|
|
122
|
+
if (f.relationType === "one-to-many" || f.relationType === "many-to-many") {
|
|
123
|
+
f.parentPkColumns = this.pkColumns;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
columnPaths,
|
|
128
|
+
columnAliases,
|
|
129
|
+
relationFetches,
|
|
130
|
+
joinedProjections: [...joinedByKey.values()].filter((p) => p.members.length > 0),
|
|
131
|
+
skipLoadFor,
|
|
132
|
+
reusableJoinKeys,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Walk the IR `select.paths` array — every member-access in the user's
|
|
137
|
+
* select body lands here as a `string[]` path. Three cases:
|
|
138
|
+
*
|
|
139
|
+
* - **Leaf column** (`p.col`) — path doesn't start with a relation key,
|
|
140
|
+
* so it goes straight into the SELECT list as `<alias>.<col>`.
|
|
141
|
+
* - **Relation root** (`p.author`) — path is exactly `[relKey]`. Means
|
|
142
|
+
* "fetch the whole related entity"; produces a `relationFetch`.
|
|
143
|
+
* - **Relation member** (`p.author.name`) — depends on whether the
|
|
144
|
+
* relation is in `joinedRelationKeys`:
|
|
145
|
+
* - Joined → emit a column path on the JOIN's alias (rendered as
|
|
146
|
+
* e.g. `t1.name AS author_name`), record a projection entry on
|
|
147
|
+
* `joinedByKey` so the assembler can reshape the flat row, and
|
|
148
|
+
* add the relation key to `skipLoadFor` so the eager-loader
|
|
149
|
+
* doesn't redundantly fetch it.
|
|
150
|
+
* - Not joined → produce a `relationFetch` carrying just that
|
|
151
|
+
* sub-path so the eager-loader's secondary query selects only
|
|
152
|
+
* what was asked for.
|
|
153
|
+
*
|
|
154
|
+
* Side effects on `joinedByKey` and `skipLoadFor` mean we don't need a
|
|
155
|
+
* second pass over `select.paths` to compute those outputs.
|
|
156
|
+
*/
|
|
157
|
+
classifyPathEntries(joinedRelationKeys, joinedByKey, skipLoadFor) {
|
|
158
|
+
const { select, relations } = this;
|
|
159
|
+
const relNames = new Set(Object.keys(relations));
|
|
160
|
+
const out = {
|
|
161
|
+
columnPaths: [],
|
|
162
|
+
columnAliases: [],
|
|
163
|
+
relationFetches: [],
|
|
164
|
+
};
|
|
165
|
+
for (let i = 0; i < select.paths.length; i++) {
|
|
166
|
+
const path = select.paths[i];
|
|
167
|
+
const alias = select.aliases?.[i] ?? path[path.length - 1];
|
|
168
|
+
if (path.length === 1 && relNames.has(path[0])) {
|
|
169
|
+
const meta = buildRelationFetchMeta({ name: path[0], outputKey: alias }, relations[path[0]]);
|
|
170
|
+
out.relationFetches.push(meta);
|
|
171
|
+
}
|
|
172
|
+
else if (path.length > 1 && relNames.has(path[0])) {
|
|
173
|
+
if (joinedRelationKeys?.has(path[0])) {
|
|
174
|
+
const colAlias = select.aliases?.[i] ?? `${path[0]}_${path[path.length - 1]}`;
|
|
175
|
+
out.columnPaths.push(path);
|
|
176
|
+
out.columnAliases.push(colAlias);
|
|
177
|
+
let proj = joinedByKey.get(path[0]);
|
|
178
|
+
if (!proj) {
|
|
179
|
+
proj = { relationKey: path[0], outputKey: path[0], members: [] };
|
|
180
|
+
joinedByKey.set(path[0], proj);
|
|
181
|
+
}
|
|
182
|
+
proj.members.push({ alias: colAlias, subPath: path[path.length - 1] });
|
|
183
|
+
skipLoadFor.add(path[0]);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
const meta = buildRelationFetchMeta({ name: path[0], outputKey: alias, subPaths: [path.slice(1)] }, relations[path[0]]);
|
|
187
|
+
out.relationFetches.push(meta);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
out.columnPaths.push(path);
|
|
192
|
+
out.columnAliases.push(alias);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Walk the IR `select.relations` array — these come from explicit
|
|
199
|
+
* nested-relation projections (e.g. selecting `posts: p => ({ id, title })`
|
|
200
|
+
* means the IR carries a `{ name: "posts", outputKey: "posts",
|
|
201
|
+
* subPaths: [["id"], ["title"]] }` entry).
|
|
202
|
+
*
|
|
203
|
+
* `seenOutputKeys` is the set of `outputKey`s already produced by
|
|
204
|
+
* `classifyPathEntries` — duplicates here would cause the relation
|
|
205
|
+
* pipeline to fetch the same data twice or produce ambiguous result
|
|
206
|
+
* shapes, so we just skip them.
|
|
207
|
+
*
|
|
208
|
+
* Joined relation with non-empty subPaths → emit each subPath as a
|
|
209
|
+
* column-list entry (column names like `posts_title`), record a
|
|
210
|
+
* `joinedByKey` entry (overriding `outputKey` when the user aliased
|
|
211
|
+
* the relation), and add the relation to `skipLoadFor`. Non-joined or
|
|
212
|
+
* no subPaths → produce a relationFetch, the eager-loader handles it.
|
|
213
|
+
*/
|
|
214
|
+
classifyRelationEntries(joinedRelationKeys, seenOutputKeys, joinedByKey, skipLoadFor) {
|
|
215
|
+
const { select, relations } = this;
|
|
216
|
+
const out = {
|
|
217
|
+
columnPaths: [],
|
|
218
|
+
columnAliases: [],
|
|
219
|
+
relationFetches: [],
|
|
220
|
+
};
|
|
221
|
+
for (const r of select.relations ?? []) {
|
|
222
|
+
const relDef = relations[r.name];
|
|
223
|
+
if (!relDef) {
|
|
224
|
+
throw new Error(`[typhex] select relation "${r.name}" is not defined on this entity`);
|
|
225
|
+
}
|
|
226
|
+
if (seenOutputKeys.has(r.outputKey)) {
|
|
227
|
+
throw new Error(`[typhex] select relation output "${r.outputKey}" is duplicated`);
|
|
228
|
+
}
|
|
229
|
+
seenOutputKeys.add(r.outputKey);
|
|
230
|
+
if (joinedRelationKeys?.has(r.name) && r.subPaths?.length) {
|
|
231
|
+
let proj = joinedByKey.get(r.name);
|
|
232
|
+
if (!proj) {
|
|
233
|
+
proj = { relationKey: r.name, outputKey: r.outputKey, members: [] };
|
|
234
|
+
joinedByKey.set(r.name, proj);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// A path-driven entry was created earlier with `outputKey: r.name`;
|
|
238
|
+
// an explicit relation entry takes precedence (user may have aliased it).
|
|
239
|
+
proj.outputKey = r.outputKey;
|
|
240
|
+
}
|
|
241
|
+
for (const sub of r.subPaths) {
|
|
242
|
+
if (sub.length > 0) {
|
|
243
|
+
const alias = `${r.outputKey}_${sub.join("_")}`;
|
|
244
|
+
out.columnPaths.push([r.name, ...sub]);
|
|
245
|
+
out.columnAliases.push(alias);
|
|
246
|
+
proj.members.push({ alias, subPath: sub[sub.length - 1] });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
skipLoadFor.add(r.name);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const meta = buildRelationFetchMeta(r, relDef);
|
|
253
|
+
out.relationFetches.push(meta);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return out;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Make sure every join-key column a `relationFetch` needs is in the
|
|
260
|
+
* parent's SELECT list. Without this, the relation-fetcher would have
|
|
261
|
+
* the secondary query's rows but no way to pair them back to the
|
|
262
|
+
* correct parent row.
|
|
263
|
+
*
|
|
264
|
+
* The "key" columns differ by relation kind:
|
|
265
|
+
* - **to-many** (one-to-many, many-to-many): the parent's PK columns —
|
|
266
|
+
* the secondary query joins the child's FK against this.
|
|
267
|
+
* - **to-one** (many-to-one, one-to-one): the parent's FK columns
|
|
268
|
+
* stored on this row.
|
|
269
|
+
*
|
|
270
|
+
* Returns only the *missing* keys. Anything already in `existingPaths`
|
|
271
|
+
* is skipped to avoid duplicate SELECT entries (which would also break
|
|
272
|
+
* the row hydrator since aliases would clash).
|
|
273
|
+
*/
|
|
274
|
+
missingJoinKeyColumns(fetches, existingPaths) {
|
|
275
|
+
const paths = [];
|
|
276
|
+
const aliases = [];
|
|
277
|
+
const added = new Set(existingPaths.map((p) => p[0]));
|
|
278
|
+
for (const meta of fetches) {
|
|
279
|
+
const isMany = meta.relationType === "one-to-many" || meta.relationType === "many-to-many";
|
|
280
|
+
const cols = isMany ? this.pkColumns : meta.fkColumns;
|
|
281
|
+
if (isMany && cols.length === 0) {
|
|
282
|
+
throw new Error(`[typhex] select relation "${meta.relation.name}" requires a primary key on the parent entity`);
|
|
283
|
+
}
|
|
284
|
+
for (const col of cols) {
|
|
285
|
+
if (!added.has(col)) {
|
|
286
|
+
paths.push([col]);
|
|
287
|
+
aliases.push(col);
|
|
288
|
+
added.add(col);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { paths, aliases };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Build the runtime metadata the relation-fetcher needs to execute a
|
|
297
|
+
* secondary load for one relation, given the IR description and the
|
|
298
|
+
* relation definition from the entity.
|
|
299
|
+
*
|
|
300
|
+
* Per relation-kind handling:
|
|
301
|
+
* - **many-to-one / one-to-one**: FK columns are on the parent; PK
|
|
302
|
+
* columns come from the target's schema unless overridden by the
|
|
303
|
+
* relation's `references` option.
|
|
304
|
+
* - **one-to-many**: FK columns are on the child (so we read them off
|
|
305
|
+
* the relation options); PK comes from the target schema.
|
|
306
|
+
* - **many-to-many**: both FK and PK live on the junction table; the
|
|
307
|
+
* junction itself is recorded so the fetcher can build the join.
|
|
308
|
+
*/
|
|
309
|
+
function buildRelationFetchMeta(ir, relDef) {
|
|
310
|
+
const target = relDef._target();
|
|
311
|
+
const targetEntity = target && typeof target.query === "function"
|
|
312
|
+
? target
|
|
313
|
+
: null;
|
|
314
|
+
if (!targetEntity) {
|
|
315
|
+
throw new Error(`[typhex] relation "${ir.name}" target is not a queryable entity`);
|
|
316
|
+
}
|
|
317
|
+
const targetPkColumnsFromSchema = getPkColumnsFromSchema(targetEntity.table._schema);
|
|
318
|
+
switch (relDef._relType) {
|
|
319
|
+
case "many-to-one":
|
|
320
|
+
case "one-to-one": {
|
|
321
|
+
const opts = relDef._options;
|
|
322
|
+
return {
|
|
323
|
+
relationType: relDef._relType,
|
|
324
|
+
relation: ir,
|
|
325
|
+
fkColumns: toArray(opts.foreignKey),
|
|
326
|
+
targetPkColumns: opts.references != null ? toArray(opts.references) : targetPkColumnsFromSchema,
|
|
327
|
+
targetEntity,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
case "one-to-many": {
|
|
331
|
+
const opts = relDef._options;
|
|
332
|
+
return {
|
|
333
|
+
relationType: "one-to-many",
|
|
334
|
+
relation: ir,
|
|
335
|
+
fkColumns: toArray(opts.foreignKey),
|
|
336
|
+
targetPkColumns: targetPkColumnsFromSchema,
|
|
337
|
+
targetEntity,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
case "many-to-many": {
|
|
341
|
+
const j = relDef._options;
|
|
342
|
+
return {
|
|
343
|
+
relationType: "many-to-many",
|
|
344
|
+
relation: ir,
|
|
345
|
+
fkColumns: toArray(j.referenceKey),
|
|
346
|
+
targetPkColumns: targetPkColumnsFromSchema,
|
|
347
|
+
targetEntity,
|
|
348
|
+
junction: {
|
|
349
|
+
table: j.junction,
|
|
350
|
+
foreignKey: toArray(j.foreignKey),
|
|
351
|
+
referenceKey: toArray(j.referenceKey),
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
default:
|
|
356
|
+
throw new Error(`[typhex] Unsupported relation type: ${relDef._relType}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=select-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-classifier.js","sourceRoot":"","sources":["../../../../src/orm/helpers/query-plan/select-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation assembler: attaches relation data onto rows.
|
|
3
|
+
* Handles both flat JOIN columns (assembleJoined) and pre-fetched maps (assembleFetched).
|
|
4
|
+
*/
|
|
5
|
+
import type { JoinedProjection, RelationFetchMetadata } from "../query-plan/query-plan.js";
|
|
6
|
+
export type RelationFetchedData = Map<string, Map<string, unknown> | Map<string, unknown[]>>;
|
|
7
|
+
/** Attaches JOIN-projected and separately fetched relation data onto result rows. */
|
|
8
|
+
export declare class RelationAssembler {
|
|
9
|
+
private readonly rows;
|
|
10
|
+
constructor(rows: Record<string, unknown>[]);
|
|
11
|
+
/**
|
|
12
|
+
* Reconstruct nested objects from flat JOIN columns
|
|
13
|
+
* (e.g. author_name to row.author.name) using pre-extracted projections.
|
|
14
|
+
*/
|
|
15
|
+
assembleJoined(projections: JoinedProjection[]): void;
|
|
16
|
+
/** Attach fetched relation maps onto rows. */
|
|
17
|
+
assembleFetched(fetches: RelationFetchMetadata[], fetched: RelationFetchedData, skip: Set<string>): void;
|
|
18
|
+
private attachToManyRelation;
|
|
19
|
+
private attachToOneRelation;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=relation-assembler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-assembler.d.ts","sourceRoot":"","sources":["../../../../src/orm/helpers/relations/relation-assembler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAG3F,MAAM,MAAM,mBAAmB,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAE7F,qFAAqF;AACrF,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;IAE5D;;;OAGG;IACH,cAAc,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAYrD,8CAA8C;IAC9C,eAAe,CACb,OAAO,EAAE,qBAAqB,EAAE,EAChC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAChB,IAAI;IAaP,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,mBAAmB;CAM5B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation assembler: attaches relation data onto rows.
|
|
3
|
+
* Handles both flat JOIN columns (assembleJoined) and pre-fetched maps (assembleFetched).
|
|
4
|
+
*/
|
|
5
|
+
import { makeCompositeKey } from "../../query-helpers.js";
|
|
6
|
+
/** Attaches JOIN-projected and separately fetched relation data onto result rows. */
|
|
7
|
+
export class RelationAssembler {
|
|
8
|
+
rows;
|
|
9
|
+
constructor(rows) {
|
|
10
|
+
this.rows = rows;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reconstruct nested objects from flat JOIN columns
|
|
14
|
+
* (e.g. author_name to row.author.name) using pre-extracted projections.
|
|
15
|
+
*/
|
|
16
|
+
assembleJoined(projections) {
|
|
17
|
+
for (const proj of projections) {
|
|
18
|
+
if (proj.members.length === 0)
|
|
19
|
+
continue;
|
|
20
|
+
for (const row of this.rows) {
|
|
21
|
+
const obj = {};
|
|
22
|
+
for (const member of proj.members)
|
|
23
|
+
obj[member.subPath] = row[member.alias];
|
|
24
|
+
row[proj.outputKey] = obj;
|
|
25
|
+
for (const member of proj.members)
|
|
26
|
+
delete row[member.alias];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Attach fetched relation maps onto rows. */
|
|
31
|
+
assembleFetched(fetches, fetched, skip) {
|
|
32
|
+
for (const meta of fetches) {
|
|
33
|
+
if (skip.has(meta.relation.name))
|
|
34
|
+
continue;
|
|
35
|
+
const data = fetched.get(meta.relation.name);
|
|
36
|
+
if (!data)
|
|
37
|
+
continue;
|
|
38
|
+
if (meta.relationType === "one-to-many" || meta.relationType === "many-to-many") {
|
|
39
|
+
this.attachToManyRelation(meta, data);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.attachToOneRelation(meta, data);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
attachToManyRelation(meta, data) {
|
|
47
|
+
const pkCols = meta.parentPkColumns;
|
|
48
|
+
for (const row of this.rows) {
|
|
49
|
+
const key = makeCompositeKey(row, pkCols);
|
|
50
|
+
row[meta.relation.outputKey] = data.get(key) ?? [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
attachToOneRelation(meta, data) {
|
|
54
|
+
for (const row of this.rows) {
|
|
55
|
+
const key = makeCompositeKey(row, meta.fkColumns);
|
|
56
|
+
row[meta.relation.outputKey] = data.get(key) ?? null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=relation-assembler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-assembler.js","sourceRoot":"","sources":["../../../../src/orm/helpers/relations/relation-assembler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI1D,qFAAqF;AACrF,MAAM,OAAO,iBAAiB;IACC;IAA7B,YAA6B,IAA+B;QAA/B,SAAI,GAAJ,IAAI,CAA2B;IAAG,CAAC;IAEhE;;;OAGG;IACH,cAAc,CAAC,WAA+B;QAC5C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACxC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAA4B,EAAE,CAAC;gBACxC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;oBAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC3E,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;gBAC1B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,eAAe,CACb,OAAgC,EAChC,OAA4B,EAC5B,IAAiB;QAEjB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,IAAI,CAAC,YAAY,KAAK,aAAa,IAAI,IAAI,CAAC,YAAY,KAAK,cAAc,EAAE,CAAC;gBAChF,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAA8B,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAA4B,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,IAA2B,EAAE,IAA4B;QACpF,MAAM,MAAM,GAAG,IAAI,CAAC,eAAgB,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACrD,CAAC;IACH,CAAC;IAEO,mBAAmB,CAAC,IAA2B,EAAE,IAA0B;QACjF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;QACvD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation fetcher: fetches related entities via WHERE IN queries.
|
|
3
|
+
* Does NOT mutate rows — returns fetched data as maps.
|
|
4
|
+
*/
|
|
5
|
+
import type { QueryExecutor } from "../../db.js";
|
|
6
|
+
import type { RelationFetchMetadata } from "../query-plan/query-plan.js";
|
|
7
|
+
export type RelationFetchResult = Map<string, Map<string, unknown> | Map<string, unknown[]>>;
|
|
8
|
+
/** Runs one WHERE IN query per pending relation fetch and collects keyed result maps. */
|
|
9
|
+
export declare class RelationFetcher {
|
|
10
|
+
private readonly qe;
|
|
11
|
+
private readonly rows;
|
|
12
|
+
private readonly fetches;
|
|
13
|
+
private readonly skip;
|
|
14
|
+
constructor(qe: QueryExecutor, rows: Record<string, unknown>[], fetches: RelationFetchMetadata[], skip: Set<string>);
|
|
15
|
+
fetch(): Promise<RelationFetchResult>;
|
|
16
|
+
private fetchRelation;
|
|
17
|
+
/** Fetch a to-many relation: WHERE IN on FK columns, grouped by FK composite key. */
|
|
18
|
+
private fetchOneToMany;
|
|
19
|
+
/** Fetch a to-one relation: WHERE IN on FK to target-PK, indexed by target PK composite key. */
|
|
20
|
+
private fetchOneToOne;
|
|
21
|
+
/** Many-to-many: two fetchRows calls through the junction, grouped by parent composite key. */
|
|
22
|
+
private fetchManyToMany;
|
|
23
|
+
private buildTargetParentIndex;
|
|
24
|
+
/** Batch-fetch rows from `entity` by mapping source column values onto target columns. */
|
|
25
|
+
private fetchRows;
|
|
26
|
+
private remapCols;
|
|
27
|
+
private indexByCompositeKey;
|
|
28
|
+
private groupByCompositeKey;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=relation-fetcher.d.ts.map
|