@snowtop/ent 0.1.0-alpha16 → 0.1.0-alpha160-test2

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.
Files changed (176) hide show
  1. package/action/action.d.ts +25 -14
  2. package/action/action.js +22 -7
  3. package/action/executor.d.ts +16 -3
  4. package/action/executor.js +89 -28
  5. package/action/experimental_action.d.ts +25 -16
  6. package/action/experimental_action.js +34 -14
  7. package/action/index.d.ts +4 -1
  8. package/action/index.js +7 -1
  9. package/action/operations.d.ts +126 -0
  10. package/action/operations.js +686 -0
  11. package/action/orchestrator.d.ts +43 -12
  12. package/action/orchestrator.js +461 -101
  13. package/action/relative_value.d.ts +47 -0
  14. package/action/relative_value.js +125 -0
  15. package/action/transaction.d.ts +10 -0
  16. package/action/transaction.js +23 -0
  17. package/auth/auth.d.ts +1 -1
  18. package/core/base.d.ts +56 -23
  19. package/core/base.js +7 -1
  20. package/core/clause.d.ts +103 -39
  21. package/core/clause.js +430 -66
  22. package/core/config.d.ts +13 -3
  23. package/core/config.js +10 -1
  24. package/core/const.d.ts +3 -0
  25. package/core/const.js +6 -0
  26. package/core/context.d.ts +6 -3
  27. package/core/context.js +22 -3
  28. package/core/convert.d.ts +1 -1
  29. package/core/date.js +1 -5
  30. package/core/db.d.ts +12 -8
  31. package/core/db.js +21 -9
  32. package/core/ent.d.ts +99 -95
  33. package/core/ent.js +550 -602
  34. package/core/global_schema.d.ts +7 -0
  35. package/core/global_schema.js +51 -0
  36. package/core/loaders/assoc_count_loader.d.ts +5 -2
  37. package/core/loaders/assoc_count_loader.js +19 -3
  38. package/core/loaders/assoc_edge_loader.d.ts +2 -3
  39. package/core/loaders/assoc_edge_loader.js +23 -17
  40. package/core/loaders/index.d.ts +1 -2
  41. package/core/loaders/index.js +1 -5
  42. package/core/loaders/loader.d.ts +3 -3
  43. package/core/loaders/loader.js +4 -21
  44. package/core/loaders/object_loader.d.ts +30 -9
  45. package/core/loaders/object_loader.js +226 -79
  46. package/core/loaders/query_loader.d.ts +7 -13
  47. package/core/loaders/query_loader.js +60 -24
  48. package/core/loaders/raw_count_loader.d.ts +1 -0
  49. package/core/loaders/raw_count_loader.js +8 -3
  50. package/core/logger.d.ts +1 -1
  51. package/core/logger.js +1 -0
  52. package/core/privacy.d.ts +26 -16
  53. package/core/privacy.js +68 -51
  54. package/core/query/assoc_query.d.ts +3 -2
  55. package/core/query/assoc_query.js +10 -2
  56. package/core/query/custom_clause_query.d.ts +29 -0
  57. package/core/query/custom_clause_query.js +105 -0
  58. package/core/query/custom_query.d.ts +19 -2
  59. package/core/query/custom_query.js +111 -13
  60. package/core/query/index.d.ts +1 -0
  61. package/core/query/index.js +3 -1
  62. package/core/query/query.d.ts +18 -4
  63. package/core/query/query.js +135 -58
  64. package/core/query/shared_assoc_test.d.ts +2 -1
  65. package/core/query/shared_assoc_test.js +186 -55
  66. package/core/query/shared_test.d.ts +9 -2
  67. package/core/query/shared_test.js +529 -236
  68. package/core/query_impl.d.ts +8 -0
  69. package/core/query_impl.js +28 -0
  70. package/core/viewer.d.ts +2 -0
  71. package/core/viewer.js +3 -1
  72. package/graphql/graphql.d.ts +108 -22
  73. package/graphql/graphql.js +183 -137
  74. package/graphql/graphql_field_helpers.d.ts +9 -3
  75. package/graphql/graphql_field_helpers.js +22 -2
  76. package/graphql/index.d.ts +2 -2
  77. package/graphql/index.js +5 -5
  78. package/graphql/query/connection_type.d.ts +9 -9
  79. package/graphql/query/shared_assoc_test.js +1 -1
  80. package/graphql/query/shared_edge_connection.js +1 -19
  81. package/graphql/scalars/orderby_direction.d.ts +2 -0
  82. package/graphql/scalars/orderby_direction.js +15 -0
  83. package/imports/dataz/example1/_auth.js +128 -47
  84. package/imports/dataz/example1/_viewer.js +87 -39
  85. package/imports/index.d.ts +7 -2
  86. package/imports/index.js +20 -5
  87. package/index.d.ts +23 -5
  88. package/index.js +35 -10
  89. package/package.json +20 -19
  90. package/parse_schema/parse.d.ts +33 -9
  91. package/parse_schema/parse.js +182 -33
  92. package/schema/base_schema.d.ts +13 -3
  93. package/schema/base_schema.js +13 -0
  94. package/schema/field.d.ts +78 -21
  95. package/schema/field.js +232 -72
  96. package/schema/index.d.ts +2 -2
  97. package/schema/index.js +7 -2
  98. package/schema/json_field.d.ts +16 -4
  99. package/schema/json_field.js +32 -2
  100. package/schema/schema.d.ts +109 -20
  101. package/schema/schema.js +42 -53
  102. package/schema/struct_field.d.ts +15 -3
  103. package/schema/struct_field.js +117 -22
  104. package/schema/union_field.d.ts +1 -1
  105. package/scripts/custom_compiler.js +12 -8
  106. package/scripts/custom_graphql.js +167 -64
  107. package/scripts/migrate_v0.1.js +36 -0
  108. package/scripts/move_types.js +120 -0
  109. package/scripts/read_schema.js +22 -7
  110. package/testutils/action/complex_schemas.d.ts +69 -0
  111. package/testutils/action/complex_schemas.js +405 -0
  112. package/testutils/builder.d.ts +37 -41
  113. package/testutils/builder.js +66 -46
  114. package/testutils/db/fixture.d.ts +10 -0
  115. package/testutils/db/fixture.js +26 -0
  116. package/testutils/db/{test_db.d.ts → temp_db.d.ts} +32 -8
  117. package/testutils/db/{test_db.js → temp_db.js} +251 -48
  118. package/testutils/db/value.d.ts +7 -0
  119. package/testutils/db/value.js +251 -0
  120. package/testutils/db_mock.d.ts +16 -4
  121. package/testutils/db_mock.js +52 -9
  122. package/testutils/db_time_zone.d.ts +4 -0
  123. package/testutils/db_time_zone.js +41 -0
  124. package/testutils/ent-graphql-tests/index.d.ts +7 -1
  125. package/testutils/ent-graphql-tests/index.js +56 -26
  126. package/testutils/fake_comms.js +1 -1
  127. package/testutils/fake_data/const.d.ts +2 -1
  128. package/testutils/fake_data/const.js +3 -0
  129. package/testutils/fake_data/fake_contact.d.ts +7 -3
  130. package/testutils/fake_data/fake_contact.js +13 -7
  131. package/testutils/fake_data/fake_event.d.ts +4 -1
  132. package/testutils/fake_data/fake_event.js +7 -6
  133. package/testutils/fake_data/fake_tag.d.ts +36 -0
  134. package/testutils/fake_data/fake_tag.js +89 -0
  135. package/testutils/fake_data/fake_user.d.ts +8 -5
  136. package/testutils/fake_data/fake_user.js +31 -19
  137. package/testutils/fake_data/index.js +5 -1
  138. package/testutils/fake_data/internal.d.ts +2 -0
  139. package/testutils/fake_data/internal.js +7 -1
  140. package/testutils/fake_data/tag_query.d.ts +13 -0
  141. package/testutils/fake_data/tag_query.js +48 -0
  142. package/testutils/fake_data/test_helpers.d.ts +14 -6
  143. package/testutils/fake_data/test_helpers.js +31 -15
  144. package/testutils/fake_data/user_query.d.ts +16 -6
  145. package/testutils/fake_data/user_query.js +72 -23
  146. package/testutils/fake_log.js +1 -1
  147. package/testutils/parse_sql.d.ts +6 -0
  148. package/testutils/parse_sql.js +16 -2
  149. package/testutils/test_edge_global_schema.d.ts +15 -0
  150. package/testutils/test_edge_global_schema.js +62 -0
  151. package/testutils/write.d.ts +2 -2
  152. package/testutils/write.js +33 -7
  153. package/tsc/ast.d.ts +15 -3
  154. package/tsc/ast.js +114 -23
  155. package/tsc/compilerOptions.js +5 -1
  156. package/tsc/move_generated.d.ts +1 -0
  157. package/tsc/move_generated.js +164 -0
  158. package/tsc/transform.d.ts +22 -0
  159. package/tsc/transform.js +182 -0
  160. package/tsc/transform_action.d.ts +22 -0
  161. package/tsc/transform_action.js +183 -0
  162. package/tsc/transform_ent.d.ts +17 -0
  163. package/tsc/transform_ent.js +60 -0
  164. package/tsc/transform_schema.d.ts +27 -0
  165. package/{scripts → tsc}/transform_schema.js +146 -117
  166. package/core/loaders/index_loader.d.ts +0 -14
  167. package/core/loaders/index_loader.js +0 -27
  168. package/graphql/enums.d.ts +0 -3
  169. package/graphql/enums.js +0 -25
  170. package/scripts/move_generated.js +0 -141
  171. package/scripts/transform_actions.js +0 -266
  172. package/scripts/transform_code.d.ts +0 -1
  173. package/scripts/transform_code.js +0 -111
  174. package/scripts/transform_schema.d.ts +0 -1
  175. /package/scripts/{move_generated.d.ts → migrate_v0.1.d.ts} +0 -0
  176. /package/scripts/{transform_actions.d.ts → move_types.d.ts} +0 -0
