@protobase/query 0.14.1 → 0.14.3

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/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CompileOptions, compileFilter } from "./compile-filter.js";
2
2
  import { Db } from "./db.js";
3
3
  import { Scope } from "./scope.js";
4
+ import { RelatedRowsQuery, buildRelatedRows, relatedRows } from "./related-rows.js";
4
5
  import { ExtraColumn, ListOptions, ListPlan, ListResult, buildListQuery, listQuery, maxLimit } from "./list-query.js";
5
6
  import { estimateCount } from "./estimate-count.js";
6
7
  import { exactCount } from "./exact-count.js";
@@ -13,4 +14,4 @@ import { ScrollMode, scrollMode } from "./scroll-mode.js";
13
14
  import { GuardFinding, GuardOptions, GuardReport, explainGuard } from "./explain-guard.js";
14
15
  import { QueryError, QueryErrorCode } from "./fields/query-error.js";
15
16
  import { SeekRequest, seekToPosition } from "./seek-to-position.js";
16
- export { type CompileOptions, type Db, type ExtraColumn, type FacetCount, type FacetOptions, type Granularity, type GuardFinding, type GuardOptions, type GuardReport, type Histogram, type HistogramBucket, type ListOptions, type ListPlan, type ListResult, type MapBounds, type MapBucket, type MapBuckets, type MapPosition, QueryError, type QueryErrorCode, type Scope, type ScrollMode, type SeekRequest, type SeriesOptions, type SeriesPoint, buildListQuery, cellsAcross, checkMapPosition, compileFilter, countUpTo, estimateCount, exactCount, explainGuard, facetCounts, histogram, listQuery, mapBuckets, mapCellPixels, maxLimit, maxMapBuckets, maxMapZoom, scrollMode, seekToPosition, series };
17
+ export { type CompileOptions, type Db, type ExtraColumn, type FacetCount, type FacetOptions, type Granularity, type GuardFinding, type GuardOptions, type GuardReport, type Histogram, type HistogramBucket, type ListOptions, type ListPlan, type ListResult, type MapBounds, type MapBucket, type MapBuckets, type MapPosition, QueryError, type QueryErrorCode, type RelatedRowsQuery, type Scope, type ScrollMode, type SeekRequest, type SeriesOptions, type SeriesPoint, buildListQuery, buildRelatedRows, cellsAcross, checkMapPosition, compileFilter, countUpTo, estimateCount, exactCount, explainGuard, facetCounts, histogram, listQuery, mapBuckets, mapCellPixels, maxLimit, maxMapBuckets, maxMapZoom, relatedRows, scrollMode, seekToPosition, series };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { QueryError } from "./fields/query-error.js";
2
2
  import { compileFilter } from "./compile-filter.js";
3
3
  import { buildListQuery, listQuery, maxLimit } from "./list-query.js";
4
+ import { buildRelatedRows, relatedRows } from "./related-rows.js";
4
5
  import { estimateCount } from "./estimate-count.js";
5
6
  import { exactCount } from "./exact-count.js";
6
7
  import { countUpTo } from "./count-up-to.js";
