@snowtop/ent 0.1.0-alpha9 → 0.1.0-alpha91

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 (135) hide show
  1. package/action/action.d.ts +36 -31
  2. package/action/action.js +2 -6
  3. package/action/executor.d.ts +3 -3
  4. package/action/executor.js +2 -2
  5. package/action/experimental_action.d.ts +29 -22
  6. package/action/experimental_action.js +29 -6
  7. package/action/orchestrator.d.ts +38 -16
  8. package/action/orchestrator.js +223 -61
  9. package/action/privacy.d.ts +2 -2
  10. package/core/base.d.ts +45 -24
  11. package/core/base.js +7 -1
  12. package/core/clause.d.ts +83 -7
  13. package/core/clause.js +334 -63
  14. package/core/config.d.ts +8 -0
  15. package/core/config.js +5 -1
  16. package/core/context.d.ts +5 -3
  17. package/core/context.js +20 -2
  18. package/core/convert.d.ts +1 -1
  19. package/core/db.d.ts +2 -2
  20. package/core/db.js +6 -2
  21. package/core/ent.d.ts +79 -24
  22. package/core/ent.js +527 -176
  23. package/core/loaders/assoc_count_loader.d.ts +3 -2
  24. package/core/loaders/assoc_count_loader.js +14 -2
  25. package/core/loaders/assoc_edge_loader.d.ts +2 -2
  26. package/core/loaders/assoc_edge_loader.js +5 -1
  27. package/core/loaders/index.d.ts +1 -1
  28. package/core/loaders/index.js +1 -3
  29. package/core/loaders/index_loader.d.ts +2 -2
  30. package/core/loaders/loader.js +5 -5
  31. package/core/loaders/object_loader.d.ts +6 -5
  32. package/core/loaders/object_loader.js +67 -59
  33. package/core/loaders/query_loader.d.ts +6 -12
  34. package/core/loaders/query_loader.js +52 -11
  35. package/core/loaders/raw_count_loader.d.ts +2 -2
  36. package/core/loaders/raw_count_loader.js +5 -1
  37. package/core/logger.d.ts +1 -1
  38. package/core/logger.js +1 -0
  39. package/core/privacy.d.ts +26 -25
  40. package/core/privacy.js +21 -25
  41. package/core/query/assoc_query.d.ts +7 -6
  42. package/core/query/assoc_query.js +9 -1
  43. package/core/query/custom_clause_query.d.ts +26 -0
  44. package/core/query/custom_clause_query.js +78 -0
  45. package/core/query/custom_query.d.ts +20 -5
  46. package/core/query/custom_query.js +87 -12
  47. package/core/query/index.d.ts +1 -0
  48. package/core/query/index.js +3 -1
  49. package/core/query/query.d.ts +8 -4
  50. package/core/query/query.js +101 -53
  51. package/core/query/shared_assoc_test.d.ts +2 -1
  52. package/core/query/shared_assoc_test.js +34 -43
  53. package/core/query/shared_test.d.ts +8 -1
  54. package/core/query/shared_test.js +470 -236
  55. package/core/viewer.d.ts +3 -3
  56. package/core/viewer.js +1 -1
  57. package/graphql/graphql.js +16 -6
  58. package/graphql/query/edge_connection.d.ts +9 -9
  59. package/graphql/query/page_info.d.ts +1 -1
  60. package/graphql/query/shared_edge_connection.js +1 -15
  61. package/imports/index.js +5 -1
  62. package/index.d.ts +11 -5
  63. package/index.js +20 -7
  64. package/package.json +1 -1
  65. package/parse_schema/parse.d.ts +12 -3
  66. package/parse_schema/parse.js +70 -11
  67. package/schema/base_schema.js +3 -0
  68. package/schema/field.d.ts +44 -8
  69. package/schema/field.js +136 -10
  70. package/schema/index.d.ts +2 -2
  71. package/schema/index.js +5 -1
  72. package/schema/json_field.d.ts +13 -1
  73. package/schema/json_field.js +28 -1
  74. package/schema/schema.d.ts +66 -11
  75. package/schema/schema.js +18 -4
  76. package/schema/struct_field.d.ts +11 -1
  77. package/schema/struct_field.js +44 -5
  78. package/scripts/custom_compiler.js +10 -6
  79. package/scripts/custom_graphql.js +13 -4
  80. package/scripts/{transform_schema.d.ts → migrate_v0.1.d.ts} +0 -0
  81. package/scripts/migrate_v0.1.js +36 -0
  82. package/scripts/read_schema.js +20 -5
  83. package/testutils/builder.d.ts +31 -21
  84. package/testutils/builder.js +83 -29
  85. package/testutils/db/fixture.d.ts +10 -0
  86. package/testutils/db/fixture.js +26 -0
  87. package/testutils/db/{test_db.d.ts → temp_db.d.ts} +20 -7
  88. package/testutils/db/{test_db.js → temp_db.js} +102 -36
  89. package/testutils/db/value.d.ts +6 -0
  90. package/testutils/db/value.js +251 -0
  91. package/testutils/db_mock.js +3 -1
  92. package/testutils/db_time_zone.d.ts +4 -0
  93. package/testutils/db_time_zone.js +41 -0
  94. package/testutils/ent-graphql-tests/index.js +8 -1
  95. package/testutils/fake_data/const.d.ts +2 -1
  96. package/testutils/fake_data/const.js +3 -0
  97. package/testutils/fake_data/fake_contact.d.ts +7 -4
  98. package/testutils/fake_data/fake_contact.js +14 -6
  99. package/testutils/fake_data/fake_event.d.ts +5 -3
  100. package/testutils/fake_data/fake_event.js +8 -5
  101. package/testutils/fake_data/fake_tag.d.ts +35 -0
  102. package/testutils/fake_data/fake_tag.js +88 -0
  103. package/testutils/fake_data/fake_user.d.ts +6 -4
  104. package/testutils/fake_data/fake_user.js +16 -13
  105. package/testutils/fake_data/index.js +5 -1
  106. package/testutils/fake_data/internal.d.ts +2 -0
  107. package/testutils/fake_data/internal.js +7 -1
  108. package/testutils/fake_data/tag_query.d.ts +13 -0
  109. package/testutils/fake_data/tag_query.js +43 -0
  110. package/testutils/fake_data/test_helpers.d.ts +11 -4
  111. package/testutils/fake_data/test_helpers.js +28 -12
  112. package/testutils/fake_data/user_query.d.ts +13 -6
  113. package/testutils/fake_data/user_query.js +54 -22
  114. package/testutils/fake_log.d.ts +3 -3
  115. package/testutils/parse_sql.d.ts +6 -0
  116. package/testutils/parse_sql.js +16 -2
  117. package/testutils/test_edge_global_schema.d.ts +15 -0
  118. package/testutils/test_edge_global_schema.js +62 -0
  119. package/testutils/write.d.ts +2 -2
  120. package/testutils/write.js +33 -7
  121. package/tsc/ast.d.ts +44 -0
  122. package/tsc/ast.js +271 -0
  123. package/tsc/compilerOptions.d.ts +6 -0
  124. package/tsc/compilerOptions.js +45 -2
  125. package/tsc/move_generated.d.ts +1 -0
  126. package/tsc/move_generated.js +164 -0
  127. package/tsc/transform.d.ts +21 -0
  128. package/tsc/transform.js +171 -0
  129. package/tsc/transform_action.d.ts +22 -0
  130. package/tsc/transform_action.js +183 -0
  131. package/tsc/transform_ent.d.ts +17 -0
  132. package/tsc/transform_ent.js +59 -0
  133. package/tsc/transform_schema.d.ts +27 -0
  134. package/tsc/transform_schema.js +383 -0
  135. package/scripts/transform_schema.js +0 -445