@@ -1,20 +1,104 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CustomEdgeQueryBase = void 0;
4
+ const clause_1 = require("../clause");
4
5
  const ent_1 = require("../ent");
6
+ const loaders_1 = require("../loaders");
5
7
  const query_1 = require("./query");
8
+ function getClause(opts) {
9
+ let cls = opts.clause;
10
+ if (opts.disableTransformations) {
11
+ return cls;
12
+ }
13
+ let optClause = opts.loadEntOptions.loaderFactory?.options?.clause;
14
+ if (typeof optClause === "function") {
15
+ optClause = optClause();
16
+ }
17
+ if (!optClause) {
18
+ return cls;
19
+ }
20
+ return (0, clause_1.AndOptional)(cls, optClause);
21
+ }
22
+ function getRawCountLoader(viewer, opts) {
23
+ if (!viewer.context?.cache) {
24
+ return new loaders_1.RawCountLoader({
25
+ tableName: opts.loadEntOptions.tableName,
26
+ groupCol: opts.groupCol,
27
+ clause: getClause(opts),
28
+ });
29
+ }
30
+ const name = `custom_query_count_loader:${opts.name}`;
31
+ return viewer.context.cache.getLoader(name, () => new loaders_1.RawCountLoader({
32
+ tableName: opts.loadEntOptions.tableName,
33
+ groupCol: opts.groupCol,
34
+ clause: getClause(opts),
35
+ }));
36
+ }
37
+ function getQueryLoader(viewer, opts, options) {
38
+ const loader = opts.loadEntOptions.loaderFactory;
39
+ const name = `custom_query_loader:${opts.name}`;
40
+ return loaders_1.QueryLoaderFactory.createConfigurableLoader(name, {
41
+ tableName: opts.loadEntOptions.tableName,
42
+ fields: opts.loadEntOptions.fields,
43
+ groupCol: opts.groupCol,
44
+ clause: getClause(opts),
45
+ toPrime: [loader],
46
+ }, options, viewer.context);
47
+ }
48
+ function isDeprecatedOptions(options) {
49
+ return (options
50
+ .countLoaderFactory !== undefined);
51
+ }
6
52
  class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
