@snowtop/ent 0.1.0-alpha1 → 0.1.0-alpha100

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