@snowtop/ent 0.2.0-alpha.6.test2 → 0.2.0-alpha.8

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/core/clause.d.ts CHANGED
@@ -126,6 +126,50 @@ export declare function JSONKeyExists<T extends Data, K = keyof T>(dbCol: K, val
126
126
  export declare function JSONBKeyInList<T extends Data, K = keyof T>(dbCol: K, jsonCol: string, val: any, overrideAlias?: string): Clause<T, K>;
127
127
  export declare function JSONKeyInList<T extends Data, K = keyof T>(dbCol: K, jsonCol: string, val: any, overrideAlias?: string): Clause<T, K>;
128
128
  export declare function PaginationMultipleColsSubQuery<T extends Data, K = keyof T>(col: K, op: string, tableName: string, uniqueCol: K, val: any, overrideAlias?: string): Clause<T, K>;
129
+ export type PaginationUnboundColsQueryOrdering<T extends Data, K = keyof T> = {
130
+ sortCol: K;
131
+ direction: "ASC" | "DESC";
132
+ sortValue: string | number | null;
133
+ nullsPlacement?: "first" | "last";
134
+ overrideAlias?: string;
135
+ };
136
+ /**
137
+ * When paginating over multiple ordered columns, we need to construct a nested
138
+ * set of clauses to correctly filter. The resulting query will be structured as
139
+ * a group of nested ANDs and ORs.
140
+ *
141
+ * The four cases for each ordering entry are:
142
+ *
143
+ * 1) When sorting in ASC order with null placement LAST (e.g., [1,2,3,null,null])
144
+ * a) If the sort value is not null, then it needs to check for values greater than the
145
+ * sort value OR null values.
146
+ * b) If the sort value is null, then it needs to check for null values only.
147
+ * 2) When sorting in ASC order with null placement FIRST (e.g., [null,null,1,2,3])
148
+ * a) If the sort value is not null, then it needs to check for values greater than the
149
+ * sort value.
150
+ * b) If the sort value is null, then there will be no check for this value since all
151
+ * possible values are greater than or equal to null.
152
+ * 3) When sorting in DESC order with null placement LAST (e.g., [1,2,3,null,null])
153
+ * a) If the sort value is not null, then it needs to check for values less than the
154
+ * sort value OR null values.
155
+ * b) If the sort value is null, then it needs to check for null values only.
156
+ * 4) When sorting in DESC order with null placement FIRST (e.g., [null,null,1,2,3])
157
+ * a) If the sort value is not null, then it needs to check for values less than the
158
+ * sort value.
159
+ * b) If the sort value is null, then there will be no check for this value since all
160
+ * possible values are less than or equal to null.
161
+ *
162
+ * Each ordering entry will do the above check OR'ed with the following ordering entry and
163
+ * an equals check. For instance, given a set of ordering [{col1, less1}, {col2, greater2}],
164
+ * the function will construct a query that looks like:
165
+ *
166
+ * col1 < $1 OR (col1 = $1 AND col2 > $2)
167
+ *
168
+ * In english: each ordering entry will check for values lesser/greater than the supplied value,
169
+ * OR equal to the supplied value AND matching the next ordering entry. For the last ordering entry,
170
+ * it will not check for values equal to the supplied value.
171
+ */
172
+ export declare function PaginationUnboundColsQuery<T extends Data, K = keyof T>(ordering: PaginationUnboundColsQueryOrdering<T, K>[]): Clause<T, K> | undefined;
129
173
  export declare function PaginationMultipleColsQuery<T extends Data, K = keyof T>(sortCol: K, cursorCol: K, less: boolean, // if true, <, if false, >
130
174
  sortValue: any, cursorValue: any, overrideAlias?: string): Clause<T, K>;
131
175
  export declare function Add<T extends Data, K = keyof T>(col: K, value: any, overrideAlias?: string): Clause<T, K>;
package/core/clause.js CHANGED
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.JSONKeyInList = exports.JSONBKeyInList = exports.JSONKeyExists = exports.JSONPathValuePredicate = exports.JSONObjectFieldKeyAsText = exports.JSONObjectFieldKeyASJSON = exports.sensitiveValue = exports.TsVectorWebsearchToTsQuery = exports.TsVectorPhraseToTsQuery = exports.TsVectorPlainToTsQuery = exports.TsVectorColTsQuery = exports.WebsearchToTsQuery = exports.PhraseToTsQuery = exports.PlainToTsQuery = exports.TsQuery = exports.DBTypeNotIn = exports.TextNotIn = exports.IntegerNotIn = exports.UuidNotIn = exports.DBTypeIn = exports.TextIn = exports.IntegerIn = exports.UuidIn = exports.In = exports.OrOptional = exports.Or = exports.AndOptional = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.ContainsIgnoreCase = exports.EndsWithIgnoreCase = exports.StartsWithIgnoreCase = exports.Contains = exports.EndsWith = exports.StartsWith = exports.Eq = exports.ArrayNotEq = exports.ArrayEq = exports.PostgresArrayNotOverlaps = exports.PostgresArrayOverlaps = exports.PostgresArrayNotContains = exports.PostgresArrayNotContainsValue = exports.PostgresArrayContains = exports.PostgresArrayContainsValue = exports.notInClause = exports.inClause = void 0;
27
- exports.Expression = exports.getCombinedClause = exports.Modulo = exports.Divide = exports.Multiply = exports.Subtract = exports.Add = exports.PaginationMultipleColsQuery = exports.PaginationMultipleColsSubQuery = void 0;
27
+ exports.Expression = exports.getCombinedClause = exports.Modulo = exports.Divide = exports.Multiply = exports.Subtract = exports.Add = exports.PaginationMultipleColsQuery = exports.PaginationUnboundColsQuery = exports.PaginationMultipleColsSubQuery = void 0;
28
28
  const db_1 = __importStar(require("./db"));
29
29
  const query_impl_1 = require("./query_impl");
30
30
  function isSensitive(val) {
@@ -632,7 +632,7 @@ function ContainsIgnoreCase(col, value, overrideAlias) {
632
632
  exports.ContainsIgnoreCase = ContainsIgnoreCase;
633
633
  function NotEq(col, value, overrideAlias) {
634
634
  return new simpleClause(col, value, "!=", {
635
- handleNull: new isNotNullClause(col),
635
+ handleNull: new isNotNullClause(col, overrideAlias),
636
636
  overrideAlias,
637
637
  });
638
638
  }
@@ -943,6 +943,79 @@ function PaginationMultipleColsSubQuery(col, op, tableName, uniqueCol, val, over
943
943
  return new paginationMultipleColumnsSubQueryClause(col, op, tableName, uniqueCol, val, overrideAlias);
944
944
  }
945
945
  exports.PaginationMultipleColsSubQuery = PaginationMultipleColsSubQuery;
946
+ /**
947
+ * When paginating over multiple ordered columns, we need to construct a nested
948
+ * set of clauses to correctly filter. The resulting query will be structured as
949
+ * a group of nested ANDs and ORs.
950
+ *
951
+ * The four cases for each ordering entry are:
952
+ *
953
+ * 1) When sorting in ASC order with null placement LAST (e.g., [1,2,3,null,null])
954
+ * a) If the sort value is not null, then it needs to check for values greater than the
955
+ * sort value OR null values.
956
+ * b) If the sort value is null, then it needs to check for null values only.
957
+ * 2) When sorting in ASC order with null placement FIRST (e.g., [null,null,1,2,3])
958
+ * a) If the sort value is not null, then it needs to check for values greater than the
959
+ * sort value.
960
+ * b) If the sort value is null, then there will be no check for this value since all
961
+ * possible values are greater than or equal to null.
962
+ * 3) When sorting in DESC order with null placement LAST (e.g., [1,2,3,null,null])
963
+ * a) If the sort value is not null, then it needs to check for values less than the
964
+ * sort value OR null values.
965
+ * b) If the sort value is null, then it needs to check for null values only.
966
+ * 4) When sorting in DESC order with null placement FIRST (e.g., [null,null,1,2,3])
967
+ * a) If the sort value is not null, then it needs to check for values less than the
968
+ * sort value.
969
+ * b) If the sort value is null, then there will be no check for this value since all
970
+ * possible values are less than or equal to null.
971
+ *
972
+ * Each ordering entry will do the above check OR'ed with the following ordering entry and
973
+ * an equals check. For instance, given a set of ordering [{col1, less1}, {col2, greater2}],
974
+ * the function will construct a query that looks like:
975
+ *
976
+ * col1 < $1 OR (col1 = $1 AND col2 > $2)
977
+ *
978
+ * In english: each ordering entry will check for values lesser/greater than the supplied value,
979
+ * OR equal to the supplied value AND matching the next ordering entry. For the last ordering entry,
980
+ * it will not check for values equal to the supplied value.
981
+ */
982
+ function PaginationUnboundColsQuery(ordering) {
983
+ if (ordering.length === 0) {
984
+ throw new Error("Must provide at least one ordering.");
985
+ }
986
+ let nesting;
987
+ // We reverse the order of the ordering array so that we can build the query from the inner-most
988
+ // clause and work our way outwards
989
+ ordering
990
+ .reverse()
991
+ .forEach(({ sortCol, direction, sortValue, nullsPlacement, overrideAlias }) => {
992
+ const nullsOrder = nullsPlacement ?? (direction === "DESC" ? "first" : "last");
993
+ const clauseFn = direction === "DESC" ? Less : Greater;
994
+ const baseClause = clauseFn(sortCol, sortValue, overrideAlias);
995
+ const compoundClause = sortValue !== null
996
+ ? nullsOrder === "last" // There is a non-null value to compare against
997
+ ? Or(baseClause, Eq(sortCol, null, overrideAlias)) // If nulls are last, then we need to compare the value and accept nulls
998
+ : And(baseClause, NotEq(sortCol, null, overrideAlias)) // If nulls are first, then we need to compare the value and reject nulls
999
+ : nullsOrder === "last" // The value to compare against is null
1000
+ ? Eq(sortCol, null, overrideAlias) // If nulls are last, then we only accept nulls
1001
+ : undefined; // If nulls first then any all values are accepted
1002
+ // This will connect the compound clause to the previous clause for when the matching DB value equals the sort value
1003
+ // E.g. if compoundClause is `col1 < $1` and nesting is `col2 < $2`, then the result will be
1004
+ // `col1 < $1 OR (col1 = $1 AND col2 < $2)`
1005
+ if (compoundClause) {
1006
+ if (sortValue !== null) {
1007
+ nesting = nesting
1008
+ ? Or(compoundClause, And(Eq(sortCol, sortValue, overrideAlias), nesting))
1009
+ : compoundClause;
1010
+ }
1011
+ else {
1012
+ nesting = nesting ? And(compoundClause, nesting) : compoundClause;
1013
+ }
1014
+ }
1015
+ });
1016
+ return nesting;
1017
+ }
1018
+ exports.PaginationUnboundColsQuery = PaginationUnboundColsQuery;
946
1019
  function PaginationMultipleColsQuery(sortCol, cursorCol, less, // if true, <, if false, >
947
1020
  sortValue, cursorValue, overrideAlias) {
948
1021
  const clauseFn = less ? Less : Greater;
package/core/db.d.ts CHANGED
@@ -41,7 +41,7 @@ export default class DB {
41
41
  static getDialect(): Dialect;
42
42
  static initDB(args?: clientConfigArgs): void;
43
43
  }
44
- export declare const defaultTimestampParser: any;
44
+ export declare const defaultTimestampParser: (value: string) => string;
45
45
  export interface Queryer {
46
46
  query(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
47
47
  queryAll(query: string, values?: any[]): Promise<QueryResult<QueryResultRow>>;
package/core/db.js CHANGED
@@ -24,11 +24,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.PostgresClient = exports.Postgres = exports.Sqlite = exports.defaultTimestampParser = exports.Dialect = void 0;
27
- const pg_1 = __importStar(require("pg"));
28
27
  const fs = __importStar(require("fs"));
29
28
  const js_yaml_1 = require("js-yaml");
30
- const logger_1 = require("./logger");
31
29
  const luxon_1 = require("luxon");
30
+ const pg_1 = __importStar(require("pg"));
31
+ const logger_1 = require("./logger");
32
32
  function isDbDict(v) {
33
33
  return (v["production"] !== undefined ||
34
34
  v["development"] !== undefined ||
package/core/ent.d.ts CHANGED
@@ -135,8 +135,16 @@ export declare class AssocEdge {
135
135
  }
136
136
  export interface cursorOptions {
137
137
  row: Data;
138
- keys: string[];
139
- cursorKeys?: string[];
138
+ /**
139
+ * The keys that will be stored in the cursor. This should be the DB columns.
140
+ */
141
+ cursorKeys: string[];
142
+ /**
143
+ * The keys that will be used to get the values from the row. This should be
144
+ * the row object keys. If not provided, the cursorKeys will be used. This is
145
+ * only used for tests internally.
146
+ */
147
+ rowKeys?: string[];
140
148
  }
141
149
  export declare function getCursor(opts: cursorOptions): string;
142
150
  export declare class AssocEdgeData {
package/core/ent.js CHANGED
@@ -869,36 +869,29 @@ class AssocEdge {
869
869
  getCursor() {
870
870
  return getCursor({
871
871
  row: this,
872
- keys: ["id2"],
872
+ cursorKeys: ["time", "id2"],
873
873
  });
874
874
  }
875
875
  }
876
876
  exports.AssocEdge = AssocEdge;
877
877
  // TODO eventually update this for sortCol time unique keys
878
878
  function getCursor(opts) {
879
- const { row, keys, cursorKeys } = opts;
879
+ const { row, cursorKeys, rowKeys } = opts;
880
880
  // row: Data, col: string, conv?: (any) => any) {
881
881
  if (!row) {
882
882
  throw new Error(`no row passed to getCursor`);
883
883
  }
884
- if (cursorKeys?.length && cursorKeys.length !== keys.length) {
885
- throw new Error("length of cursorKeys should match keys");
884
+ if (rowKeys?.length && rowKeys.length !== cursorKeys.length) {
885
+ throw new Error("length of cursorKeys should match rowKeys");
886
886
  }
887
- const convert = (d) => {
888
- if (d instanceof Date) {
889
- return d.getTime();
890
- }
891
- return d;
892
- };
887
+ const convert = (d) => (d instanceof Date ? d.toISOString() : d);
893
888
  const parts = [];
894
- for (let i = 0; i < keys.length; i++) {
895
- const key = keys[i];
896
- const cursorKey = cursorKeys?.[i] || key;
897
- parts.push(key);
898
- parts.push(convert(row[cursorKey]));
899
- }
900
- const str = parts.join(":");
901
- return Buffer.from(str, "ascii").toString("base64");
889
+ for (let i = 0; i < cursorKeys.length; i++) {
890
+ const cursorKey = cursorKeys[i];
891
+ const rowKey = rowKeys?.[i] || cursorKey;
892
+ parts.push([cursorKey, convert(row[rowKey])]);
893
+ }
894
+ return btoa(JSON.stringify(parts));
902
895
  }
903
896
  exports.getCursor = getCursor;
904
897
  class AssocEdgeData {
@@ -1,4 +1,4 @@
1
- import { Context, ID, EdgeQueryableDataOptions, Loader, LoaderFactory } from "../base";
1
+ import { Context, EdgeQueryableDataOptions, ID, Loader, LoaderFactory } from "../base";
2
2
  import { AssocEdge, AssocEdgeConstructor } from "../ent";
3
3
  export interface AssocLoader<T extends AssocEdge> extends Loader<ID, T[]> {
4
4
  loadEdgeForID2(id: ID, id2: ID): Promise<T | undefined>;
@@ -28,11 +28,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.AssocEdgeLoaderFactory = exports.AssocDirectEdgeLoader = exports.AssocEdgeLoader = void 0;
30
30
  const dataloader_1 = __importDefault(require("dataloader"));
31
- const ent_1 = require("../ent");
31
+ const memoizee_1 = __importDefault(require("memoizee"));
32
32
  const clause = __importStar(require("../clause"));
33
+ const ent_1 = require("../ent");
33
34
  const logger_1 = require("../logger");
34
35
  const loader_1 = require("./loader");
35
- const memoizee_1 = __importDefault(require("memoizee"));
36
36
  function createLoader(options, edgeType, edgeCtr, edgeData) {
37
37
  const loaderOptions = {};
38
38
  if ((0, logger_1.logEnabled)("query")) {
@@ -208,7 +208,7 @@ class AssocEdgeLoaderFactory {
208
208
  return new AssocDirectEdgeLoader(this.edgeType, edgeCtr, options, context);
209
209
  }
210
210
  // we create a loader which can combine first X queries in the same fetch
211
- const key = `${this.name}:limit:${options.limit}:orderby:${options.orderby}:disableTransformations:${options.disableTransformations}`;
211
+ const key = `${this.name}:limit:${options.limit}:orderby:${options.orderby?.map((orderBy) => JSON.stringify(orderBy))}:disableTransformations:${options.disableTransformations}`;
212
212
  return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr, options, context), context);
213
213
  }
214
214
  }
@@ -1,8 +1,8 @@
1
- import { ID, Ent, Viewer, LoadEntOptions, EdgeQueryableDataOptions } from "../base";
1
+ import { EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, Viewer } from "../base";
2
2
  import { AssocEdge } from "../ent";
3
3
  import { AssocEdgeCountLoaderFactory } from "../loaders/assoc_count_loader";
4
4
  import { AssocEdgeLoaderFactory } from "../loaders/assoc_edge_loader";
5
- import { EdgeQuery, BaseEdgeQuery, IDInfo } from "./query";
5
+ import { BaseEdgeQuery, EdgeQuery, IDInfo } from "./query";
6
6
  export type EdgeQuerySource<TSource extends Ent<TViewer>, TDest extends Ent<TViewer> = Ent<any>, TViewer extends Viewer = Viewer> = TSource | TSource[] | ID | ID[] | EdgeQuery<TDest, Ent, AssocEdge>;
7
7
  type loaderOptionsFunc<TViewer extends Viewer> = (type: string) => LoadEntOptions<Ent, TViewer>;
8
8
  export declare abstract class AssocEdgeQueryBase<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TEdge extends AssocEdge, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<TSource, TDest, TEdge> implements EdgeQuery<TSource, TDest, TEdge> {
@@ -24,16 +24,28 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.AssocEdgeQueryBase = void 0;
27
+ const clause = __importStar(require("../clause"));
27
28
  const ent_1 = require("../ent");
28
29
  const query_1 = require("./query");
29
- const clause = __importStar(require("../clause"));
30
30
  // would be nice to someday have an API for assoc asc
31
31
  class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
32
32
  constructor(viewer, src, countLoaderFactory, dataLoaderFactory,
33
33
  // if function, it's a polymorphic edge and need to provide
34
34
  // a function that goes from edgeType to LoadEntOptions
35
35
  options) {
36
- super(viewer, "time", "id2");
36
+ super(viewer, {
37
+ cursorCol: "id2",
38
+ orderby: [
39
+ {
40
+ column: "time",
41
+ direction: "DESC",
42
+ },
43
+ {
44
+ column: "id2",
45
+ direction: "DESC",
46
+ },
47
+ ],
48
+ });
37
49
  this.viewer = viewer;
38
50
  this.src = src;
39
51
  this.countLoaderFactory = countLoaderFactory;
@@ -1,9 +1,10 @@
1
1
  import { Data, EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, QueryDataOptions, Viewer } from "../base";
2
2
  import { Clause } from "../clause";
3
3
  import { OrderBy } from "../query_impl";
4
- import { BaseEdgeQuery, EdgeQueryOptions, IDInfo } from "./query";
5
- export interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
4
+ import { BaseEdgeQuery, IDInfo } from "./query";
5
+ export interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer, TSource extends Ent<TViewer> | undefined = undefined> {
6
6
  loadEntOptions: LoadEntOptions<TDest, TViewer>;
7
+ source?: TSource;
7
8
  clause: Clause;
8
9
  name: string;
9
10
  primarySortColIsUnique?: boolean;
@@ -14,19 +15,20 @@ export interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer ex
14
15
  disableTransformations?: boolean;
15
16
  joinBETA?: QueryDataOptions["join"];
16
17
  }
17
- export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<any, TDest, Data> {
18
+ export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer, TSource extends Ent<TViewer> | undefined = undefined> extends BaseEdgeQuery<any, TDest, Data> {
18
19
  viewer: TViewer;
19
20
  private options;
20
21
  private clause;
22
+ private source?;
21
23
  constructor(viewer: TViewer, options: CustomClauseQueryOptions<TDest, TViewer>);
22
- sourceEnt(_id: ID): Promise<null>;
24
+ __maybeSetSource(src: TSource): void;
25
+ sourceEnt(_id: ID): Promise<NonNullable<TSource> | null>;
23
26
  getTableName(): string;
24
- protected includeSortColInCursor(options: EdgeQueryOptions): boolean;
25
27
  queryRawCount(): Promise<number>;
26
28
  queryAllRawCount(): Promise<Map<ID, number>>;
27
29
  protected loadRawIDs(_addID: (src: ID) => void): Promise<void>;
28
30
  protected loadRawData(_infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
29
31
  dataToID(edge: Data): ID;
30
32
  protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
31
- __getOptions(): CustomClauseQueryOptions<TDest, TViewer>;
33
+ __getOptions(): CustomClauseQueryOptions<TDest, TViewer, undefined>;
32
34
  }
@@ -52,17 +52,27 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
52
52
  this.viewer = viewer;
53
53
  this.options = options;
54
54
  this.clause = getClause(options);
55
+ this.source = options.source;
56
+ }
57
+ __maybeSetSource(src) {
58
+ if (this.source && this.source !== src) {
59
+ console.warn("source already set to something else");
60
+ }
61
+ else {
62
+ this.source = src;
63
+ }
55
64
  }
56
65
  async sourceEnt(_id) {
57
- return null;
66
+ // The sourceEnt is used for privacy checks and if we have the source we already know
67
+ // the privacy checks have been done or will be done
68
+ // This is being set for completeness but we don't really care about this.
69
+ // See https://github.com/lolopinto/ent/blob/15af0165f83458acc1d1c9f934f4534dca6154ff/ts/src/core/query/query.ts#L729-L739 for how sourceEnt is
70
+ // used in the codebase
71
+ return this.source ?? null;
58
72
  }
59
73
  getTableName() {
60
74
  return this.options.loadEntOptions.tableName;
61
75
  }
62
- includeSortColInCursor(options) {
63
- // TODO maybe we should just always do this?
64
- return options.joinBETA !== undefined && this.sortCol !== this.cursorCol;
65
- }
66
76
  async queryRawCount() {
67
77
  // sqlite needs as count otherwise it returns count(1)
68
78
  let fields = ["count(1) as count"];
@@ -97,7 +107,7 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
97
107
  if (!options.orderby) {
98
108
  options.orderby = [
99
109
  {
100
- column: this.getSortCol(),
110
+ column: this.getCursorCol(),
101
111
  direction: this.options.orderByDirection ?? "DESC",
102
112
  nullsPlacement: this.options.nullsPlacement,
103
113
  },
@@ -116,7 +126,12 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
116
126
  // if doing a join, select distinct rows
117
127
  distinct: this.options.joinBETA !== undefined,
118
128
  });
119
- this.edges.set(1, rows);
129
+ if (this.source) {
130
+ this.edges.set(this.source.id, rows);
131
+ }
132
+ else {
133
+ this.edges.set(1, rows);
134
+ }
120
135
  }
121
136
  dataToID(edge) {
122
137
  return edge.id;
@@ -1,7 +1,7 @@
1
- import { Data, Ent, ID, EdgeQueryableDataOptions, LoadEntOptions, Viewer, LoaderFactory, ConfigurableLoaderFactory } from "../base";
1
+ import { ConfigurableLoaderFactory, Data, EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, LoaderFactory, Viewer } from "../base";
2
2
  import { Clause } from "../clause";
3
3
  import { OrderBy } from "../query_impl";
4
- import { BaseEdgeQuery, IDInfo, EdgeQuery } from "./query";
4
+ import { BaseEdgeQuery, EdgeQuery, IDInfo } from "./query";
5
5
  export interface CustomEdgeQueryOptionsDeprecated<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
6
6
  src: TSource | ID;
7
7
  countLoaderFactory: LoaderFactory<ID, number>;
@@ -139,7 +139,7 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
139
139
  if (!options.orderby) {
140
140
  options.orderby = [
141
141
  {
142
- column: this.getSortCol(),
142
+ column: this.getCursorCol(),
143
143
  direction: "DESC",
144
144
  },
145
145
  ];
@@ -1,4 +1,4 @@
1
- import { ID, Ent, Viewer, EdgeQueryableDataOptions, Data, PrivacyPolicy, EdgeQueryableDataOptionsConfigureLoader, QueryableDataOptions, SelectBaseDataOptions } from "../base";
1
+ import { Data, EdgeQueryableDataOptions, EdgeQueryableDataOptionsConfigureLoader, Ent, ID, PrivacyPolicy, QueryableDataOptions, SelectBaseDataOptions, Viewer } from "../base";
2
2
  import { OrderBy } from "../query_impl";
3
3
  export interface EdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> {
4
4
  queryEdges(): Promise<TEdge[]>;
@@ -31,6 +31,7 @@ export interface PaginationInfo {
31
31
  startCursor: string;
32
32
  endCursor: string;
33
33
  }
34
+ export type CursorKeyValues = [key: string, value: string | number | null][];
34
35
  export interface EdgeQueryOptions {
35
36
  cursorCol: string;
36
37
  cursorColIsDate?: boolean;
@@ -48,16 +49,12 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
48
49
  protected genIDInfosToFetch: () => Promise<IDInfo[]>;
49
50
  private idMap;
50
51
  private idsToFetch;
51
- protected sortCol: string;
52
52
  protected cursorCol: string;
53
- protected cursorColIsDate: boolean;
54
- protected sortColIsDate: boolean;
55
53
  private edgeQueryOptions;
56
54
  private limitAdded;
57
55
  private cursorKeys;
58
- constructor(viewer: Viewer, sortCol: string, cursorCol: string);
59
56
  constructor(viewer: Viewer, options: EdgeQueryOptions);
60
- protected getSortCol(): string;
57
+ protected getCursorCol(): string;
61
58
  getPrivacyPolicy(): PrivacyPolicy<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>>;
62
59
  abstract sourceEnt(id: ID): Promise<Ent | null>;
63
60
  first(n: number, after?: string): this;
@@ -89,7 +86,6 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
89
86
  protected configureEdgeQueryableDataOptions(opts: EdgeQueryableDataOptionsConfigureLoader): void;
90
87
  protected getDefaultEdgeQueryOptions(): Partial<Pick<QueryableDataOptions, "clause" | "limit" | "orderby" | "disableTransformations">> | undefined;
91
88
  private loadEdges;
92
- protected includeSortColInCursor(options: EdgeQueryOptions): boolean;
93
89
  getCursor(row: TEdge): string;
94
90
  }
95
91
  export interface IDInfo {