7
53
  constructor(viewer, options) {
8
- super(viewer, options.sortColumn || "created_at");
54
+ let opts;
55
+ let defaultSort = "id";
56
+ let uniqueColIsSort = false;
57
+ let orderby;
58
+ let sortCol;
59
+ if (isDeprecatedOptions(options)) {
60
+ opts = options.options;
61
+ }
62
+ else {
63
+ opts = options.loadEntOptions;
64
+ if (options.primarySortColIsUnique) {
65
+ uniqueColIsSort = true;
66
+ }
67
+ if (options.orderby) {
68
+ orderby = options.orderby;
69
+ sortCol = options.orderby[0].column;
70
+ }
71
+ }
72
+ let uniqueCol = opts.loaderFactory.options?.key || "id";
73
+ if (!orderby) {
74
+ options.sortColumn = options.sortColumn || defaultSort;
75
+ sortCol = options.sortColumn;
76
+ orderby = [
77
+ {
78
+ column: options.sortColumn,
79
+ direction: "DESC",
80
+ },
81
+ ];
82
+ }
83
+ if (uniqueColIsSort) {
84
+ uniqueCol = sortCol || defaultSort;
85
+ }
86
+ super(viewer, {
87
+ cursorCol: uniqueCol,
88
+ orderby,
89
+ });
9
90
  this.viewer = viewer;
10
91
  this.options = options;
11
- options.sortColumn = options.sortColumn || "created_at";
12
92
  if (typeof options.src === "object") {
13
93
  this.id = options.src.id;
14
94
  }
15
95
  else {
16
96
  this.id = options.src;
17
97
  }
98
+ this.opts = opts;
99
+ }
100
+ getTableName() {
101
+ return this.opts.tableName;
18
102
  }
