@convex-dev/better-auth 0.10.13 → 0.11.0

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 (185) hide show
  1. package/dist/auth-options.d.ts.map +1 -1
  2. package/dist/auth-options.js +0 -2
  3. package/dist/auth-options.js.map +1 -1
  4. package/dist/client/adapter-utils.d.ts +10 -10
  5. package/dist/client/adapter-utils.d.ts.map +1 -1
  6. package/dist/client/adapter-utils.js +41 -32
  7. package/dist/client/adapter-utils.js.map +1 -1
  8. package/dist/client/adapter.d.ts +1 -1
  9. package/dist/client/adapter.d.ts.map +1 -1
  10. package/dist/client/adapter.js +113 -7
  11. package/dist/client/adapter.js.map +1 -1
  12. package/dist/client/create-api.d.ts +8 -7
  13. package/dist/client/create-api.d.ts.map +1 -1
  14. package/dist/client/create-api.js +1 -0
  15. package/dist/client/create-api.js.map +1 -1
  16. package/dist/client/create-client.d.ts +1 -1
  17. package/dist/client/create-client.d.ts.map +1 -1
  18. package/dist/client/create-client.js +8 -7
  19. package/dist/client/create-client.js.map +1 -1
  20. package/dist/client/create-schema.d.ts +0 -1
  21. package/dist/client/create-schema.d.ts.map +1 -1
  22. package/dist/client/create-schema.js +0 -1
  23. package/dist/client/create-schema.js.map +1 -1
  24. package/dist/component/_generated/api.d.ts +12 -0
  25. package/dist/component/_generated/api.d.ts.map +1 -1
  26. package/dist/component/_generated/api.js.map +1 -1
  27. package/dist/component/_generated/component.d.ts +7407 -92
  28. package/dist/component/_generated/component.d.ts.map +1 -1
  29. package/dist/component/adapter.d.ts +8 -7
  30. package/dist/component/adapter.d.ts.map +1 -1
  31. package/dist/component/adapterTest.d.ts +1 -7
  32. package/dist/component/adapterTest.d.ts.map +1 -1
  33. package/dist/component/adapterTest.js +193 -390
  34. package/dist/component/adapterTest.js.map +1 -1
  35. package/dist/component/schema.d.ts +35 -74
  36. package/dist/component/schema.d.ts.map +1 -1
  37. package/dist/component/schema.js +16 -21
  38. package/dist/component/schema.js.map +1 -1
  39. package/dist/component/testProfiles/adapterAdditionalFields.d.ts +131 -0
  40. package/dist/component/testProfiles/adapterAdditionalFields.d.ts.map +1 -0
  41. package/dist/component/testProfiles/adapterAdditionalFields.js +5 -0
  42. package/dist/component/testProfiles/adapterAdditionalFields.js.map +1 -0
  43. package/dist/component/testProfiles/adapterOrganizationJoins.d.ts +131 -0
  44. package/dist/component/testProfiles/adapterOrganizationJoins.d.ts.map +1 -0
  45. package/dist/component/testProfiles/adapterOrganizationJoins.js +5 -0
  46. package/dist/component/testProfiles/adapterOrganizationJoins.js.map +1 -0
  47. package/dist/component/testProfiles/adapterPluginTable.d.ts +131 -0
  48. package/dist/component/testProfiles/adapterPluginTable.d.ts.map +1 -0
  49. package/dist/component/testProfiles/adapterPluginTable.js +5 -0
  50. package/dist/component/testProfiles/adapterPluginTable.js.map +1 -0
  51. package/dist/component/testProfiles/adapterRenameField.d.ts +131 -0
  52. package/dist/component/testProfiles/adapterRenameField.d.ts.map +1 -0
  53. package/dist/component/testProfiles/adapterRenameField.js +5 -0
  54. package/dist/component/testProfiles/adapterRenameField.js.map +1 -0
  55. package/dist/component/testProfiles/adapterRenameUserCustom.d.ts +131 -0
  56. package/dist/component/testProfiles/adapterRenameUserCustom.d.ts.map +1 -0
  57. package/dist/component/testProfiles/adapterRenameUserCustom.js +5 -0
  58. package/dist/component/testProfiles/adapterRenameUserCustom.js.map +1 -0
  59. package/dist/component/testProfiles/adapterRenameUserTable.d.ts +131 -0
  60. package/dist/component/testProfiles/adapterRenameUserTable.d.ts.map +1 -0
  61. package/dist/component/testProfiles/adapterRenameUserTable.js +5 -0
  62. package/dist/component/testProfiles/adapterRenameUserTable.js.map +1 -0
  63. package/dist/component/testProfiles/auth-options.profile-additional-fields.d.ts +3 -0
  64. package/dist/component/testProfiles/auth-options.profile-additional-fields.d.ts.map +1 -0
  65. package/dist/component/testProfiles/auth-options.profile-additional-fields.js +38 -0
  66. package/dist/component/testProfiles/auth-options.profile-additional-fields.js.map +1 -0
  67. package/dist/component/testProfiles/auth-options.profile-plugin-table.d.ts +3 -0
  68. package/dist/component/testProfiles/auth-options.profile-plugin-table.d.ts.map +1 -0
  69. package/dist/component/testProfiles/auth-options.profile-plugin-table.js +92 -0
  70. package/dist/component/testProfiles/auth-options.profile-plugin-table.js.map +1 -0
  71. package/dist/component/testProfiles/auth-options.profile-rename-joins.d.ts +6 -0
  72. package/dist/component/testProfiles/auth-options.profile-rename-joins.d.ts.map +1 -0
  73. package/dist/component/testProfiles/auth-options.profile-rename-joins.js +49 -0
  74. package/dist/component/testProfiles/auth-options.profile-rename-joins.js.map +1 -0
  75. package/dist/component/testProfiles/schema.profile-additional-fields.d.ts +227 -0
  76. package/dist/component/testProfiles/schema.profile-additional-fields.d.ts.map +1 -0
  77. package/dist/component/testProfiles/schema.profile-additional-fields.js +37 -0
  78. package/dist/component/testProfiles/schema.profile-additional-fields.js.map +1 -0
  79. package/dist/component/testProfiles/schema.profile-plugin-table.d.ts +450 -0
  80. package/dist/component/testProfiles/schema.profile-plugin-table.d.ts.map +1 -0
  81. package/dist/component/testProfiles/schema.profile-plugin-table.js +116 -0
  82. package/dist/component/testProfiles/schema.profile-plugin-table.js.map +1 -0
  83. package/dist/nextjs/index.d.ts.map +1 -1
  84. package/dist/nextjs/index.js +1 -0
  85. package/dist/nextjs/index.js.map +1 -1
  86. package/dist/plugins/convex/index.d.ts +131 -12
  87. package/dist/plugins/convex/index.d.ts.map +1 -1
  88. package/dist/plugins/convex/index.js +12 -5
  89. package/dist/plugins/convex/index.js.map +1 -1
  90. package/dist/plugins/cross-domain/client.d.ts +1 -1
  91. package/dist/plugins/cross-domain/index.d.ts +126 -1
  92. package/dist/plugins/cross-domain/index.d.ts.map +1 -1
  93. package/dist/plugins/cross-domain/index.js +10 -15
  94. package/dist/plugins/cross-domain/index.js.map +1 -1
  95. package/dist/react-start/index.d.ts.map +1 -1
  96. package/dist/react-start/index.js +1 -0
  97. package/dist/react-start/index.js.map +1 -1
  98. package/dist/test/adapter-factory/auth-flow.d.ts +42 -0
  99. package/dist/test/adapter-factory/auth-flow.d.ts.map +1 -0
  100. package/dist/test/adapter-factory/auth-flow.js +145 -0
  101. package/dist/test/adapter-factory/auth-flow.js.map +1 -0
  102. package/dist/test/adapter-factory/basic.d.ts +190 -0
  103. package/dist/test/adapter-factory/basic.d.ts.map +1 -0
  104. package/dist/test/adapter-factory/basic.js +2713 -0
  105. package/dist/test/adapter-factory/basic.js.map +1 -0
  106. package/dist/test/adapter-factory/convex-custom.d.ts +18 -0
  107. package/dist/test/adapter-factory/convex-custom.d.ts.map +1 -0
  108. package/dist/test/adapter-factory/convex-custom.js +610 -0
  109. package/dist/test/adapter-factory/convex-custom.js.map +1 -0
  110. package/dist/test/adapter-factory/index.d.ts +11 -0
  111. package/dist/test/adapter-factory/index.d.ts.map +1 -0
  112. package/dist/test/adapter-factory/index.js +11 -0
  113. package/dist/test/adapter-factory/index.js.map +1 -0
  114. package/dist/test/adapter-factory/joins.d.ts +18 -0
  115. package/dist/test/adapter-factory/joins.d.ts.map +1 -0
  116. package/dist/test/adapter-factory/joins.js +22 -0
  117. package/dist/test/adapter-factory/joins.js.map +1 -0
  118. package/dist/test/adapter-factory/number-id.d.ts +18 -0
  119. package/dist/test/adapter-factory/number-id.d.ts.map +1 -0
  120. package/dist/test/adapter-factory/number-id.js +36 -0
  121. package/dist/test/adapter-factory/number-id.js.map +1 -0
  122. package/dist/test/adapter-factory/profile-additional-fields.d.ts +71 -0
  123. package/dist/test/adapter-factory/profile-additional-fields.d.ts.map +1 -0
  124. package/dist/test/adapter-factory/profile-additional-fields.js +44 -0
  125. package/dist/test/adapter-factory/profile-additional-fields.js.map +1 -0
  126. package/dist/test/adapter-factory/profile-plugin-table.d.ts +19 -0
  127. package/dist/test/adapter-factory/profile-plugin-table.d.ts.map +1 -0
  128. package/dist/test/adapter-factory/profile-plugin-table.js +25 -0
  129. package/dist/test/adapter-factory/profile-plugin-table.js.map +1 -0
  130. package/dist/test/adapter-factory/profile-rename-joins.d.ts +73 -0
  131. package/dist/test/adapter-factory/profile-rename-joins.d.ts.map +1 -0
  132. package/dist/test/adapter-factory/profile-rename-joins.js +34 -0
  133. package/dist/test/adapter-factory/profile-rename-joins.js.map +1 -0
  134. package/dist/test/adapter-factory/transactions.d.ts +21 -0
  135. package/dist/test/adapter-factory/transactions.d.ts.map +1 -0
  136. package/dist/test/adapter-factory/transactions.js +28 -0
  137. package/dist/test/adapter-factory/transactions.js.map +1 -0
  138. package/dist/test/adapter-factory/uuid.d.ts +18 -0
  139. package/dist/test/adapter-factory/uuid.d.ts.map +1 -0
  140. package/dist/test/adapter-factory/uuid.js +58 -0
  141. package/dist/test/adapter-factory/uuid.js.map +1 -0
  142. package/dist/utils/index.d.ts +18 -3
  143. package/dist/utils/index.d.ts.map +1 -1
  144. package/dist/utils/index.js.map +1 -1
  145. package/package.json +8 -4
  146. package/src/auth-options.ts +0 -2
  147. package/src/client/adapter-utils.ts +80 -73
  148. package/src/client/adapter.test.ts +2 -74
  149. package/src/client/adapter.ts +142 -7
  150. package/src/client/create-api.ts +1 -0
  151. package/src/client/create-client.ts +14 -6
  152. package/src/client/create-schema.ts +0 -1
  153. package/src/component/_generated/api.ts +12 -0
  154. package/src/component/_generated/component.ts +19454 -215
  155. package/src/component/adapterTest.ts +250 -466
  156. package/src/component/schema.ts +21 -26
  157. package/src/component/testProfiles/adapterAdditionalFields.ts +13 -0
  158. package/src/component/testProfiles/adapterOrganizationJoins.ts +13 -0
  159. package/src/component/testProfiles/adapterPluginTable.ts +13 -0
  160. package/src/component/testProfiles/adapterRenameField.ts +13 -0
  161. package/src/component/testProfiles/adapterRenameUserCustom.ts +13 -0
  162. package/src/component/testProfiles/adapterRenameUserTable.ts +13 -0
  163. package/src/component/testProfiles/auth-options.profile-additional-fields.ts +39 -0
  164. package/src/component/testProfiles/auth-options.profile-plugin-table.ts +93 -0
  165. package/src/component/testProfiles/auth-options.profile-rename-joins.ts +54 -0
  166. package/src/component/testProfiles/schema.profile-additional-fields.ts +39 -0
  167. package/src/component/testProfiles/schema.profile-plugin-table.ts +130 -0
  168. package/src/nextjs/index.ts +1 -0
  169. package/src/plugins/convex/index.test.ts +55 -0
  170. package/src/plugins/convex/index.ts +26 -11
  171. package/src/plugins/cross-domain/index.test.ts +67 -0
  172. package/src/plugins/cross-domain/index.ts +10 -21
  173. package/src/react-start/index.ts +1 -0
  174. package/src/test/adapter-factory/auth-flow.ts +170 -0
  175. package/src/test/adapter-factory/basic.ts +3190 -0
  176. package/src/test/adapter-factory/convex-custom.ts +706 -0
  177. package/src/test/adapter-factory/index.ts +10 -0
  178. package/src/test/adapter-factory/joins.ts +28 -0
  179. package/src/test/adapter-factory/number-id.ts +45 -0
  180. package/src/test/adapter-factory/profile-additional-fields.ts +84 -0
  181. package/src/test/adapter-factory/profile-plugin-table.ts +37 -0
  182. package/src/test/adapter-factory/profile-rename-joins.ts +67 -0
  183. package/src/test/adapter-factory/transactions.ts +38 -0
  184. package/src/test/adapter-factory/uuid.ts +67 -0
  185. package/src/utils/index.ts +25 -3
