turbine-orm 0.30.0 → 0.31.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/dist/powql.js CHANGED
@@ -949,7 +949,13 @@ export class PowqlInterface {
949
949
  const { TransactionClient } = await import('./client.js');
950
950
  const tx = new TransactionClient(client, this.schema, this.middlewares, this.options);
951
951
  const ctx = { schema: this.schema, tx: tx };
952
- const result = await fn(ctx);
952
+ // Plant the single-writer re-entrancy marker for the implicit tx's
953
+ // subtree (same seam TurbineClient.$transaction uses) — user code that
954
+ // fires db.$transaction from inside (e.g. $use middleware around a
955
+ // nested-write child op) must fast-fail E017, not queue into deadlock.
956
+ const wrap = client
957
+ .wrapTransactionCallback;
958
+ const result = await (wrap ? wrap(() => fn(ctx)) : fn(ctx));
953
959
  await client.query(d?.commitStatement?.() ?? 'commit');
954
960
  return result;
955
961
  }
@@ -436,7 +436,12 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
436
436
  */
437
437
  private collectRelationFilterParams;
438
438
  private collectRelFilterParams;
439
- /** Collect params from operator clauses. Mirrors buildOperatorClauses. */
439
+ /**
440
+ * Collect params from operator clauses. Mirrors buildOperatorClauses:
441
+ * {@link ColumnRef} values compile into the SQL text, so they push NOTHING -
442
+ * but they re-run the same validation (unknown ref / insensitive mode) so a
443
+ * warmed cache can never skip a check the build path enforces.
444
+ */
440
445
  private collectOperatorParams;
441
446
  /**
442
447
  * Collect params from JSON filter. Mirrors buildJsonFilterClauses exactly:
@@ -448,10 +453,10 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
448
453
  /** Collect params from array filter. Mirrors buildArrayFilterClauses. */
449
454
  private collectArrayFilterParams;
450
455
  /**
451
- * Collect params for an orderBy clause. Only vector KNN ordering pushes a
452
- * param (the `$n::vector` query vector); plain direction ordering is
453
- * parameterless. Mirrors buildOrderBy's push order exactly so the cached-SQL
454
- * param re-collection stays in lockstep.
456
+ * Collect params for an orderBy clause. Vector KNN ordering pushes the
457
+ * `$n::vector` query vector and JSON-path ordering pushes its text[] path;
458
+ * plain direction ordering is parameterless. Mirrors buildOrderBy's push
459
+ * order exactly so the cached-SQL param re-collection stays in lockstep.
455
460
  */
456
461
  private collectOrderByParams;
457
462
  /**
@@ -611,9 +616,28 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
611
616
  * differently-shaped wheres would share one cached SQL string.
612
617
  */
613
618
  private fingerprintAliasWhere;
619
+ /**
620
+ * Validate a `{ col }` column reference against its table and return the
621
+ * resolved snake_case column name. Shared by the SQL-build path
622
+ * ({@link buildOperatorClauses}) and the cache-hit param-collect path
623
+ * (`collectOperatorParams`) so both always throw identically: a warmed
624
+ * cache can never skip the check.
625
+ */
626
+ private resolveColumnRef;
627
+ /**
628
+ * Compile a `{ col }` reference to its quoted, prefix-matched SQL identifier.
629
+ * NO param is bound: the referenced column is part of the SQL text (and of
630
+ * the where fingerprint, see {@link fingerprintOperatorShape}).
631
+ */
632
+ private columnRefSql;
614
633
  /**
615
634
  * Build SQL clauses for a single operator object on a column.
616
635
  * Each operator key becomes its own clause, all ANDed together.
636
+ *
637
+ * `equals`/`not`/`gt`/`gte`/`lt`/`lte` also accept a {@link ColumnRef}
638
+ * (`{ col: 'otherField' }`) which compiles to a column-to-column comparison
639
+ * against `refCtx`: no param bound, so `collectOperatorParams` mirrors by
640
+ * pushing nothing and the referenced name lives in the fingerprint.
617
641
  */
618
642
  private buildOperatorClauses;