19
103
  async idVisible() {
20
104
  const ids = await this.genIDInfosToFetch();
@@ -23,14 +107,24 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
23
107
  }
24
108
  return !ids[0].invalidated;
25
109
  }
110
+ getCountLoader() {
111
+ if (isDeprecatedOptions(this.options)) {
112
+ return this.options.countLoaderFactory.createLoader(this.viewer.context);
113
+ }
114
+ return getRawCountLoader(this.viewer, this.options);
115
+ }
116
+ getQueryLoader(options) {
117
+ if (isDeprecatedOptions(this.options)) {
118
+ return this.options.dataLoaderFactory.createConfigurableLoader(options, this.viewer.context);
119
+ }
120
+ return getQueryLoader(this.viewer, this.options, options);
121
+ }
26
122
  async queryRawCount() {
27
123
  const idVisible = await this.idVisible();
28
124
  if (!idVisible) {
29
125
  return 0;
30
126
  }
31
- return await this.options.countLoaderFactory
32
- .createLoader(this.viewer.context)
33
- .load(this.id);
127
+ return this.getCountLoader().load(this.id);
34
128
  }
35
129
  async queryAllRawCount() {
36
130
  let count = 0;
@@ -44,16 +138,21 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
44
138
  addID(this.options.src);
45
139
  }
46
140
  async loadRawData(infos, options) {
47
- const loader = this.options.dataLoaderFactory.createConfigurableLoader(options, this.viewer.context);
141
+ if (infos.length !== 1) {
142
+ throw new Error(`expected 1 info passed to loadRawData. ${infos.length} passed`);
143
+ }
48
144
  if (!options.orderby) {
49
- options.orderby = `${this.options.sortColumn} DESC`;
145
+ options.orderby = [
146
+ {
147
+ column: this.getSortCol(),
148
+ direction: "DESC",
149
+ },
150
+ ];
50
151
  }
51
152
  if (!options.limit) {
52
- options.limit = ent_1.DefaultLimit;
53
- }
54
- if (infos.length !== 1) {
55
- throw new Error(`expected 1 info passed to loadRawData. ${infos.length} passed`);
153
+ options.limit = (0, ent_1.getDefaultLimit)();
56
154
  }
155
+ const loader = this.getQueryLoader(options);
57
156
  const info = infos[0];
58
157
  if (info.invalidated) {
59
158
  this.edges.set(this.id, []);
@@ -66,8 +165,7 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
66
165
  return edge.id;
67
166
  }
68
167
  async loadEntsFromEdges(id, rows) {
69
- const ents = await (0, ent_1.applyPrivacyPolicyForRows)(this.viewer, rows, this.options.options);
70
- return Array.from(ents.values());
168
+ return (0, ent_1.applyPrivacyPolicyForRows)(this.viewer, rows, this.opts);
71
169
  }
72
170
  }
73
171
  exports.CustomEdgeQueryBase = CustomEdgeQueryBase;
@@ -1,3 +1,4 @@
1
1
  export { EdgeQuery, BaseEdgeQuery, EdgeQueryFilter, PaginationInfo, } from "./query";
2
2
  export { AssocEdgeQueryBase, EdgeQuerySource } from "./assoc_query";
3
3
  export { CustomEdgeQueryBase } from "./custom_query";
4
+ export { CustomClauseQuery } from "./custom_clause_query";
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CustomEdgeQueryBase = exports.AssocEdgeQueryBase = exports.BaseEdgeQuery = void 0;
3
+ exports.CustomClauseQuery = exports.CustomEdgeQueryBase = exports.AssocEdgeQueryBase = exports.BaseEdgeQuery = void 0;
4
4
  var query_1 = require("./query");
5
5
  Object.defineProperty(exports, "BaseEdgeQuery", { enumerable: true, get: function () { return query_1.BaseEdgeQuery; } });
6
6
  var assoc_query_1 = require("./assoc_query");
7
7
  Object.defineProperty(exports, "AssocEdgeQueryBase", { enumerable: true, get: function () { return assoc_query_1.AssocEdgeQueryBase; } });
8
8
  var custom_query_1 = require("./custom_query");
9
9
  Object.defineProperty(exports, "CustomEdgeQueryBase", { enumerable: true, get: function () { return custom_query_1.CustomEdgeQueryBase; } });
