Repository navigation
v0.4.2
0.4.2
This release fixes bug when using sql template literal as left-hand side operator in where clauses. It also adds navigation property support for literal/constant values in composite keys for discriminator-style joins
Navigation Key Constants & Composite Keys
Constant values in navigation key definitions
Navigation properties now support literal/constant values in composite keys for discriminator-style joins:
entity.hasOne(e => e.activePrice, () => ProductPrice)
.withForeignKey(e => [e.productId, e.isActive])
.withPrincipalKey(e => [e.id, true]);
// → LEFT JOIN product_prices ON products.product_id = product_prices.id AND products.is_active = trueSupported constant types: number, string, boolean, and sql tagged template literals.
entity.hasOne(e => e.activePrice, () => ProductPrice)
.withForeignKey(e => [e.productId, e.isActive])
.withPrincipalKey(e => [e.id, sql`TRUE`]);
// sql`` fragments also work as the sole key value:
entity.hasOne(e => e.latest, () => Snapshot)
.withForeignKey(e => e.snapshotId)
.withPrincipalKey(e => sql`5`);Composite keys via entity builder
Composite foreign keys defined through the entity builder (e.g. .withForeignKey(e => [e.col1, e.col2])) now work correctly. Previously, composite keys were silently broken — the comma-joined property names were passed as a single column lookup which would fail.
Fix: SqlFragment as field in comparison operators
Using sql tagged templates as the left-hand side of comparison operators (like, eq, gt, etc.) previously generated invalid double-quoted SQL:
// Before (broken): ""product"."internal_id"::varchar(255)" LIKE $1
like(sql`${p.internalId}::varchar(255)`, `%${search}%`)
// After (fixed): "product"."internal_id"::varchar(255) LIKE $1WhereComparisonBase.getDbColumnName() now detects SqlFragment and calls buildSql() instead of wrapping it in quotes. Affects all comparison operators: eq, ne, gt, lt, gte, lte, like, ilike, in, notIn, between.
Files Changed
src/entity/entity-base.ts—NavigationMetadata.foreignKey/principalKeychanged fromstringtostring[](foreignKeys/principalKeys)src/entity/entity-builder.ts—extractKeyPartsFromSelector()detects constants in array selectors via proxy identity check; supportsSqlFragment(sql tagged templates) both as single values and in arrays; type signatures acceptnumber | string | boolean | SqlFragmentin arrayssrc/entity/model-config.ts— Resolves composite key parts individually; creates literal FieldRefs with__isLiteralflag; filters literals from FK constraintssrc/schema/navigation.ts— Preserves__LIT:prefix when converting literal FieldRefs to column name stringssrc/query/join-utils.ts— New sharedformatJoinValue()helpersrc/query/query-builder.ts,src/query/grouped-query.ts,src/query/strategies/cte-collection-strategy.ts,src/query/strategies/lateral-collection-strategy.ts— All 12 JOIN builder locations updated to useformatJoinValue()src/query/conditions.ts—WhereComparisonBase.getDbColumnName()handlesSqlFragmentfield;getFieldRefs()extracts refs from SqlFragment fields; allbuildSql()overrides pass context togetDbColumnName()