@@ -11,4 +12,4 @@ import { cellsAcross, checkMapPosition, mapBuckets, mapCellPixels, maxMapBuckets
11
12
  import { scrollMode } from "./scroll-mode.js";
12
13
  import { explainGuard } from "./explain-guard.js";
13
14
  import { seekToPosition } from "./seek-to-position.js";
14
- export { QueryError, buildListQuery, cellsAcross, checkMapPosition, compileFilter, countUpTo, estimateCount, exactCount, explainGuard, facetCounts, histogram, listQuery, mapBuckets, mapCellPixels, maxLimit, maxMapBuckets, maxMapZoom, scrollMode, seekToPosition, series };
15
+ export { QueryError, buildListQuery, buildRelatedRows, cellsAcross, checkMapPosition, compileFilter, countUpTo, estimateCount, exactCount, explainGuard, facetCounts, histogram, listQuery, mapBuckets, mapCellPixels, maxLimit, maxMapBuckets, maxMapZoom, relatedRows, scrollMode, seekToPosition, series };
@@ -0,0 +1,33 @@
1
+ import { Db } from "./db.js";
2
+ import { Scope } from "./scope.js";
3
+ import { KeyValue, ResourceModel, SortSpec } from "@protobase/schema";
4
+ //#region src/related-rows.d.ts
5
+ /** The rows of `model` whose `field` holds one of `values`, at most `limit` for each value, in `sort` order. */
6
+ export type RelatedRowsQuery = {
7
+ /** The field that points at the records the rows belong to, such as a photo's `listing_id`. */
8
+ field: string;
9
+ /** The keys of those records. */
10
+ values: readonly KeyValue[];
11
+ /** The fields it reads, by name; `field` is always among them. */
12
+ columns: string[];
13
+ /** The order within each value; the primary key decides ties. */
14
+ sort?: SortSpec;
15
+ limit: number;
16
+ };
17
+ /**
18
+ * The query `relatedRows` runs: the values that have rows, each joined to its first `limit` rows by a lateral subquery,
19
+ * so an index on `field` and the sort reads only those rows. Both sides stay inside the scope.
20
+ */
21
+ export declare const buildRelatedRows: (db: Db, model: ResourceModel, query: RelatedRowsQuery, scope?: Scope) => import("kysely").SelectQueryBuilder<{
22
+ [x: string]: any;
23
+ [x: number]: any;
24
+ [x: symbol]: any;
25
+ }, "k" | "r", {
26
+ [x: string]: any;
27
+ }>;
28
+ /**
29
+ * The rows of every value in one query, in `sort` order for each value, with `field` holding the value they belong to.
30
+ * The values themselves are never read from the caller's input: they are the keys of records already read.
31
+ */
32
+ export declare const relatedRows: (db: Db, model: ResourceModel, query: RelatedRowsQuery, scope?: Scope) => Promise<Array<Record<string, unknown>>>;
33
+ //#endregion
@@ -0,0 +1,35 @@
1
+ import { QueryError } from "./fields/query-error.js";
2
+ import { columnRef, findField } from "./columns.js";
3
+ import { baseQuery } from "./base-query.js";
4
+ import { effectiveSort } from "./sort.js";
5
+ import { orderTerm } from "./order.js";
6
+ import "./list-query.js";
7
+ import { sql } from "kysely";
8
+ //#region src/related-rows.ts
9
+ const ownerAlias = "__pb_owner";
10
+ const rankAlias = "__pb_rank";
11
+ /**
12
+ * The query `relatedRows` runs: the values that have rows, each joined to its first `limit` rows by a lateral subquery,
13
+ * so an index on `field` and the sort reads only those rows. Both sides stay inside the scope.
14
+ */
15
+ const buildRelatedRows = (db, model, query, scope) => {
16
+ if (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 500) throw new QueryError("invalid_limit", `limit must be a whole number from 1 to 500`);
17
+ const owner = findField(model, query.field);
18
+ const columns = [.../* @__PURE__ */ new Set([query.field, ...query.columns])].map((name) => findField(model, name));
19
+ const order = effectiveSort(model, query.sort).map((key) => orderTerm(key));
20
+ const owners = baseQuery(db, model, void 0, scope).select(sql`${columnRef(owner)}`.as(ownerAlias)).distinct().where(sql`${columnRef(owner)} in (${sql.join(query.values)})`);
21
+ let rows = baseQuery(db, model, void 0, scope).select(columns.map((field) => sql`${columnRef(field)}`.as(field.name))).select(sql`row_number() over (order by ${sql.join(order)})`.as(rankAlias)).where(sql`${columnRef(owner)} = ${sql.ref(`k.${ownerAlias}`)}`);
22
+ for (const term of order) rows = rows.orderBy(term);
23
+ return db.selectFrom(owners.as("k")).innerJoinLateral(rows.limit(query.limit).as("r"), (join) => join.onTrue()).selectAll("r").orderBy(sql.ref(`r.${rankAlias}`));
24
+ };
25
+ /**
26
+ * The rows of every value in one query, in `sort` order for each value, with `field` holding the value they belong to.
27
+ * The values themselves are never read from the caller's input: they are the keys of records already read.
28
+ */
29
+ const relatedRows = async (db, model, query, scope) => {
30
+ const built = buildRelatedRows(db, model, query, scope);
31
+ if (query.values.length === 0) return [];
32
+ return (await built.execute()).map(({ [rankAlias]: _rank, ...row }) => row);
33
+ };
34
+ //#endregion
35
+ export { buildRelatedRows, relatedRows };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/query",
3
- "version": "0.14.1",
3
+ "version": "0.14.3",
4
4
  "description": "Kysely list, filter, count and aggregate queries over Protobase resources.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@protobase/schema": "0.14.1",
32
+ "@protobase/schema": "0.14.3",
33
33
  "kysely": "^0.29.6"
34
34
  }
35
35
  }