10
+ var custom_clause_query_1 = require("./custom_clause_query");
11
+ Object.defineProperty(exports, "CustomClauseQuery", { enumerable: true, get: function () { return custom_clause_query_1.CustomClauseQuery; } });
@@ -1,4 +1,5 @@
1
- import { ID, Ent, Viewer, EdgeQueryableDataOptions, Data, PrivacyPolicy } from "../base";
1
+ import { ID, Ent, Viewer, EdgeQueryableDataOptions, Data, PrivacyPolicy, EdgeQueryableDataOptionsConfigureLoader } from "../base";
2
+ import { OrderBy } from "../query_impl";
2
3
  export interface EdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> {
3
4
  queryEdges(): Promise<TEdge[]>;
4
5
  queryAllEdges(): Promise<Map<ID, TEdge[]>>;
@@ -20,7 +21,7 @@ export interface EdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends
20
21
  }
21
22
  export interface EdgeQueryFilter<T extends Data> {
22
23
  filter?(id: ID, edges: T[]): T[];
23
- query?(options: EdgeQueryableDataOptions): EdgeQueryableDataOptions;
24
+ query?(options: EdgeQueryableDataOptions): EdgeQueryableDataOptions | Promise<EdgeQueryableDataOptions>;
24
25
  paginationInfo?(id: ID): PaginationInfo | undefined;
25
26
  }