@@ -0,0 +1,706 @@
1
+ import { createTestSuite } from "@better-auth/test-utils/adapter";
2
+ import { expect } from "vitest";
3
+
4
+ export const convexCustomTestSuite = createTestSuite(
5
+ "convex-custom",
6
+ {},
7
+ ({ adapter }) => ({
8
+ "should handle lone range operators": async () => {
9
+ const user = await adapter.create({
10
+ model: "user",
11
+ data: {
12
+ name: "ab",
13
+ email: "a@a.com",
14
+ },
15
+ });
16
+ expect(
17
+ await adapter.findMany({
18
+ model: "user",
19
+ where: [
20
+ {
21
+ field: "name",
22
+ operator: "lt",
23
+ value: "a",
24
+ },
25
+ ],
26
+ }),
27
+ ).toEqual([]);
28
+ expect(
29
+ await adapter.findMany({
30
+ model: "user",
31
+ where: [
32
+ {
33
+ field: "name",
34
+ operator: "lte",
35
+ value: "a",
36
+ },
37
+ ],
38
+ }),
39
+ ).toEqual([]);
40
+ expect(
41
+ await adapter.findMany({
42
+ model: "user",
43
+ where: [
44
+ {
45
+ field: "name",
46
+ operator: "gt",
47
+ value: "a",
48
+ },
49
+ ],
50
+ }),
51
+ ).toEqual([user]);
52
+ expect(
53
+ await adapter.findMany({
54
+ model: "user",
55
+ where: [
56
+ {
57
+ field: "name",
58
+ operator: "gte",
59
+ value: "ab",
60
+ },
61
+ ],
62
+ }),
63
+ ).toEqual([user]);
64
+ },
65
+
66
+ "should handle compound indexes that include id field": async () => {
67
+ const user = await adapter.create({
68
+ model: "user",
69
+ data: {
70
+ name: "foo",
71
+ email: "foo@bar.com",
72
+ },
73
+ });
74
+ expect(
75
+ await adapter.findOne({
76
+ model: "user",
77
+ where: [
78
+ {
79
+ field: "id",
80
+ value: user.id,
81
+ },
82
+ {
83
+ field: "name",
84
+ value: "wrong name",
85
+ },
86
+ ],
87
+ }),
88
+ ).toEqual(null);
89
+ expect(
90
+ await adapter.findOne({
91
+ model: "user",
92
+ where: [
93
+ {
94
+ field: "id",
95
+ value: user.id,
96
+ },
97
+ {
98
+ field: "name",
99
+ value: "foo",
100
+ },
101
+ ],
102
+ }),
103
+ ).toEqual(user);
104
+ expect(
105
+ await adapter.findOne({
106
+ model: "user",
107
+ where: [
108
+ {
109
+ field: "id",
110
+ value: user.id,
111
+ },
112
+ {
113
+ field: "name",
114
+ value: "foo",
115
+ operator: "lt",
116
+ },
117
+ ],
118
+ }),
119
+ ).toEqual(null);
120
+ expect(
121
+ await adapter.findOne({
122
+ model: "user",
123
+ where: [
124
+ {
125
+ field: "id",
126
+ value: user.id,
127
+ },
128
+ {
129
+ field: "name",
130
+ value: "foo",
131
+ operator: "lte",
132
+ },
133
+ ],
134
+ }),
135
+ ).toEqual(user);
136
+ expect(
137
+ await adapter.findOne({
138
+ model: "user",
139
+ where: [
140
+ {
141
+ field: "id",
142
+ value: user.id,
143
+ },
144
+ {
145
+ field: "name",
146
+ value: "foo",
147
+ operator: "gt",
148
+ },
149
+ ],
150
+ }),
151
+ ).toEqual(null);
152
+ expect(
153
+ await adapter.findOne({
154
+ model: "user",
155
+ where: [
156
+ {
157
+ field: "id",
158
+ value: user.id,
159
+ },
160
+ {
161
+ field: "name",
162
+ value: "foo",
163
+ operator: "gte",
164
+ },
165
+ ],
166
+ }),
167
+ ).toEqual(user);
168
+ expect(
169
+ await adapter.findOne({
170
+ model: "user",
171
+ where: [
172
+ {
173
+ field: "id",
174
+ value: user.id,
175
+ },
176
+ {
177
+ field: "name",
178
+ operator: "in",
179
+ value: ["wrong", "name"],
180
+ },
181
+ ],
182
+ }),
183
+ ).toEqual(null);
184
+ expect(
185
+ await adapter.findOne({
186
+ model: "user",
187
+ where: [
188
+ {
189
+ field: "id",
190
+ value: user.id,
191
+ },
192
+ {
193
+ field: "name",
194
+ operator: "in",
195
+ value: ["foo"],
196
+ },
197
+ ],
198
+ }),
199
+ ).toEqual(user);
200
+ },
201
+
202
+ "should automatically paginate": async () => {
203
+ for (let i = 0; i < 300; i++) {
204
+ await adapter.create({
205
+ model: "user",
206
+ data: {
207
+ name: `foo${i}`,
208
+ email: `foo${i}@bar.com`,
209
+ },
210
+ });
211
+ }
212
+ // Better Auth defaults to a limit of 100
213
+ expect(
214
+ await adapter.findMany({
215
+ model: "user",
216
+ }),
217
+ ).toHaveLength(100);
218
+
219
+ // Pagination has a hardcoded numItems max of 200, this tests that it can handle
220
+ // specified limits beyond that
221
+ expect(
222
+ await adapter.findMany({
223
+ model: "user",
224
+ limit: 250,
225
+ }),
226
+ ).toHaveLength(250);
227
+ expect(
228
+ await adapter.findMany({
229
+ model: "user",
230
+ limit: 350,
231
+ }),
232
+ ).toHaveLength(300);
233
+ },
234
+
235
+ "should support select in findMany": async () => {
236
+ await adapter.create({
237
+ model: "user",
238
+ data: {
239
+ name: "foo",
240
+ email: "foo@bar.com",
241
+ },
242
+ });
243
+ const result = await adapter.findMany({
244
+ model: "user",
245
+ where: [{ field: "email", value: "foo@bar.com" }],
246
+ select: ["email"],
247
+ });
248
+ expect(result).toHaveLength(1);
249
+ expect((result[0] as any).email).toEqual("foo@bar.com");
250
+ },
251
+
252
+ "should handle OR where clauses": async () => {
253
+ const user = await adapter.create({
254
+ model: "user",
255
+ data: {
256
+ name: "foo",
257
+ email: "foo@bar.com",
258
+ },
259
+ });
260
+ expect(
261
+ await adapter.findOne({
262
+ model: "user",
263
+ where: [
264
+ { field: "name", value: "bar", connector: "OR" },
265
+ { field: "name", value: "foo", connector: "OR" },
266
+ ],
267
+ }),
268
+ ).toEqual(user);
269
+ },
270
+
271
+ "should handle OR where clauses with sortBy": async () => {
272
+ const fooUser = await adapter.create({
273
+ model: "user",
274
+ data: {
275
+ name: "foo",
276
+ email: "foo@bar.com",
277
+ },
278
+ });
279
+ const barUser = await adapter.create({
280
+ model: "user",
281
+ data: {
282
+ name: "bar",
283
+ email: "bar@bar.com",
284
+ },
285
+ });
286
+ await adapter.create({
287
+ model: "user",
288
+ data: {
289
+ name: "baz",
290
+ email: "baz@bar.com",
291
+ },
292
+ });
293
+ expect(
294
+ await adapter.findMany({
295
+ model: "user",
296
+ where: [
297
+ { field: "name", value: "bar", connector: "OR" },
298
+ { field: "name", value: "foo", connector: "OR" },
299
+ ],
300
+ sortBy: { field: "name", direction: "asc" },
301
+ }),
302
+ ).toEqual([barUser, fooUser]);
303
+ expect(
304
+ await adapter.findMany({
305
+ model: "user",
306
+ where: [
307
+ { field: "name", value: "bar", connector: "OR" },
308
+ { field: "name", value: "foo", connector: "OR" },
309
+ ],
310
+ sortBy: { field: "name", direction: "desc" },
311
+ }),
312
+ ).toEqual([fooUser, barUser]);
313
+ },
314
+
315
+ "should apply OR dedupe/sort/limit before select": async () => {
316
+ const suffix = Date.now();
317
+ const alphaOnly = await adapter.create({
318
+ model: "user",
319
+ data: {
320
+ name: "alpha-only",
321
+ email: `alpha-only-${suffix}@other.test`,
322
+ },
323
+ });
324
+ const alphaOverlap = await adapter.create({
325
+ model: "user",
326
+ data: {
327
+ name: "alpha-overlap",
328
+ email: `alpha-overlap-${suffix}@example.com`,
329
+ },
330
+ });
331
+ await adapter.create({
332
+ model: "user",
333
+ data: {
334
+ name: "beta-only",
335
+ email: `beta-only-${suffix}@example.com`,
336
+ },
337
+ });
338
+ await adapter.create({
339
+ model: "user",
340
+ data: {
341
+ name: "delta-only",
342
+ email: `delta-only-${suffix}@example.com`,
343
+ },
344
+ });
345
+
346
+ const result = await adapter.findMany<{ email: string }>({
347
+ model: "user",
348
+ where: [
349
+ {
350
+ field: "name",
351
+ operator: "starts_with",
352
+ value: "alpha",
353
+ connector: "OR",
354
+ },
355
+ {
356
+ field: "email",
357
+ operator: "contains",
358
+ value: "@example.com",
359
+ connector: "OR",
360
+ },
361
+ ],
362
+ sortBy: { field: "name", direction: "asc" },
363
+ limit: 2,
364
+ select: ["email"],
365
+ });
366
+
367
+ expect(result).toEqual([
368
+ { email: alphaOnly.email },
369
+ { email: alphaOverlap.email },
370
+ ]);
371
+ },
372
+
373
+ "should reject update with an empty where clause": async () => {
374
+ const user = await adapter.create({
375
+ model: "user",
376
+ data: {
377
+ name: "foo",
378
+ email: "foo@bar.com",
379
+ },
380
+ });
381
+ await expect(
382
+ adapter.update({
383
+ model: "user",
384
+ where: [],
385
+ update: { name: "bar" },
386
+ }),
387
+ ).rejects.toThrow("where clause not supported");
388
+ expect(
389
+ await adapter.findOne({
390
+ model: "user",
391
+ where: [{ field: "id", value: user.id }],
392
+ }),
393
+ ).toEqual(user);
394
+ },
395
+
396
+ "should update and count each match only once for overlapping OR clauses":
397
+ async () => {
398
+ const foo = await adapter.create({
399
+ model: "user",
400
+ data: {
401
+ name: "foo",
402
+ email: "foo@bar.com",
403
+ },
404
+ });
405
+ const foobar = await adapter.create({
406
+ model: "user",
407
+ data: {
408
+ name: "foobar",
409
+ email: "foobar@bar.com",
410
+ },
411
+ });
412
+ const count = await adapter.updateMany({
413
+ model: "user",
414
+ where: [
415
+ { field: "name", value: "foo", connector: "OR" },
416
+ {
417
+ field: "name",
418
+ operator: "starts_with",
419
+ value: "foo",
420
+ connector: "OR",
421
+ },
422
+ ],
423
+ update: { emailVerified: true },
424
+ });
425
+ expect(count).toEqual(2);
426
+ expect(
427
+ await adapter.findOne({
428
+ model: "user",
429
+ where: [{ field: "id", value: foo.id }],
430
+ }),
431
+ ).toMatchObject({ emailVerified: true });
432
+ expect(
433
+ await adapter.findOne({
434
+ model: "user",
435
+ where: [{ field: "id", value: foobar.id }],
436
+ }),
437
+ ).toMatchObject({ emailVerified: true });
438
+ },
439
+
440
+ "should delete and count each match only once for overlapping OR clauses":
441
+ async () => {
442
+ await adapter.create({
443
+ model: "user",
444
+ data: {
445
+ name: "foo",
446
+ email: "foo@bar.com",
447
+ },
448
+ });
449
+ await adapter.create({
450
+ model: "user",
451
+ data: {
452
+ name: "foobar",
453
+ email: "foobar@bar.com",
454
+ },
455
+ });
456
+ const untouched = await adapter.create({
457
+ model: "user",
458
+ data: {
459
+ name: "bar",
460
+ email: "bar@bar.com",
461
+ },
462
+ });
463
+ const count = await adapter.deleteMany({
464
+ model: "user",
465
+ where: [
466
+ { field: "name", value: "foo", connector: "OR" },
467
+ {
468
+ field: "name",
469
+ operator: "starts_with",
470
+ value: "foo",
471
+ connector: "OR",
472
+ },
473
+ ],
474
+ });
475
+ expect(count).toEqual(2);
476
+ const result = await adapter.findMany({
477
+ model: "user",
478
+ });
479
+ expect(result).toHaveLength(1);
480
+ expect(result).toEqual([untouched]);
481
+ },
482
+
483
+ "should handle count": async () => {
484
+ await adapter.create({
485
+ model: "user",
486
+ data: {
487
+ name: "foo",
488
+ email: "foo@bar.com",
489
+ },
490
+ });
491
+ await adapter.create({
492
+ model: "user",
493
+ data: {
494
+ name: "bar",
495
+ email: "bar@bar.com",
496
+ },
497
+ });
498
+ expect(
499
+ await adapter.count({
500
+ model: "user",
501
+ where: [{ field: "name", value: "foo" }],
502
+ }),
503
+ ).toEqual(1);
504
+ },
505
+
506
+ "should handle queries with no index": async () => {
507
+ const user = await adapter.create({
508
+ model: "user",
509
+ data: {
510
+ name: "foo",
511
+ email: "foo@bar.com",
512
+ emailVerified: true,
513
+ },
514
+ });
515
+ expect(
516
+ await adapter.findOne({
517
+ model: "user",
518
+ where: [{ field: "emailVerified", value: true }],
519
+ }),
520
+ ).toEqual(user);
521
+ expect(
522
+ await adapter.findOne({
523
+ model: "user",
524
+ where: [{ field: "emailVerified", value: false }],
525
+ }),
526
+ ).toEqual(null);
527
+ },
528
+
529
+ "should handle compound operator on non-unique field without an index":
530
+ async () => {
531
+ await adapter.create({
532
+ model: "account",
533
+ data: {
534
+ accountId: "foo",
535
+ providerId: "bar",
536
+ userId: "baz",
537
+ accessTokenExpiresAt: null,
538
+ createdAt: Date.now(),
539
+ updatedAt: Date.now(),
540
+ },
541
+ });
542
+ expect(
543
+ await adapter.findOne({
544
+ model: "account",
545
+ where: [
546
+ {
547
+ operator: "lt",
548
+ connector: "AND",
549
+ field: "accessTokenExpiresAt",
550
+ value: Date.now(),
551
+ },
552
+ {
553
+ operator: "ne",
554
+ connector: "AND",
555
+ field: "accessTokenExpiresAt",
556
+ value: null,
557
+ },
558
+ ],
559
+ }),
560
+ ).toEqual(null);
561
+ },
562
+
563
+ "should preserve null to non-null range comparisons": async () => {
564
+ const now = Date.now();
565
+ const nullRangeAccountId = `null-range-${now}-null`;
566
+ const nonNullRangeAccountId = `null-range-${now}-non-null`;
567
+
568
+ const nullRangeAccount = await adapter.create({
569
+ model: "account",
570
+ data: {
571
+ accountId: nullRangeAccountId,
572
+ providerId: "null-range-provider",
573
+ userId: `null-range-user-${now}`,
574
+ accessTokenExpiresAt: null,
575
+ createdAt: now,
576
+ updatedAt: now,
577
+ },
578
+ });
579
+
580
+ const nonNullRangeAccount = await adapter.create({
581
+ model: "account",
582
+ data: {
583
+ accountId: nonNullRangeAccountId,
584
+ providerId: "non-null-range-provider",
585
+ userId: `non-null-range-user-${now}`,
586
+ accessTokenExpiresAt: now + 1_000,
587
+ createdAt: now,
588
+ updatedAt: now,
589
+ },
590
+ });
591
+
592
+ expect(
593
+ await adapter.findOne({
594
+ model: "account",
595
+ where: [
596
+ {
597
+ field: "accessTokenExpiresAt",
598
+ operator: "lt",
599
+ connector: "AND",
600
+ value: now,
601
+ },
602
+ {
603
+ field: "accountId",
604
+ operator: "eq",
605
+ connector: "AND",
606
+ value: nullRangeAccountId,
607
+ },
608
+ ],
609
+ }),
610
+ ).toEqual(nullRangeAccount);
611
+
612
+ expect(
613
+ await adapter.findOne({
614
+ model: "account",
615
+ where: [
616
+ {
617
+ field: "accessTokenExpiresAt",
618
+ operator: "lte",
619
+ connector: "AND",
620
+ value: now,
621
+ },
622
+ {
623
+ field: "accountId",
624
+ operator: "eq",
625
+ connector: "AND",
626
+ value: nullRangeAccountId,
627
+ },
628
+ ],
629
+ }),
630
+ ).toEqual(nullRangeAccount);
631
+
632
+ expect(
633
+ await adapter.findOne({
634
+ model: "account",
635
+ where: [
636
+ {
637
+ field: "accessTokenExpiresAt",
638
+ operator: "gt",
639
+ connector: "AND",
640
+ value: null,
641
+ },
642
+ {
643
+ field: "accountId",
644
+ operator: "eq",
645
+ connector: "AND",
646
+ value: nonNullRangeAccountId,
647
+ },
648
+ ],
649
+ }),
650
+ ).toEqual(nonNullRangeAccount);
651
+
652
+ expect(
653
+ await adapter.findOne({
654
+ model: "account",
655
+ where: [
656
+ {
657
+ field: "accessTokenExpiresAt",
658
+ operator: "gte",
659
+ connector: "AND",
660
+ value: null,
661
+ },
662
+ {
663
+ field: "accountId",
664
+ operator: "eq",
665
+ connector: "AND",
666
+ value: nonNullRangeAccountId,
667
+ },
668
+ ],
669
+ }),
670
+ ).toEqual(nonNullRangeAccount);
671
+ },
672
+
673
+ "should fail to create a record with a unique field that already exists":
674
+ async () => {
675
+ await adapter.create({
676
+ model: "user",
677
+ data: { name: "foo", email: "foo@bar.com" },
678
+ });
679
+ await expect(
680
+ adapter.create({
681
+ model: "user",
682
+ data: { name: "foo", email: "foo@bar.com" },
683
+ }),
684
+ ).rejects.toThrow("user email already exists");
685
+ },
686
+
687
+ "should be able to compare against a date": async () => {
688
+ const now = new Date().toISOString();
689
+ const user = await adapter.create({
690
+ model: "user",
691
+ data: {
692
+ name: "foo",
693
+ email: "foo@bar.com",
694
+ createdAt: now,
695
+ },
696
+ });
697
+ expect(
698
+ await adapter.findOne({
699
+ model: "user",
700
+ where: [{ field: "createdAt", value: now }],
701
+ }),
702
+ ).toEqual(user);
703
+ expect(user.createdAt).toBeInstanceOf(Date);
704
+ },
705
+ }),
706
+ );
@@ -0,0 +1,10 @@
1
+ export * from "./auth-flow.js";
2
+ export * from "./basic.js";
3
+ export * from "./convex-custom.js";
4
+ export * from "./joins.js";
5
+ export * from "./number-id.js";
6
+ export * from "./profile-additional-fields.js";
7
+ export * from "./profile-plugin-table.js";
8
+ export * from "./profile-rename-joins.js";
9
+ export * from "./transactions.js";
10
+ export * from "./uuid.js";