619
643
  /**
@@ -647,6 +671,33 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
647
671
  * {@link UnsupportedFeatureError} (E017) instead of broken SQL.
648
672
  */
649
673
  private nullsSuffix;
674
+ /**
675
+ * Resolve an orderBy key to its snake_case column via the table's columnMap
676
+ * (camelToSnake fallback), throwing the SAME unknown-field E003 the top-level
677
+ * where path uses. Shared by top-level JSON-path ordering and every nested
678
+ * relation orderBy path so nested orderBy accepts exactly what top-level
679
+ * accepts (the 0.30.x bug: nested orderBy skipped the columnMap and rejected
680
+ * camelCase-named DB columns like "sortOrder").
681
+ */
682
+ private resolveOrderByColumn;
683
+ /**
684
+ * Validate a {@link JsonPathOrderBy} entry: column must exist AND be
685
+ * json/jsonb, path must be a non-empty array of keys/indexes: and return
686
+ * the resolved column. Shared by the SQL-build path
687
+ * ({@link buildJsonPathOrderEntry}) and the cache-hit param-collect mirrors
688
+ * so both always throw identically.
689
+ */
690
+ private validateJsonPathOrderBy;
691
+ /**
692
+ * Compile one {@link JsonPathOrderBy} entry:
693
+ * `("col" #>> $n::text[])::numeric ASC`: the numeric cast only with
694
+ * `type: 'numeric'` (default is text comparison), the extraction routed
695
+ * through the dialect's JSON hook exactly like the JSON where-filters, the
696
+ * path bound as ONE text[] param (mirrored by the order-param collectors).
697
+ * `prefix` scopes the column (`''` top-level, `t0.` inside a relation
698
+ * subquery).
699
+ */
700
+ private buildJsonPathOrderEntry;
650
701
  /**
651
702
  * Compile a relation ordering term. For a to-many relation the only allowed
652
703
  * key is `_count`, which becomes a correlated `COUNT(*)` subquery. For a
@@ -655,8 +706,37 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
655
706
  *
656
707
  * Validation: relation must exist (E005); to-many only allows `_count`, and
657
708
  * to-one only allows real target columns (E003).
709
+ *
710
+ * `ctx` generalizes the term beyond the root table: inside a relation
711
+ * subquery's orderBy the relations live on the TARGET table's metadata and
712
+ * the correlation parent is the relation's alias, not `this.table`.
658
713
  */
659
714
  private buildRelationOrderBy;
715
+ /**
716
+ * Compile the ORDER BY terms of a relation `with` clause against the
717
+ * relation's table alias. One unified path for every relation shape
718
+ * (hasMany / manyToMany / belongsTo / hasOne) supporting exactly what the
719
+ * top-level orderBy accepts at this level:
720
+ *
721
+ * - scalar columns via columnMap resolution (camelToSnake fallback) with
722
+ * {@link OrderBySpec} nulls placement,
723
+ * - {@link JsonPathOrderBy} entries (path bound as one text[] param),
724
+ * - relation ordering on the TARGET's relations (`_count` for to-many, a
725
+ * target column for to-one), correlated to the relation alias,
726
+ * - vector KNN ordering stays top-level-only (E003, same as before).
727
+ *
728
+ * Param pushes (JSON paths, relation-order global filters) MUST be mirrored,
729
+ * in the same order, by {@link collectRelationOrderParams}.
730
+ */
731
+ private buildRelationOrderClause;
732
+ /**
733
+ * Param-collect mirror of {@link buildRelationOrderClause}: JSON-path
734
+ * entries push their path (one text[] param each); relation-order entries
735
+ * mirror {@link collectOrderByParams}' relation branch (count / to-one
736
+ * global-filter params); scalar entries push nothing but re-run the same
737
+ * column validation so a warmed cache can never skip it.
738
+ */
739
+ private collectRelationOrderParams;
660
740
  /**
661
741
  * Build a correlated `(SELECT COUNT(*) …)` scalar subquery for a to-many
662
742
  * relation, correlated to `parentRef`. hasMany counts child rows via the FK;