26
27
  export interface PaginationInfo {
@@ -29,9 +30,12 @@ export interface PaginationInfo {
29
30
  startCursor: string;
30
31
  endCursor: string;
31
32
  }
33
+ interface EdgeQueryOptions {
34
+ cursorCol: string;
35
+ orderby: OrderBy;
36
+ }
32
37
  export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> implements EdgeQuery<TSource, TDest, TEdge> {
33
38
  viewer: Viewer;
34
- private sortCol;
35
39
  private filters;
36
40
  private queryDispatched;
37
41
  protected edges: Map<ID, TEdge[]>;
@@ -40,7 +44,12 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
40
44
  protected genIDInfosToFetch: () => Promise<IDInfo[]>;
41
45
  private idMap;
42
46
  private idsToFetch;
43
- constructor(viewer: Viewer, sortCol: string);
47
+ private sortCol;
48
+ private cursorCol;
49
+ private edgeQueryOptions;
50
+ constructor(viewer: Viewer, sortCol: string, cursorCol: string);
51
+ constructor(viewer: Viewer, options: EdgeQueryOptions);
52
+ protected getSortCol(): string;
44
53
  getPrivacyPolicy(): PrivacyPolicy<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>>;
45
54
  abstract sourceEnt(id: ID): Promise<Ent | null>;
46
55
  first(n: number, after?: string): this;
@@ -64,7 +73,11 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
64
73
  protected abstract loadRawIDs(addID: (src: ID | TSource) => void): Promise<void>;
65
74
  protected abstract loadRawData(infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
66
75
  private addID;
76
+ abstract getTableName(): string | Promise<string>;
67
77
  protected genIDInfosToFetchImpl(): Promise<IDInfo[]>;
78
+ private _defaultEdgeQueryableOptions;
79
+ protected configureEdgeQueryableDataOptions(opts: EdgeQueryableDataOptionsConfigureLoader): void;
80
+ protected getDefaultEdgeQueryOptions(): Partial<Pick<import("../base").QueryableDataOptions, "clause" | "limit" | "orderby" | "disableTransformations">> | undefined;
68
81
  private loadEdges;
69
82
  getCursor(row: TEdge): string;
70
83
  }
@@ -72,3 +85,4 @@ export interface IDInfo {
72
85
  id: ID;
73
86
  invalidated?: boolean;
74
87
  }
88
+ export {};
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -27,6 +31,9 @@ const ent_1 = require("../ent");
27
31
  const clause = __importStar(require("../clause"));
28
32
  const memoizee_1 = __importDefault(require("memoizee"));
29
33
  const privacy_1 = require("../privacy");
34
+ const uuid_1 = require("uuid");
35
+ const query_impl_1 = require("../query_impl");
36
+ const types_1 = require("util/types");
30
37
  // TODO can we generalize EdgeQuery to support any clause
31
38
  function assertPositive(n) {
32
39
  if (n < 0) {
@@ -36,31 +43,32 @@ function assertPositive(n) {
36
43
  function assertValidCursor(cursor, col) {
37
44
  let decoded = Buffer.from(cursor, "base64").toString("ascii");
38
45
  let parts = decoded.split(":");
46
+ // uuid, don't parse int since it tries to validate just first part
47
+ if ((0, uuid_1.validate)(parts[1])) {
48
+ return parts[1];
49
+ }
39
50
  // invalid or unknown cursor. nothing to do here.
40
51
  if (parts.length !== 2 || parts[0] !== col) {
41
52
  throw new Error(`invalid cursor ${cursor} passed`);
42
53
  }
43
- // TODO check if numeric or not but for now we're only doing numbers
54
+ // TODO handle both cases... (time vs not) better
55
+ // TODO change this to only do the parseInt part if time...
56
+ // pass flag indicating if time?
44
57
  const time = parseInt(parts[1], 10);
45
58
  if (isNaN(time)) {
46
- throw new Error(`invalid cursor ${cursor} passed`);
59
+ return parts[1];
47
60
  }
48
61
  return time;
49
62
  }
63
+ const orderbyRegex = new RegExp(/([0-9a-z_]+)[ ]?([0-9a-z_]+)?/i);
50
64
  class FirstFilter {
51
65
  constructor(options) {
52
66
  this.options = options;
53
67
  this.pageMap = new Map();
54
68
  assertPositive(options.limit);
55
- if (options.before) {
56
- throw new Error(`cannot specify before with a first filter`);
57
- }
58
- this.sortCol = options.sortCol || "time";
69
+ this.sortCol = options.sortCol;
59
70
  if (options.after) {
60
- this.offset = assertValidCursor(options.after, this.sortCol);
61
- }
62
- if (this.options.sortColNotTime && !this.options.sortCol) {
63
- throw new Error(`cannot specify sortColNotTime without specifying a sortCol`);
71
+ this.offset = assertValidCursor(options.after, options.cursorCol);
64
72
  }
65
73
  this.edgeQuery = options.query;
66
74
  }
@@ -69,6 +77,8 @@ class FirstFilter {
69
77
  const ret = edges.slice(0, this.options.limit);
70
78
  this.pageMap.set(id, {
71
79
  hasNextPage: true,
80
+ // hasPreviousPage always false even if there's a previous page because
81
+ // we shouldn't be querying in both directions at the same
72
82
  hasPreviousPage: false,
73
83
  startCursor: this.edgeQuery.getCursor(ret[0]),
74
84
  endCursor: this.edgeQuery.getCursor(ret[ret.length - 1]),
@@ -82,24 +92,37 @@ class FirstFilter {
82
92
  // so we'd need a way to indicate whether this is done in sql or not
83
93
  return edges;
84
94
  }
85
- query(options) {
95
+ async query(options) {
86
96
  // we fetch an extra one to see if we're at the end
87
97
  const limit = this.options.limit + 1;
88
98
  options.limit = limit;
89
- // todo may not be desc
90
- // and if asc
91
- // clause below should switch to greater...
92
- options.orderby = `${this.sortCol} DESC`;
93
99
  // we sort by most recent first
94
100
  // so when paging, we fetch afterCursor X
95
- if (this.offset) {
96
- if (this.options.sortColNotTime) {
97
- options.clause = clause.Less(this.sortCol, this.offset);
101
+ const less = this.options.orderby[0].direction === "DESC";
102
+ const orderby = this.options.orderby;
103
+ if (this.options.cursorCol !== this.sortCol) {
104
+ // we also sort cursor col in same direction. (direction doesn't matter)
105
+ orderby.push({
106
+ column: this.options.cursorCol,
107
+ direction: orderby[0].direction,
108
+ });
109
+ if (this.offset) {
110
+ const res = this.edgeQuery.getTableName();
111
+ const tableName = (0, types_1.isPromise)(res) ? await res : res;
112
+ // inner col time
113
+ options.clause = clause.PaginationMultipleColsSubQuery(this.sortCol, less ? "<" : ">", tableName, this.options.cursorCol, this.offset);
98
114
  }
99
- else {
100
- options.clause = clause.Less(this.sortCol, new Date(this.offset).toISOString());
115
+ }
116
+ else {
117
+ if (this.offset) {
118
+ let clauseFn = less ? clause.Less : clause.Greater;
119
+ let val = this.options.sortColTime
120
+ ? new Date(this.offset).toISOString()
121
+ : this.offset;
122
+ options.clause = clauseFn(this.sortCol, val);
101
123
  }
102
124
  }
125
+ options.orderby = orderby;
103
126
  return options;
104
127
  }
105
128
  // TODO?
@@ -112,15 +135,9 @@ class LastFilter {
112
135
  this.options = options;
113
136
  this.pageMap = new Map();
114
137
  assertPositive(options.limit);
115
- if (options.after) {
116
- throw new Error(`cannot specify after with a last filter`);
117
- }
118
- this.sortCol = options.sortCol || "time";
138
+ this.sortCol = options.sortCol;
119
139
  if (options.before) {
120
- this.offset = assertValidCursor(options.before, this.sortCol);
121
- }
122
- if (this.options.sortColNotTime && !this.options.sortCol) {
123
- throw new Error(`cannot specify sortColNotTime without specifying a sortCol`);
140
+ this.offset = assertValidCursor(options.before, options.cursorCol);
124
141
  }
125
142
  this.edgeQuery = options.query;
126
143
  }
@@ -137,11 +154,13 @@ class LastFilter {
137
154
  }
138
155
  }
139
156
  else {
140
- ret = edges.slice(edges.length - this.options.limit, edges.length);
157
+ ret = edges.slice(0, this.options.limit);
141
158
  }
142
159
  if (edges.length > this.options.limit) {
143
160
  this.pageMap.set(id, {
144
161
  hasPreviousPage: true,
162
+ // hasNextPage always false even if there's a next page because
163
+ // we shouldn't be querying in both directions at the same
145
164
  hasNextPage: false,
146
165
  startCursor: this.edgeQuery.getCursor(ret[0]),
147
166
  endCursor: this.edgeQuery.getCursor(ret[ret.length - 1]),
@@ -149,18 +168,33 @@ class LastFilter {
149
168
  }
150
169
  return ret;
151
170
  }
152
- query(options) {
153
- if (!this.offset) {
154
- return options;
155
- }
156
- options.orderby = `${this.sortCol} ASC`;
171
+ async query(options) {
172
+ const orderby = (0, query_impl_1.reverseOrderBy)(this.options.orderby);
173
+ const greater = orderby[0].direction === "ASC";
157
174
  options.limit = this.options.limit + 1; // fetch an extra so we know if previous pag
158
- if (this.options.sortColNotTime) {
159
- options.clause = clause.Greater(this.sortCol, this.offset);
175
+ if (this.options.cursorCol !== this.sortCol) {
176
+ const res = this.edgeQuery.getTableName();
177
+ const tableName = (0, types_1.isPromise)(res) ? await res : res;
178
+ if (this.offset) {
179
+ // inner col time
180
+ options.clause = clause.PaginationMultipleColsSubQuery(this.sortCol, greater ? ">" : "<", tableName, this.options.cursorCol, this.offset);
181
+ }
182
+ // we also sort cursor col in same direction. (direction doesn't matter)
183
+ orderby.push({
184
+ column: this.options.cursorCol,
185
+ direction: orderby[0].direction,
186
+ });
160
187
  }
161
188
  else {
162
- options.clause = clause.Greater(this.sortCol, new Date(this.offset).toISOString());
189
+ if (this.offset) {
190
+ let clauseFn = greater ? clause.Greater : clause.Less;
191
+ let val = this.options.sortColTime
192
+ ? new Date(this.offset).toISOString()
193
+ : this.offset;
194
+ options.clause = clauseFn(this.sortCol, val);
195
+ }
163
196
  }
197
+ options.orderby = orderby;
164
198
  return options;
165
199
  }
166
200
  paginationInfo(id) {
@@ -168,9 +202,8 @@ class LastFilter {
168
202
  }
169
203
  }
170
204
  class BaseEdgeQuery {
171
- constructor(viewer, sortCol) {
205
+ constructor(viewer, sortColOrOptions, cursorColMaybe) {
172
206
  this.viewer = viewer;
173
- this.sortCol = sortCol;
174
207
  this.filters = [];
175
208
  this.edges = new Map();
176
209
  this.pagination = new Map();
@@ -181,7 +214,7 @@ class BaseEdgeQuery {
181
214
  return await this.querySingleEdge("queryEdges");
182
215
  };
183
216
  this.queryAllEdges = async () => {
184
- return await this.memoizedloadEdges();
217
+ return this.memoizedloadEdges();
185
218
  };
186
219
  this.queryIDs = async () => {
187
220
  const edges = await this.querySingleEdge("queryIDs");
@@ -209,7 +242,7 @@ class BaseEdgeQuery {
209
242
  };
210
243
  this.queryEnts = async () => {
211
244
  const edges = await this.querySingleEdge("queryEnts");
212
- return await this.loadEntsFromEdges("id", edges);
245
+ return this.loadEntsFromEdges("id", edges);
213
246
  };
214
247
  this.queryAllEnts = async () => {
215
248
  // applies filters and then gets things after
@@ -226,9 +259,48 @@ class BaseEdgeQuery {
226
259
  await Promise.all(promises);
227
260
  return results;
228
261
  };
262
+ let sortCol;
263
+ let cursorCol;
264
+ if (typeof sortColOrOptions === "string") {
265
+ sortCol = sortColOrOptions;
266
+ cursorCol = cursorColMaybe;
267
+ this.edgeQueryOptions = {
268
+ cursorCol,
269
+ orderby: [
270
+ {
271
+ column: sortCol,
272
+ direction: "DESC",
273
+ },
274
+ ],
275
+ };
276
+ }
277
+ else {
278
+ if (typeof sortColOrOptions.orderby === "string") {
279
+ sortCol = sortColOrOptions.orderby;
280
+ }
281
+ else {
282
+ // TODO this orderby isn't consistent and this logic needs to be changed anywhere that's using this and this.getSortCol()
283
+ sortCol = sortColOrOptions.orderby[0].column;
284
+ }
285
+ cursorCol = sortColOrOptions.cursorCol;
286
+ this.edgeQueryOptions = sortColOrOptions;
287
+ }
288
+ this.sortCol = sortCol;
289
+ let m = orderbyRegex.exec(sortCol);
290
+ if (!m) {
291
+ throw new Error(`invalid sort column ${sortCol}`);
292
+ }
293
+ this.sortCol = m[1];
294
+ if (m[2]) {
295
+ throw new Error(`passing direction in sort column is not supproted. use orderby`);
296
+ }
297
+ this.cursorCol = cursorCol;
229
298
  this.memoizedloadEdges = (0, memoizee_1.default)(this.loadEdges.bind(this));
230
299
  this.genIDInfosToFetch = (0, memoizee_1.default)(this.genIDInfosToFetchImpl.bind(this));
231
300
  }
301
+ getSortCol() {
302
+ return this.sortCol;
303
+ }
232
304
  getPrivacyPolicy() {
233
305
  // default PrivacyPolicy is always allow. nothing to do here
234
306
  return privacy_1.AlwaysAllowPrivacyPolicy;
@@ -239,6 +311,8 @@ class BaseEdgeQuery {
239
311
  limit: n,
240
312
  after,
241
313
  sortCol: this.sortCol,
314
+ cursorCol: this.cursorCol,
315
+ orderby: this.edgeQueryOptions.orderby,
242
316
  query: this,
243
317
  }));
244
318
  return this;
@@ -249,6 +323,8 @@ class BaseEdgeQuery {
249
323
  limit: n,
250
324
  before,
251
325
  sortCol: this.sortCol,
326
+ cursorCol: this.cursorCol,
327
+ orderby: this.edgeQueryOptions.orderby,
252
328
  query: this,
253
329
  }));
254
330
  return this;
@@ -290,21 +366,32 @@ class BaseEdgeQuery {
290
366
  await this.loadRawIDs(this.addID.bind(this));
291
367
  return applyPrivacyPolicyForEdgeQ(this.viewer, this, this.idsToFetch, this.idMap);
292
368
  }
369
+ // FYI: this should be used sparingly.
370
+ // currently only exists so that disableTransformations can be configured by the developer
371
+ // so we're only exposing a partial API for now but maybe in the future we can expose
372
+ // the full API if there's a reason to use this that's not via filters
373
+ configureEdgeQueryableDataOptions(opts) {
374
+ this._defaultEdgeQueryableOptions = opts;
375
+ }
376
+ getDefaultEdgeQueryOptions() {
377
+ return this._defaultEdgeQueryableOptions;
378
+ }
293
379
  async loadEdges() {
294
380
  const idsInfo = await this.genIDInfosToFetch();
295
381
  if (!this.filters.length) {
296
382
  // if no filter, we add the firstN filter to ensure we get pagination info
297
- this.first(ent_1.DefaultLimit);
383
+ this.first((0, ent_1.getDefaultLimit)());
298
384
  }
299
- let options = {};
385
+ let options = this._defaultEdgeQueryableOptions ?? {};
300
386
  // TODO once we add a lot of complex filters, this needs to be more complicated
301
387
  // e.g. commutative filters. what can be done in sql or combined together etc
302
388
  // may need to bring sql mode or something back
303
- this.filters.forEach((filter) => {
389
+ for (const filter of this.filters) {
304
390
  if (filter.query) {
305
- options = filter.query(options);
391
+ let res = filter.query(options);
392
+ options = (0, types_1.isPromise)(res) ? await res : res;
306
393
  }
307
- });
394
+ }
308
395
  await this.loadRawData(idsInfo, options);
309
396
  // no filters. nothing to do here.
310
397
  if (!this.filters.length) {
@@ -331,17 +418,7 @@ class BaseEdgeQuery {
331
418
  getCursor(row) {
332
419
  return (0, ent_1.getCursor)({
333
420
  row,
334
- col: this.sortCol,
335
- conv: (datum) => {
336
- if (datum instanceof Date) {
337
- return datum.getTime();
338
- }
339
- // sqlite stores it as string and doesn't convert back
340
- if (typeof datum === "string") {
341
- return Date.parse(datum);
342
- }
343
- return datum;
344
- },
421
+ col: this.cursorCol,
345
422
  });
346
423
  }
347
424
  }
@@ -1 +1,2 @@
1
- export declare function assocTests(): void;
1
+ import { MockLogs } from "../../testutils/mock_log";
2
+ export declare function assocTests(ml: MockLogs, global?: boolean): void;