@@ -1,190 +1,306 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.commonTests = void 0;
4
- const db_mock_1 = require("../../testutils/db_mock");
5
4
  const ent_1 = require("../ent");
6
5
  const viewer_1 = require("../viewer");
7
6
  const index_1 = require("../../testutils/fake_data/index");
8
7
  const test_helpers_1 = require("../../testutils/fake_data/test_helpers");
9
- const test_db_1 = require("../../testutils/db/test_db");
8
+ const temp_db_1 = require("../../testutils/db/temp_db");
10
9
  const test_context_1 = require("../../testutils/context/test_context");
11
10
  const logger_1 = require("../logger");
12
- class TestQueryFilter {
13
- constructor(filter, newQuery, ents, defaultViewer) {
14
- this.filter = filter;
15
- this.newQuery = newQuery;
16
- this.ents = ents;
17
- this.defaultViewer = defaultViewer;
18
- this.allContacts = [];
19
- this.filteredContacts = [];
11
+ const test_edge_global_schema_1 = require("../../testutils/test_edge_global_schema");
12
+ const builder_1 = require("../../testutils/builder");
13
+ const action_1 = require("../../action");
14
+ const clause_1 = require("../clause");
15
+ function getWhereClause(query) {
16
+ const idx = query.query.indexOf("WHERE");
17
+ if (idx !== -1) {
18
+ return query.query.substr(idx + 6);
20
19
  }
21
- async beforeEach() {
22
- // console.log("sss");
23
- [this.user, this.allContacts] = await (0, test_helpers_1.createAllContacts)();
24
- // console.log(this.user, this.contacts);
25
- // this.allContacts = this.allContacts.reverse();
26
- this.filteredContacts = this.ents(this.allContacts);
27
- db_mock_1.QueryRecorder.clearQueries();
28
- }
29
- getQuery(viewer) {
30
- return this.filter(this.newQuery(viewer || this.defaultViewer, this.user), this.user, this.allContacts);
31
- }
32
- async testIDs() {
33
- const ids = await this.getQuery().queryIDs();
34
- this.verifyIDs(ids);
35
- }
36
- verifyIDs(ids) {
37
- expect(ids).toEqual(this.filteredContacts.map((contact) => contact.id));
38
- }
39
- // rawCount isn't affected by filters...
40
- async testRawCount() {
41
- const count = await this.getQuery().queryRawCount();
42
- this.verifyRawCount(count);
43
- }
44
- verifyRawCount(count) {
45
- expect(count).toBe(test_helpers_1.inputs.length);
46
- }
47
- async testCount() {
48
- const count = await this.getQuery().queryCount();
49
- this.verifyCount(count);
50
- }
51
- verifyCount(count) {
52
- expect(count).toBe(this.filteredContacts.length);
53
- }
54
- async testEdges() {
55
- const edges = await this.getQuery().queryEdges();
56
- this.verifyEdges(edges);
57
- }
58
- verifyEdges(edges) {
59
- const q = this.getQuery();
20
+ return null;
21
+ }
22
+ const commonTests = (opts) => {
23
+ (0, logger_1.setLogLevels)(["query", "error"]);
24
+ const ml = opts.ml;
25
+ ml.mock();
26
+ function isCustomQuery(q) {
27
+ if (q.customQuery !== undefined) {
28
+ return q.customQuery;
29
+ }
60
30
  // TODO sad not generic enough
61
- if (q instanceof index_1.UserToContactsFkeyQuery) {
62
- (0, test_helpers_1.verifyUserToContactRawData)(this.user, edges, this.filteredContacts);
31
+ return (q instanceof index_1.UserToContactsFkeyQuery ||
32
+ q instanceof index_1.UserToContactsFkeyQueryDeprecated ||
33
+ q instanceof index_1.UserToContactsFkeyQueryAsc);
34
+ }
35
+ class TestQueryFilter {
36
+ constructor(filter, newQuery, ents, defaultViewer) {
37
+ this.filter = filter;
38
+ this.newQuery = newQuery;
39
+ this.ents = ents;
40
+ this.defaultViewer = defaultViewer;
41
+ this.allContacts = [];
42
+ this.filteredContacts = [];
43
+ // @ts-ignore
44
+ const q = this.newQuery(this.defaultViewer);
45
+ this.customQuery = isCustomQuery(q);
63
46
  }
64
- else {
65
- (0, test_helpers_1.verifyUserToContactEdges)(this.user, edges, this.filteredContacts);
47
+ async createData() {
48
+ [this.user, this.allContacts] = await (0, test_helpers_1.createAllContacts)();
49
+ // this.allContacts = this.allContacts.reverse();
50
+ this.filteredContacts = this.ents(this.allContacts);
51
+ ml.clear();
66
52
  }
67
- }
68
- async testEnts() {
69
- const entsMap = await this.getQuery(new viewer_1.IDViewer(this.user.id)).queryEnts();
70
- this.verifyEnts(entsMap);
71
- }
72
- verifyEnts(ents) {
73
- (0, test_helpers_1.verifyUserToContacts)(this.user, ents, this.filteredContacts);
74
- }
75
- async testAll() {
76
- const query = this.getQuery(new viewer_1.IDViewer(this.user.id));
77
- const [edges, count, ids, rawCount, ents] = await Promise.all([
78
- query.queryEdges(),
79
- query.queryCount(),
80
- query.queryIDs(),
81
- query.queryRawCount(),
82
- query.queryEnts(),
83
- ]);
84
- this.verifyCount(count);
85
- this.verifyEdges(edges);
86
- this.verifyIDs(ids);
87
- this.verifyRawCount(rawCount);
88
- this.verifyEnts(ents);
89
- }
90
- }
91
- const preparedVar = /(\$(\d))/g;
92
- const commonTests = (opts) => {
93
- function verifyQuery({ length = 1, numQueries = 1, limit = ent_1.DefaultLimit, disablePaginationBump = false, }) {
94
- if (opts.livePostgresDB || opts.sqlite) {
95
- return;
53
+ getQuery(viewer) {
54
+ return this.filter(this.newQuery(viewer || this.defaultViewer, this.user), this.user, this.allContacts);
55
+ }
56
+ async testIDs() {
57
+ const ids = await this.getQuery().queryIDs();
58
+ this.verifyIDs(ids);
59
+ }
60
+ verifyIDs(ids) {
61
+ expect(ids).toEqual(this.filteredContacts.map((contact) => contact.id));
96
62
  }
97
- const queries = db_mock_1.QueryRecorder.getCurrentQueries();
98
- expect(queries.length).toBe(length);
63
+ // rawCount isn't affected by filters...
64
+ async testRawCount(expectedCount) {
65
+ const count = await this.getQuery().queryRawCount();
66
+ this.verifyRawCount(count, expectedCount);
67
+ }
68
+ verifyRawCount(count, expectedCount) {
69
+ expect(count).toBe(expectedCount ?? test_helpers_1.inputs.length);
70
+ }
71
+ async testCount(expectedCount) {
72
+ const count = await this.getQuery().queryCount();
73
+ this.verifyCount(count, expectedCount);
74
+ }
75
+ verifyCount(count, expectedCount) {
76
+ expect(count).toBe(expectedCount ?? this.filteredContacts.length);
77
+ }
78
+ async testEdges() {
79
+ const edges = await this.getQuery().queryEdges();
80
+ this.verifyEdges(edges);
81
+ }
82
+ verifyEdges(edges) {
83
+ const q = this.getQuery();
84
+ // TODO sad not generic enough
85
+ if (this.customQuery) {
86
+ (0, test_helpers_1.verifyUserToContactRawData)(this.user, edges, this.filteredContacts);
87
+ }
88
+ else {
89
+ (0, test_helpers_1.verifyUserToContactEdges)(this.user, edges, this.filteredContacts);
90
+ }
91
+ }
92
+ async testEnts(v) {
93
+ const ents = await this.getQuery(v || new viewer_1.IDViewer(this.user.id)).queryEnts();
94
+ this.verifyEnts(ents);
95
+ return ents;
96
+ }
97
+ async testEntsCache() {
98
+ if (!this.customQuery) {
99
+ return;
100
+ }
101
+ (0, logger_1.setLogLevels)(["query", "cache"]);
102
+ const v = new test_context_1.TestContext(new viewer_1.IDViewer(this.user.id)).getViewer();
103
+ const ents = await this.testEnts(v);
104
+ expect(ml.logs.length).toBe(1);
105
+ expect(ml.logs[0].query).toMatch(/SELECT (.+) FROM /);
106
+ await Promise.all(ents.map((ent) => index_1.FakeContact.loadX(v, ent.id)));
107
+ expect(ml.logs.length).toBe(this.filteredContacts.length + 1);
108
+ for (const log of ml.logs.slice(1)) {
109
+ expect(log["ent-cache-hit"]).toBeDefined();
110
+ }
111
+ // "restore" back to previous
112
+ (0, logger_1.setLogLevels)("query");
113
+ }
114
+ async testDataCache() {
115
+ if (!this.customQuery) {
116
+ return;
117
+ }
118
+ (0, logger_1.setLogLevels)(["query", "cache"]);
119
+ const v = new test_context_1.TestContext(new viewer_1.IDViewer(this.user.id)).getViewer();
120
+ const ents = await this.testEnts(v);
121
+ expect(ml.logs.length).toBe(1);
122
+ expect(ml.logs[0].query).toMatch(/SELECT (.+) FROM /);
123
+ await Promise.all(ents.map((ent) => index_1.FakeContact.loadRawData(ent.id, v.context)));
124
+ expect(ml.logs.length).toBe(this.filteredContacts.length + 1);
125
+ for (const log of ml.logs.slice(1)) {
126
+ expect(log["dataloader-cache-hit"]).toBeDefined();
127
+ }
128
+ // "restore" back to previous
129
+ (0, logger_1.setLogLevels)("query");
130
+ }
131
+ verifyEnts(ents) {
132
+ (0, test_helpers_1.verifyUserToContacts)(this.user, ents, this.filteredContacts);
133
+ }
134
+ async testAll(expectedCount) {
135
+ const query = this.getQuery(new viewer_1.IDViewer(this.user.id));
136
+ const [edges, count, ids, rawCount, ents] = await Promise.all([
137
+ query.queryEdges(),
138
+ query.queryCount(),
139
+ query.queryIDs(),
140
+ query.queryRawCount(),
141
+ query.queryEnts(),
142
+ ]);
143
+ this.verifyCount(count, expectedCount);
144
+ this.verifyEdges(edges);
145
+ this.verifyIDs(ids);
146
+ this.verifyRawCount(rawCount, expectedCount);
147
+ this.verifyEnts(ents);
148
+ }
149
+ }
150
+ function verifyQuery(filter, { length = 1, numQueries = 1, limit = ent_1.DefaultLimit, disablePaginationBump = false, orderby = opts.orderby, }) {
151
+ const uniqCol = isCustomQuery(filter) ? "id" : "id2";
152
+ expect(ml.logs.length).toBe(length);
99
153
  for (let i = 0; i < numQueries; i++) {
100
- const query = queries[i];
154
+ const whereClause = getWhereClause(ml.logs[i]);
101
155
  let expLimit = disablePaginationBump ? limit : limit + 1;
102
- expect(query.qs?.whereClause, `${i}`).toBe(
156
+ expect(whereClause, `${i}`).toBe(
103
157
  // default limit
104
- `${opts.where} ORDER BY ${opts.sortCol} DESC LIMIT ${expLimit}`);
158
+ `${opts.clause.clause(1)} ORDER BY ${opts.sortCol} ${orderby}, ${uniqCol} ${orderby} LIMIT ${expLimit}`);
105
159
  }
106
160
  }
107
161
  function verifyCountQuery({ length = 1, numQueries = 1 }) {
108
- if (opts.livePostgresDB || opts.sqlite) {
109
- return;
110
- }
111
- const queries = db_mock_1.QueryRecorder.getCurrentQueries();
112
- expect(queries.length).toBe(length);
162
+ expect(ml.logs.length).toBe(length);
113
163
  for (let i = 0; i < numQueries; i++) {
114
- const query = queries[i];
115
- expect(query.qs?.whereClause).toBe(opts.where);
116
- expect(query.qs?.columns).toHaveLength(1);
117
- expect(query.qs?.columns).toStrictEqual(["count(1) as count"]);
164
+ const whereClause = getWhereClause(ml.logs[i]);
165
+ expect(whereClause).toBe(opts.clause.clause(1));
118
166
  }
119
167
  }
120
- function verifyFirstAfterCursorQuery(length = 1) {
121
- if (opts.livePostgresDB || opts.sqlite) {
122
- return;
168
+ function verifyFirstAfterCursorQuery(filter, length = 1, limit = 3) {
169
+ // cache showing up in a few because of cross runs...
170
+ expect(ml.logs.length).toBeGreaterThanOrEqual(length);
171
+ const uniqCol = isCustomQuery(filter) ? "id" : "id2";
172
+ let parts = opts.clause.clause(1).split(" AND ");
173
+ const cmp = (0, clause_1.PaginationMultipleColsSubQuery)(opts.sortCol, opts.orderby === "DESC" ? "<" : ">", opts.tableName, uniqCol, "").clause(opts.clause.values().length + 1);
174
+ if (parts[parts.length - 1] === "deleted_at IS NULL") {
175
+ parts = parts
176
+ .slice(0, parts.length - 1)
177
+ .concat([cmp, "deleted_at IS NULL"]);
178
+ }
179
+ else {
180
+ parts.push(cmp);
123
181
  }
124
- const queries = db_mock_1.QueryRecorder.getCurrentQueries();
125
- expect(queries.length).toBe(length);
126
- const query = queries[0];
127
- const result = [...opts.where.matchAll(preparedVar)];
128
- expect(query.qs?.whereClause).toBe(`${opts.where} AND ${opts.sortCol} < $${result.length + 1} ORDER BY ${opts.sortCol} DESC LIMIT 4`);
182
+ expect(getWhereClause(ml.logs[0])).toBe(`${parts.join(" AND ")} ORDER BY ${opts.sortCol} ${opts.orderby}, ${uniqCol} ${opts.orderby} LIMIT ${limit + 1}`);
129
183
  }
130
- function verifyLastBeforeCursorQuery(length = 1) {
131
- if (opts.livePostgresDB || opts.sqlite) {
132
- return;
184
+ function verifyLastBeforeCursorQuery(filter, length = 1, limit = 3) {
185
+ // cache showing up in a few because of cross runs...
186
+ expect(ml.logs.length).toBeGreaterThanOrEqual(length);
187
+ const uniqCol = isCustomQuery(filter) ? "id" : "id2";
188
+ let op = "";
189
+ let orderby = "";
190
+ if (opts.orderby === "DESC") {
191
+ op = ">";
192
+ orderby = "ASC";
193
+ }
194
+ else {
195
+ op = "<";
196
+ orderby = "DESC";
197
+ }
198
+ let parts = opts.clause.clause(1).split(" AND ");
199
+ const cmp = (0, clause_1.PaginationMultipleColsSubQuery)(opts.sortCol, op, opts.tableName, uniqCol, "").clause(opts.clause.values().length + 1);
200
+ if (parts[parts.length - 1] === "deleted_at IS NULL") {
201
+ parts = parts
202
+ .slice(0, parts.length - 1)
203
+ .concat([cmp, "deleted_at IS NULL"]);
204
+ }
205
+ else {
206
+ parts.push(cmp);
133
207
  }
134
- const queries = db_mock_1.QueryRecorder.getCurrentQueries();
135
- expect(queries.length).toBe(length);
136
- const query = queries[0];
137
- const result = [...opts.where.matchAll(preparedVar)];
138
- expect(query.qs?.whereClause).toBe(
208
+ expect(getWhereClause(ml.logs[0])).toBe(
139
209
  // extra fetched for pagination
140
- `${opts.where} AND ${opts.sortCol} > $${result.length + 1} ORDER BY ${opts.sortCol} ASC LIMIT 4`);
210
+ `${parts.join(" AND ")} ORDER BY ${opts.sortCol} ${orderby}, ${uniqCol} ${orderby} LIMIT ${limit + 1}`);
141
211
  }
142
212
  function getViewer() {
143
- // live db, let's do context because we're testing complicated paths
144
- // may be worth breaking this out later
145
- // opts.liveDB no context too...
146
- // maybe this one we just always hit the db
147
- // we don't get value out of testing parse_sql no context....
148
- if (opts.livePostgresDB || opts.sqlite) {
149
- return new test_context_1.TestContext().getViewer();
150
- }
151
- // no context when not live db
152
213
  return new viewer_1.LoggedOutViewer();
153
214
  }
154
215
  function getCursorFrom(contacts, idx) {
155
- // we depend on the fact that the same time is used for the edge and created_at
156
- // based on getContactBuilder
157
- // so regardless of if we're doing assoc or custom queries, we can get the time
158
- // from the created_at field
159
216
  return (0, ent_1.getCursor)({
160
217
  row: contacts[idx],
161
- col: "createdAt",
162
- conv: (t) => {
163
- //sqlite
164
- if (typeof t === "string") {
165
- return Date.parse(t);
166
- }
167
- return t.getTime();
168
- },
169
- // we want the right column to be encoded in the cursor as opposed e.g. time for
170
- // assoc queries, created_at for index/custom queries
171
- cursorKey: opts.sortCol,
218
+ col: "id",
172
219
  });
173
220
  }
221
+ function getVerifyAfterEachCursor(edges, pageLength, user) {
222
+ let query;
223
+ async function verify(i, hasEdge, hasNextPage, cursor) {
224
+ ml.clear();
225
+ query = opts.newQuery(getViewer(), user);
226
+ const newEdges = await query.first(pageLength, cursor).queryEdges();
227
+ const pagination = query.paginationInfo().get(user.id);
228
+ if (hasEdge) {
229
+ expect(newEdges[0], `${i}`).toStrictEqual(edges[i]);
230
+ expect(newEdges.length, `${i}`).toBe(edges.length - i >= pageLength ? pageLength : edges.length - i);
231
+ }
232
+ else {
233
+ expect(newEdges.length, `${i}`).toBe(0);
234
+ }
235
+ if (hasNextPage) {
236
+ expect(pagination?.hasNextPage, `${i}`).toBe(true);
237
+ expect(pagination?.hasPreviousPage, `${i}`).toBe(false);
238
+ }
239
+ else {
240
+ expect(pagination?.hasNextPage, `${i}`).toBe(undefined);
241
+ expect(pagination?.hasNextPage, `${i}`).toBe(undefined);
242
+ }
243
+ if (cursor) {
244
+ verifyFirstAfterCursorQuery(query, 1, pageLength);
245
+ }
246
+ else {
247
+ verifyQuery(query, { orderby: opts.orderby, limit: pageLength });
248
+ }
249
+ }
250
+ function getCursor(edge) {
251
+ return query.getCursor(edge);
252
+ }
253
+ return { verify, getCursor };
254
+ }
255
+ function getVerifyBeforeEachCursor(edges, pageLength, user) {
256
+ let query;
257
+ async function verify(i, hasEdge, hasPreviousPage, cursor) {
258
+ ml.clear();
259
+ query = opts.newQuery(getViewer(), user);
260
+ const newEdges = await query.last(pageLength, cursor).queryEdges();
261
+ const pagination = query.paginationInfo().get(user.id);
262
+ if (hasEdge) {
263
+ expect(newEdges.length, `${i}`).toBe(i >= pageLength ? pageLength : i + 1);
264
+ expect(newEdges[0], `${i}`).toStrictEqual(edges[i]);
265
+ }
266
+ else {
267
+ expect(newEdges.length, `${i}`).toBe(0);
268
+ }
269
+ if (hasPreviousPage) {
270
+ expect(pagination?.hasPreviousPage, `${i}`).toBe(true);
271
+ expect(pagination?.hasNextPage, `${i}`).toBe(false);
272
+ }
273
+ else {
274
+ expect(pagination?.hasPreviousPage, `${i}`).toBe(undefined);
275
+ expect(pagination?.hasNextPage, `${i}`).toBe(undefined);
276
+ }
277
+ if (cursor) {
278
+ verifyLastBeforeCursorQuery(query, 1, pageLength);
279
+ }
280
+ else {
281
+ verifyQuery(query, {
282
+ orderby: opts.orderby === "DESC" ? "ASC" : "DESC",
283
+ limit: pageLength,
284
+ });
285
+ }
286
+ }
287
+ function getCursor(edge) {
288
+ return query.getCursor(edge);
289
+ }
290
+ return { verify, getCursor };
291
+ }
292
+ if (opts.globalSchema) {
293
+ (0, ent_1.setGlobalSchema)(test_edge_global_schema_1.testEdgeGlobalSchema);
294
+ }
174
295
  let tdb;
175
296
  if (opts.sqlite) {
176
- // tableName just to make it unique
177
- (0, test_db_1.setupSqlite)(`sqlite:///shared_test+${opts.tableName}.db`, test_helpers_1.tempDBTables);
297
+ (0, temp_db_1.setupSqlite)(`sqlite:///shared_test+${opts.uniqKey}.db`, () => (0, test_helpers_1.tempDBTables)(opts.globalSchema), {
298
+ disableDeleteAfterEachTest: true,
299
+ });
178
300
  }
179
301
  beforeAll(async () => {
180
- // want error on by default in tests?
181
- (0, logger_1.setLogLevels)(["error", "warn", "info"]);
182
- if (opts.livePostgresDB) {
183
- tdb = await (0, test_helpers_1.setupTempDB)();
184
- }
185
- });
186
- beforeEach(async () => {
187
302
  if (opts.livePostgresDB) {
303
+ tdb = await (0, test_helpers_1.setupTempDB)(opts.globalSchema);
188
304
  return;
189
305
  }
190
306
  await (0, test_helpers_1.createEdges)();
@@ -196,19 +312,22 @@ const commonTests = (opts) => {
196
312
  });
197
313
  describe("simple queries", () => {
198
314
  const filter = new TestQueryFilter((q) => {
199
- // no filterzs
315
+ // no filters
200
316
  return q;
201
317
  }, opts.newQuery, (contacts) => {
202
318
  // nothing to do here
203
319
  // reverse because edges are most recent first
204
- return contacts.reverse();
320
+ if (opts.orderby === "DESC") {
321
+ return contacts.reverse();
322
+ }
323
+ return contacts;
205
324
  }, getViewer());
206
325
  beforeEach(async () => {
207
- await filter.beforeEach();
326
+ await filter.createData();
208
327
  });
209
328
  test("ids", async () => {
210
329
  await filter.testIDs();
211
- verifyQuery({});
330
+ verifyQuery(filter, {});
212
331
  });
213
332
  test("rawCount", async () => {
214
333
  await filter.testRawCount();
@@ -216,19 +335,80 @@ const commonTests = (opts) => {
216
335
  });
217
336
  test("count", async () => {
218
337
  await filter.testCount();
219
- verifyQuery({});
338
+ verifyQuery(filter, {});
220
339
  });
221
340
  test("edges", async () => {
222
341
  await filter.testEdges();
223
- verifyQuery({});
342
+ verifyQuery(filter, {});
224
343
  });
225
344
  test("ents", async () => {
226
345
  await filter.testEnts();
227
- verifyQuery({ length: opts.entsLength });
346
+ verifyQuery(filter, { length: opts.entsLength });
228
347
  });
229
348
  test("all", async () => {
230
349
  await filter.testAll();
231
350
  });
351
+ test("ents cache", async () => {
352
+ await filter.testEntsCache();
353
+ });
354
+ test("data cache", async () => {
355
+ await filter.testDataCache();
356
+ });
357
+ });
358
+ describe("after delete", () => {
359
+ const filter = new TestQueryFilter((q) => {
360
+ // no filters
361
+ return q;
362
+ }, opts.newQuery, (contacts) => {
363
+ // nothing expected since deleted
364
+ return [];
365
+ }, getViewer());
366
+ beforeEach(async () => {
367
+ await filter.createData();
368
+ const action = new builder_1.SimpleAction(filter.user.viewer, index_1.FakeUserSchema, new Map(), action_1.WriteOperation.Edit, filter.user);
369
+ await Promise.all(filter.allContacts.map(async (contact) => {
370
+ action.builder.orchestrator.removeOutboundEdge(contact.id, index_1.EdgeType.UserToContacts);
371
+ const action2 = new builder_1.SimpleAction(filter.user.viewer, index_1.FakeContactSchema, new Map(), action_1.WriteOperation.Delete, contact);
372
+ await action2.save();
373
+ }));
374
+ await action.save();
375
+ ml.clear();
376
+ });
377
+ test("ids", async () => {
378
+ await filter.testIDs();
379
+ verifyQuery(filter, {});
380
+ });
381
+ test("rawCount", async () => {
382
+ await filter.testRawCount(0);
383
+ verifyCountQuery({});
384
+ });
385
+ test("count", async () => {
386
+ await filter.testCount(0);
387
+ verifyQuery(filter, {});
388
+ });
389
+ test("edges", async () => {
390
+ await filter.testEdges();
391
+ verifyQuery(filter, {});
392
+ });
393
+ test("ents", async () => {
394
+ await filter.testEnts();
395
+ // no ents so no subsequent query. just the edge query
396
+ verifyQuery(filter, { length: 1 });
397
+ });
398
+ test("all", async () => {
399
+ await filter.testAll(0);
400
+ });
401
+ test("raw_data", async () => {
402
+ if (opts.rawDataVerify) {
403
+ await opts.rawDataVerify(filter.user);
404
+ }
405
+ });
406
+ test("ents cache", async () => {
407
+ await filter.testEntsCache();
408
+ });
409
+ test("data cache", async () => {
410
+ await filter.testDataCache();
411
+ });
232
412
  });
233
413
  describe("first. no cursor", () => {
234
414
  const N = 2;
@@ -236,14 +416,17 @@ const commonTests = (opts) => {
236
416
  // no filters
237
417
  return q.first(N);
238
418
  }, opts.newQuery, (contacts) => {
239
- return contacts.reverse().slice(0, N);
419
+ if (opts.orderby === "DESC") {
420
+ return contacts.reverse().slice(0, N);
421
+ }
422
+ return contacts.slice(0, N);
240
423
  }, getViewer());
241
424
  beforeEach(async () => {
242
- await filter.beforeEach();
425
+ await filter.createData();
243
426
  });
244
427
  test("ids", async () => {
245
428
  await filter.testIDs();
246
- verifyQuery({ limit: 2 });
429
+ verifyQuery(filter, { limit: 2 });
247
430
  });
248
431
  test("rawCount", async () => {
249
432
  await filter.testRawCount();
@@ -251,19 +434,25 @@ const commonTests = (opts) => {
251
434
  });
252
435
  test("count", async () => {
253
436
  await filter.testCount();
254
- verifyQuery({ limit: 2 });
437
+ verifyQuery(filter, { limit: 2 });
255
438
  });
256
439
  test("edges", async () => {
257
440
  await filter.testEdges();
258
- verifyQuery({ limit: 2 });
441
+ verifyQuery(filter, { limit: 2 });
259
442
  });
260
443
  test("ents", async () => {
261
444
  await filter.testEnts();
262
- verifyQuery({ limit: 2, length: opts.entsLength });
445
+ verifyQuery(filter, { limit: 2, length: opts.entsLength });
263
446
  });
264
447
  test("all", async () => {
265
448
  await filter.testAll();
266
449
  });
450
+ test("ents cache", async () => {
451
+ await filter.testEntsCache();
452
+ });
453
+ test("data cache", async () => {
454
+ await filter.testDataCache();
455
+ });
267
456
  });
268
457
  describe("last", () => {
269
458
  const N = 2;
@@ -271,15 +460,23 @@ const commonTests = (opts) => {
271
460
  // no filters
272
461
  return q.last(N);
273
462
  }, opts.newQuery, (contacts) => {
274
- // take the first N and then reverse it to get the last N in the right order
275
- return contacts.slice(0, N).reverse();
463
+ if (opts.orderby === "DESC") {
464
+ return contacts.slice(0, N);
465
+ }
466
+ else {
467
+ return contacts.reverse().slice(0, N);
468
+ }
276
469
  }, getViewer());
470
+ const orderby = opts.orderby === "ASC" ? "DESC" : "ASC";
277
471
  beforeEach(async () => {
278
- await filter.beforeEach();
472
+ await filter.createData();
279
473
  });
280
474
  test("ids", async () => {
281
475
  await filter.testIDs();
282
- verifyQuery({ disablePaginationBump: true });
476
+ verifyQuery(filter, {
477
+ orderby,
478
+ limit: N,
479
+ });
283
480
  });
284
481
  test("rawCount", async () => {
285
482
  await filter.testRawCount();
@@ -287,19 +484,29 @@ const commonTests = (opts) => {
287
484
  });
288
485
  test("count", async () => {
289
486
  await filter.testCount();
290
- verifyQuery({ disablePaginationBump: true });
487
+ verifyQuery(filter, { orderby, limit: N });
291
488
  });
292
489
  test("edges", async () => {
293
490
  await filter.testEdges();
294
- verifyQuery({ disablePaginationBump: true });
491
+ verifyQuery(filter, { orderby, limit: N });
295
492
  });
296
493
  test("ents", async () => {
297
494
  await filter.testEnts();
298
- verifyQuery({ disablePaginationBump: true, length: opts.entsLength });
495
+ verifyQuery(filter, {
496
+ orderby,
497
+ limit: N,
498
+ length: opts.entsLength,
499
+ });
299
500
  });
300
501
  test("all", async () => {
301
502
  await filter.testAll();
302
503
  });
504
+ test("ents cache", async () => {
505
+ await filter.testEntsCache();
506
+ });
507
+ test("data cache", async () => {
508
+ await filter.testDataCache();
509
+ });
303
510
  });
304
511
  describe("first after cursor", () => {
305
512
  const idx = 2;
@@ -307,15 +514,23 @@ const commonTests = (opts) => {
307
514
  const filter = new TestQueryFilter((q, user, contacts) => {
308
515
  return q.first(N, getCursorFrom(contacts, idx));
309
516
  }, opts.newQuery, (contacts) => {
310
- // < check so we shouldn't get that index
311
- return contacts.reverse().slice(idx + 1, idx + N);
517
+ if (opts.orderby === "DESC") {
518
+ // < check so we shouldn't get that index
519
+ return contacts.reverse().slice(idx + 1, idx + N);
520
+ }
521
+ else {
522
+ return contacts.slice(idx + 1, idx + N);
523
+ }
312
524
  }, getViewer());
313
- beforeEach(async () => {
314
- await filter.beforeEach();
525
+ beforeAll(async () => {
526
+ await filter.createData();
527
+ });
528
+ beforeEach(() => {
529
+ ml.clear();
315
530
  });
316
531
  test("ids", async () => {
317
532
  await filter.testIDs();
318
- verifyFirstAfterCursorQuery();
533
+ verifyFirstAfterCursorQuery(filter);
319
534
  });
320
535
  test("rawCount", async () => {
321
536
  await filter.testRawCount();
@@ -323,51 +538,36 @@ const commonTests = (opts) => {
323
538
  });
324
539
  test("count", async () => {
325
540
  await filter.testCount();
326
- verifyFirstAfterCursorQuery();
541
+ verifyFirstAfterCursorQuery(filter);
327
542
  });
328
543
  test("edges", async () => {
329
544
  await filter.testEdges();
330
- verifyFirstAfterCursorQuery();
545
+ verifyFirstAfterCursorQuery(filter);
331
546
  });
332
547
  test("ents", async () => {
333
548
  await filter.testEnts();
334
- verifyFirstAfterCursorQuery(opts.entsLength);
549
+ verifyFirstAfterCursorQuery(filter, opts.entsLength);
335
550
  });
336
551
  test("all", async () => {
337
552
  await filter.testAll();
338
553
  });
554
+ test("ents cache", async () => {
555
+ await filter.testEntsCache();
556
+ });
557
+ test("data cache", async () => {
558
+ await filter.testDataCache();
559
+ });
339
560
  });
340
561
  test("first. after each cursor", async () => {
341
- let [user, contacts] = await (0, test_helpers_1.createAllContacts)();
342
- contacts = contacts.reverse();
562
+ let [user] = await (0, test_helpers_1.createAllContacts)();
343
563
  const edges = await opts.newQuery(getViewer(), user).queryEdges();
344
- let query;
345
- async function verify(i, hasEdge, hasNextPage, cursor) {
346
- query = opts.newQuery(getViewer(), user);
347
- const newEdges = await query.first(1, cursor).queryEdges();
348
- const pagination = query.paginationInfo().get(user.id);
349
- if (hasEdge) {
350
- expect(newEdges.length, `${i}`).toBe(1);
351
- expect(newEdges[0], `${i}`).toStrictEqual(edges[i]);
352
- }
353
- else {
354
- expect(newEdges.length, `${i}`).toBe(0);
355
- }
356
- if (hasNextPage) {
357
- expect(pagination?.hasNextPage).toBe(true);
358
- expect(pagination?.hasPreviousPage).toBe(false);
359
- }
360
- else {
361
- expect(pagination?.hasNextPage).toBe(undefined);
362
- expect(pagination?.hasNextPage).toBe(undefined);
363
- }
364
- }
564
+ const { verify, getCursor } = getVerifyAfterEachCursor(edges, 1, user);
365
565
  await verify(0, true, true, undefined);
366
- await verify(1, true, true, query.getCursor(edges[0]));
367
- await verify(2, true, true, query.getCursor(edges[1]));
368
- await verify(3, true, true, query.getCursor(edges[2]));
369
- await verify(4, true, false, query.getCursor(edges[3]));
370
- await verify(5, false, false, query.getCursor(edges[4]));
566
+ await verify(1, true, true, getCursor(edges[0]));
567
+ await verify(2, true, true, getCursor(edges[1]));
568
+ await verify(3, true, true, getCursor(edges[2]));
569
+ await verify(4, true, false, getCursor(edges[3]));
570
+ await verify(5, false, false, getCursor(edges[4]));
371
571
  });
372
572
  describe("last. before cursor", () => {
373
573
  const idx = 2;
@@ -376,14 +576,22 @@ const commonTests = (opts) => {
376
576
  return q.last(N, getCursorFrom(contacts, idx));
377
577
  }, opts.newQuery, (contacts) => {
378
578
  // > check so we don't want that index
379
- return contacts.reverse().slice(0, idx).reverse(); // because of order returned
579
+ if (opts.orderby === "DESC") {
580
+ return contacts.reverse().slice(0, idx).reverse(); // because of order returned
581
+ }
582
+ return contacts.slice(0, idx).reverse(); // because of order returned
380
583
  }, getViewer());
584
+ beforeAll(async () => {
585
+ if (opts.livePostgresDB || opts.sqlite) {
586
+ await filter.createData();
587
+ }
588
+ });
381
589
  beforeEach(async () => {
382
- await filter.beforeEach();
590
+ ml.clear();
383
591
  });
384
592
  test("ids", async () => {
385
593
  await filter.testIDs();
386
- verifyLastBeforeCursorQuery();
594
+ verifyLastBeforeCursorQuery(filter);
387
595
  });
388
596
  test("rawCount", async () => {
389
597
  await filter.testRawCount();
@@ -391,51 +599,77 @@ const commonTests = (opts) => {
391
599
  });
392
600
  test("count", async () => {
393
601
  await filter.testCount();
394
- verifyLastBeforeCursorQuery();
602
+ verifyLastBeforeCursorQuery(filter);
395
603
  });
396
604
  test("edges", async () => {
397
605
  await filter.testEdges();
398
- verifyLastBeforeCursorQuery();
606
+ verifyLastBeforeCursorQuery(filter);
399
607
  });
400
608
  test("ents", async () => {
401
609
  await filter.testEnts();
402
- verifyLastBeforeCursorQuery(opts.entsLength);
610
+ verifyLastBeforeCursorQuery(filter, opts.entsLength);
403
611
  });
404
612
  test("all", async () => {
405
613
  await filter.testAll();
406
614
  });
615
+ test("ents cache", async () => {
616
+ await filter.testEntsCache();
617
+ });
618
+ test("data cache", async () => {
619
+ await filter.testDataCache();
620
+ });
407
621
  });
408
622
  test("last. before each cursor", async () => {
409
- let [user, contacts] = await (0, test_helpers_1.createAllContacts)();
410
- contacts = contacts.reverse();
623
+ let [user] = await (0, test_helpers_1.createAllContacts)();
411
624
  const edges = await opts.newQuery(getViewer(), user).queryEdges();
412
- let query;
413
- async function verify(i, hasEdge, hasPreviousPage, cursor) {
414
- query = opts.newQuery(getViewer(), user);
415
- const newEdges = await query.last(1, cursor).queryEdges();
416
- const pagination = query.paginationInfo().get(user.id);
417
- if (hasEdge) {
418
- expect(newEdges.length, `${i}`).toBe(1);
419
- expect(newEdges[0], `${i}`).toStrictEqual(edges[i]);
420
- }
421
- else {
422
- expect(newEdges.length, `${i}`).toBe(0);
423
- }
424
- if (hasPreviousPage) {
425
- expect(pagination?.hasPreviousPage).toBe(true);
426
- expect(pagination?.hasNextPage).toBe(false);
427
- }
428
- else {
429
- expect(pagination?.hasPreviousPage).toBe(undefined);
430
- expect(pagination?.hasNextPage).toBe(undefined);
431
- }
432
- }
625
+ const { verify, getCursor } = getVerifyBeforeEachCursor(edges, 1, user);
433
626
  await verify(4, true, true, undefined);
434
- await verify(3, true, true, query.getCursor(edges[4]));
435
- await verify(2, true, true, query.getCursor(edges[3]));
436
- await verify(1, true, true, query.getCursor(edges[2]));
437
- await verify(0, true, false, query.getCursor(edges[1]));
438
- await verify(-1, false, false, query.getCursor(edges[0]));
627
+ await verify(3, true, true, getCursor(edges[4]));
628
+ await verify(2, true, true, getCursor(edges[3]));
629
+ await verify(1, true, true, getCursor(edges[2]));
630
+ await verify(0, true, false, getCursor(edges[1]));
631
+ await verify(-1, false, false, getCursor(edges[0]));
632
+ });
633
+ describe("with conflicts", () => {
634
+ let user;
635
+ let allEdges = [];
636
+ beforeEach(async () => {
637
+ const [u, contacts] = await (0, test_helpers_1.createAllContacts)();
638
+ user = u;
639
+ const [_, contacts2] = await (0, test_helpers_1.createAllContacts)({
640
+ user,
641
+ start: contacts[contacts.length - 1].createdAt.getTime() - 100,
642
+ });
643
+ await (0, test_helpers_1.createAllContacts)({
644
+ user,
645
+ start: contacts2[contacts.length - 1].createdAt.getTime() - 100,
646
+ });
647
+ const edges = await opts.newQuery(getViewer(), user).queryEdges();
648
+ // confirm there are duplicates...
649
+ expect(edges[4].created_at).toStrictEqual(edges[5].created_at);
650
+ expect(edges[9].created_at).toStrictEqual(edges[10].created_at);
651
+ allEdges = edges;
652
+ });
653
+ test("first after each cursor", async () => {
654
+ const { verify, getCursor } = getVerifyAfterEachCursor(allEdges, 5, user);
655
+ // regular pagination
656
+ await verify(0, true, true, undefined);
657
+ await verify(5, true, true, getCursor(allEdges[4]));
658
+ await verify(10, true, false, getCursor(allEdges[9]));
659
+ await verify(15, false, false, getCursor(allEdges[14]));
660
+ // one without duplicates work if we were paginating at a different place...
661
+ await verify(6, true, true, getCursor(allEdges[5]));
662
+ await verify(11, true, false, getCursor(allEdges[10]));
663
+ });
664
+ test("last before each cursor", async () => {
665
+ const { verify, getCursor } = getVerifyBeforeEachCursor(allEdges, 5, user);
666
+ await verify(14, true, true, undefined);
667
+ await verify(13, true, true, getCursor(allEdges[14]));
668
+ await verify(8, true, true, getCursor(allEdges[9]));
669
+ await verify(9, true, true, getCursor(allEdges[10]));
670
+ await verify(3, true, false, getCursor(allEdges[4]));
671
+ await verify(4, true, false, getCursor(allEdges[5]));
672
+ });
439
673
  });
440
674
  };
441
675
  exports.commonTests = commonTests;