@evolu/common 8.7.0 → 8.8.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 (300) hide show
  1. package/dist/src/Array.d.ts +21 -21
  2. package/dist/src/Array.js +5 -5
  3. package/dist/src/Assert.d.ts +478 -141
  4. package/dist/src/Assert.d.ts.map +1 -1
  5. package/dist/src/Assert.js +644 -99
  6. package/dist/src/{Buffer.d.ts → Binary.d.ts} +85 -12
  7. package/dist/src/Binary.d.ts.map +1 -0
  8. package/dist/src/{Buffer.js → Binary.js} +206 -24
  9. package/dist/src/Console.d.ts +2 -10
  10. package/dist/src/Console.d.ts.map +1 -1
  11. package/dist/src/Console.js +6 -12
  12. package/dist/src/Crypto.d.ts +5 -5
  13. package/dist/src/Crypto.js +1 -1
  14. package/dist/src/Eq.d.ts +35 -40
  15. package/dist/src/Eq.d.ts.map +1 -1
  16. package/dist/src/Eq.js +51 -87
  17. package/dist/src/Function.d.ts +9 -14
  18. package/dist/src/Function.d.ts.map +1 -1
  19. package/dist/src/Function.js +7 -9
  20. package/dist/src/Http.d.ts +6 -7
  21. package/dist/src/Http.d.ts.map +1 -1
  22. package/dist/src/LeakDetector.d.ts.map +1 -1
  23. package/dist/src/LeakDetector.js +1 -0
  24. package/dist/src/LockManager.d.ts +1 -1
  25. package/dist/src/LockManager.js +1 -1
  26. package/dist/src/Lookup.d.ts +3 -2
  27. package/dist/src/Lookup.d.ts.map +1 -1
  28. package/dist/src/Lookup.js +4 -3
  29. package/dist/src/Number.d.ts +1 -1
  30. package/dist/src/Number.d.ts.map +1 -1
  31. package/dist/src/Number.js +1 -1
  32. package/dist/src/Object.d.ts +4 -4
  33. package/dist/src/Object.d.ts.map +1 -1
  34. package/dist/src/Object.js +5 -4
  35. package/dist/src/Option.d.ts +1 -2
  36. package/dist/src/Option.d.ts.map +1 -1
  37. package/dist/src/Option.js +1 -2
  38. package/dist/src/Platform.js +2 -0
  39. package/dist/src/Polyfills.js +4 -1
  40. package/dist/src/Random.d.ts +1 -1
  41. package/dist/src/Result.d.ts +49 -54
  42. package/dist/src/Result.d.ts.map +1 -1
  43. package/dist/src/Result.js +17 -22
  44. package/dist/src/Set.d.ts +6 -6
  45. package/dist/src/Set.js +2 -2
  46. package/dist/src/Sqlite.js +1 -1
  47. package/dist/src/String.js +3 -2
  48. package/dist/src/Task.d.ts +32 -32
  49. package/dist/src/Task.d.ts.map +1 -1
  50. package/dist/src/Task.js +20 -22
  51. package/dist/src/Test.d.ts +31 -3
  52. package/dist/src/Test.d.ts.map +1 -1
  53. package/dist/src/Test.js +46 -3
  54. package/dist/src/Time.d.ts +3 -11
  55. package/dist/src/Time.d.ts.map +1 -1
  56. package/dist/src/Time.js +10 -18
  57. package/dist/src/Type.d.ts +87 -85
  58. package/dist/src/Type.d.ts.map +1 -1
  59. package/dist/src/Type.js +70 -63
  60. package/dist/src/Types.d.ts +12 -12
  61. package/dist/src/Types.js +1 -1
  62. package/dist/src/WebSocket.d.ts +4 -7
  63. package/dist/src/WebSocket.d.ts.map +1 -1
  64. package/dist/src/Worker.d.ts +1 -1
  65. package/dist/src/Worker.js +7 -7
  66. package/dist/src/index.d.ts +1 -1
  67. package/dist/src/index.js +1 -1
  68. package/dist/src/intl/_en.d.ts.map +1 -1
  69. package/dist/src/intl/_en.js +1 -1
  70. package/dist/src/intl/ar.d.ts.map +1 -1
  71. package/dist/src/intl/ar.js +1 -1
  72. package/dist/src/intl/bn.d.ts.map +1 -1
  73. package/dist/src/intl/bn.js +1 -1
  74. package/dist/src/intl/ca.d.ts.map +1 -1
  75. package/dist/src/intl/ca.js +1 -1
  76. package/dist/src/intl/cs.d.ts.map +1 -1
  77. package/dist/src/intl/cs.js +1 -1
  78. package/dist/src/intl/da.d.ts.map +1 -1
  79. package/dist/src/intl/da.js +1 -1
  80. package/dist/src/intl/de.d.ts.map +1 -1
  81. package/dist/src/intl/de.js +1 -1
  82. package/dist/src/intl/el.d.ts.map +1 -1
  83. package/dist/src/intl/el.js +1 -1
  84. package/dist/src/intl/es.d.ts.map +1 -1
  85. package/dist/src/intl/es.js +1 -1
  86. package/dist/src/intl/fa.d.ts.map +1 -1
  87. package/dist/src/intl/fa.js +1 -1
  88. package/dist/src/intl/fi.d.ts.map +1 -1
  89. package/dist/src/intl/fi.js +1 -1
  90. package/dist/src/intl/fil.d.ts.map +1 -1
  91. package/dist/src/intl/fil.js +1 -1
  92. package/dist/src/intl/fr.d.ts.map +1 -1
  93. package/dist/src/intl/fr.js +1 -1
  94. package/dist/src/intl/he.d.ts.map +1 -1
  95. package/dist/src/intl/he.js +1 -1
  96. package/dist/src/intl/hi.d.ts.map +1 -1
  97. package/dist/src/intl/hi.js +1 -1
  98. package/dist/src/intl/hr.d.ts.map +1 -1
  99. package/dist/src/intl/hr.js +1 -1
  100. package/dist/src/intl/hu.d.ts.map +1 -1
  101. package/dist/src/intl/hu.js +1 -1
  102. package/dist/src/intl/id.d.ts.map +1 -1
  103. package/dist/src/intl/id.js +1 -1
  104. package/dist/src/intl/it.d.ts.map +1 -1
  105. package/dist/src/intl/it.js +1 -1
  106. package/dist/src/intl/ja.d.ts.map +1 -1
  107. package/dist/src/intl/ja.js +1 -1
  108. package/dist/src/intl/ko.d.ts.map +1 -1
  109. package/dist/src/intl/ko.js +1 -1
  110. package/dist/src/intl/ml.d.ts.map +1 -1
  111. package/dist/src/intl/ml.js +1 -1
  112. package/dist/src/intl/mr.d.ts.map +1 -1
  113. package/dist/src/intl/mr.js +1 -1
  114. package/dist/src/intl/ms.d.ts.map +1 -1
  115. package/dist/src/intl/ms.js +1 -1
  116. package/dist/src/intl/nb.d.ts.map +1 -1
  117. package/dist/src/intl/nb.js +1 -1
  118. package/dist/src/intl/nl.d.ts.map +1 -1
  119. package/dist/src/intl/nl.js +1 -1
  120. package/dist/src/intl/pa.d.ts.map +1 -1
  121. package/dist/src/intl/pa.js +1 -1
  122. package/dist/src/intl/pl.d.ts.map +1 -1
  123. package/dist/src/intl/pl.js +1 -1
  124. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  125. package/dist/src/intl/pt-BR.js +1 -1
  126. package/dist/src/intl/pt.d.ts.map +1 -1
  127. package/dist/src/intl/pt.js +1 -1
  128. package/dist/src/intl/ro.d.ts.map +1 -1
  129. package/dist/src/intl/ro.js +1 -1
  130. package/dist/src/intl/sk.d.ts.map +1 -1
  131. package/dist/src/intl/sk.js +1 -1
  132. package/dist/src/intl/sl.d.ts.map +1 -1
  133. package/dist/src/intl/sl.js +1 -1
  134. package/dist/src/intl/sv.d.ts.map +1 -1
  135. package/dist/src/intl/sv.js +1 -1
  136. package/dist/src/intl/sw.d.ts.map +1 -1
  137. package/dist/src/intl/sw.js +1 -1
  138. package/dist/src/intl/ta.d.ts.map +1 -1
  139. package/dist/src/intl/ta.js +1 -1
  140. package/dist/src/intl/te.d.ts.map +1 -1
  141. package/dist/src/intl/te.js +1 -1
  142. package/dist/src/intl/th.d.ts.map +1 -1
  143. package/dist/src/intl/th.js +1 -1
  144. package/dist/src/intl/tr.d.ts.map +1 -1
  145. package/dist/src/intl/tr.js +1 -1
  146. package/dist/src/intl/uk.d.ts.map +1 -1
  147. package/dist/src/intl/uk.js +1 -1
  148. package/dist/src/intl/ur.d.ts.map +1 -1
  149. package/dist/src/intl/ur.js +1 -1
  150. package/dist/src/intl/vi.d.ts.map +1 -1
  151. package/dist/src/intl/vi.js +1 -1
  152. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  153. package/dist/src/intl/zh-CN.js +1 -1
  154. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  155. package/dist/src/intl/zh-TW.js +1 -1
  156. package/dist/src/local-first/Evolu.d.ts +12 -12
  157. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  158. package/dist/src/local-first/Evolu.js +2 -2
  159. package/dist/src/local-first/Protocol.d.ts +14 -76
  160. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  161. package/dist/src/local-first/Protocol.js +29 -206
  162. package/dist/src/local-first/Query.d.ts +11 -11
  163. package/dist/src/local-first/Query.js +6 -6
  164. package/dist/src/local-first/Relay.d.ts +2 -2
  165. package/dist/src/local-first/Schema.d.ts +3 -5
  166. package/dist/src/local-first/Schema.d.ts.map +1 -1
  167. package/dist/src/local-first/Schema.js +2 -4
  168. package/dist/src/local-first/Shared.d.ts.map +1 -1
  169. package/dist/src/local-first/Shared.js +5 -5
  170. package/dist/src/local-first/Storage.js +4 -4
  171. package/dist/src/local-first/Timestamp.d.ts +9 -0
  172. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  173. package/dist/src/local-first/Timestamp.js +13 -10
  174. package/package.json +7 -4
  175. package/src/Array.test.ts +809 -0
  176. package/src/Array.ts +21 -21
  177. package/src/Assert.test.ts +1181 -0
  178. package/src/Assert.ts +971 -227
  179. package/src/BigInt.test.ts +28 -0
  180. package/src/Binary.test.ts +1128 -0
  181. package/src/{Buffer.ts → Binary.ts} +273 -46
  182. package/src/Brand.test.ts +90 -0
  183. package/src/Cache.test.ts +183 -0
  184. package/src/Callbacks.test.ts +66 -0
  185. package/src/Console.test.ts +809 -0
  186. package/src/Console.ts +9 -17
  187. package/src/Crypto.test.ts +138 -0
  188. package/src/Crypto.ts +5 -5
  189. package/src/Eq.test.ts +333 -0
  190. package/src/Eq.ts +110 -176
  191. package/src/Error.test.ts +118 -0
  192. package/src/Function.test.ts +204 -0
  193. package/src/Function.ts +10 -15
  194. package/src/Http.test.ts +816 -0
  195. package/src/Http.ts +6 -7
  196. package/src/LeakDetector.test.ts +210 -0
  197. package/src/LeakDetector.ts +1 -0
  198. package/src/LockManager.ts +2 -2
  199. package/src/Lookup.test.ts +418 -0
  200. package/src/Lookup.ts +4 -3
  201. package/src/Microtask.test.ts +140 -0
  202. package/src/Number.test.ts +218 -0
  203. package/src/Number.ts +2 -2
  204. package/src/Object.test.ts +293 -0
  205. package/src/Object.ts +5 -4
  206. package/src/Option.test.ts +104 -0
  207. package/src/Option.ts +1 -2
  208. package/src/Order.test.ts +56 -0
  209. package/src/Platform.ts +2 -0
  210. package/src/Polyfills.ts +3 -4
  211. package/src/Random.test.ts +89 -0
  212. package/src/Random.ts +1 -1
  213. package/src/Ref.test.ts +139 -0
  214. package/src/RefCount.test.ts +184 -0
  215. package/src/Relation.test.ts +505 -0
  216. package/src/Resource.test.ts +4623 -0
  217. package/src/Result.test.ts +1829 -0
  218. package/src/Result.ts +49 -54
  219. package/src/Schedule.test.ts +1554 -0
  220. package/src/Set.test.ts +279 -0
  221. package/src/Set.ts +6 -6
  222. package/src/Sqlite.ts +1 -1
  223. package/src/Store.test.ts +288 -0
  224. package/src/String.test.ts +54 -0
  225. package/src/String.ts +3 -3
  226. package/src/Task.test.ts +10820 -0
  227. package/src/Task.ts +38 -43
  228. package/src/Test.test.ts +88 -0
  229. package/src/Test.ts +49 -3
  230. package/src/Time.test.ts +926 -0
  231. package/src/Time.ts +13 -21
  232. package/src/Type.base64.test.ts +88 -0
  233. package/src/Type.test.ts +20465 -0
  234. package/src/Type.ts +114 -111
  235. package/src/Types.test.ts +324 -0
  236. package/src/Types.ts +13 -13
  237. package/src/WebSocket.ts +4 -7
  238. package/src/Worker.test.ts +755 -0
  239. package/src/Worker.ts +13 -18
  240. package/src/index.ts +1 -1
  241. package/src/intl/_en.ts +1 -1
  242. package/src/intl/ar.ts +1 -1
  243. package/src/intl/bn.ts +1 -1
  244. package/src/intl/ca.ts +1 -1
  245. package/src/intl/cs.ts +1 -1
  246. package/src/intl/da.ts +1 -1
  247. package/src/intl/de.ts +1 -1
  248. package/src/intl/el.ts +1 -1
  249. package/src/intl/es.ts +1 -1
  250. package/src/intl/fa.ts +1 -1
  251. package/src/intl/fi.ts +1 -1
  252. package/src/intl/fil.ts +1 -1
  253. package/src/intl/fr.ts +1 -1
  254. package/src/intl/he.ts +1 -1
  255. package/src/intl/hi.ts +1 -1
  256. package/src/intl/hr.ts +1 -1
  257. package/src/intl/hu.ts +1 -1
  258. package/src/intl/id.ts +1 -1
  259. package/src/intl/intl.test.ts +3106 -0
  260. package/src/intl/it.ts +1 -1
  261. package/src/intl/ja.ts +1 -1
  262. package/src/intl/ko.ts +1 -1
  263. package/src/intl/ml.ts +1 -1
  264. package/src/intl/mr.ts +1 -1
  265. package/src/intl/ms.ts +1 -1
  266. package/src/intl/nb.ts +1 -1
  267. package/src/intl/nl.ts +1 -1
  268. package/src/intl/pa.ts +1 -1
  269. package/src/intl/pl.ts +1 -1
  270. package/src/intl/pt-BR.ts +1 -1
  271. package/src/intl/pt.ts +1 -1
  272. package/src/intl/ro.ts +1 -1
  273. package/src/intl/sk.ts +1 -1
  274. package/src/intl/sl.ts +1 -1
  275. package/src/intl/sv.ts +1 -1
  276. package/src/intl/sw.ts +1 -1
  277. package/src/intl/ta.ts +1 -1
  278. package/src/intl/te.ts +1 -1
  279. package/src/intl/th.ts +1 -1
  280. package/src/intl/tr.ts +1 -1
  281. package/src/intl/uk.ts +1 -1
  282. package/src/intl/ur.ts +1 -1
  283. package/src/intl/vi.ts +1 -1
  284. package/src/intl/zh-CN.ts +1 -1
  285. package/src/intl/zh-TW.ts +1 -1
  286. package/src/local-first/Evolu.test.ts +1921 -0
  287. package/src/local-first/Evolu.ts +18 -14
  288. package/src/local-first/Owner.test.ts +83 -0
  289. package/src/local-first/Protocol.test.ts +1037 -0
  290. package/src/local-first/Protocol.ts +58 -261
  291. package/src/local-first/Query.test.ts +349 -0
  292. package/src/local-first/Query.ts +11 -11
  293. package/src/local-first/Relay.ts +2 -2
  294. package/src/local-first/Schema.ts +3 -5
  295. package/src/local-first/Shared.test.ts +1828 -0
  296. package/src/local-first/Shared.ts +9 -8
  297. package/src/local-first/Storage.ts +4 -4
  298. package/src/local-first/Timestamp.test.ts +374 -0
  299. package/src/local-first/Timestamp.ts +22 -10
  300. package/dist/src/Buffer.d.ts.map +0 -1
@@ -0,0 +1,349 @@
1
+ import { test } from "node:test";
2
+ import {
3
+ assertEqual,
4
+ assertLength,
5
+ assertNotUndefined,
6
+ assertSame,
7
+ assertThrowsInstanceOf,
8
+ assertTrue,
9
+ } from "../Assert.ts";
10
+ import { ColumnNode, type SelectQueryNode } from "kysely";
11
+
12
+ import type { Query, Row } from "./Query.ts";
13
+ import {
14
+ applyPatches,
15
+ evoluJsonArrayFrom,
16
+ evoluJsonBuildObject,
17
+ evoluJsonObjectFrom,
18
+ getJsonObjectArgs,
19
+ kyselyJsonIdentifier,
20
+ kyselySql,
21
+ makePatches,
22
+ } from "./Query.ts";
23
+ import { createQueryBuilder } from "./Schema.ts";
24
+ import { sqliteQueryStringToSqliteQuery } from "../Sqlite.ts";
25
+ import { assertType, id, NonEmptyTrimmedString100 } from "../Type.ts";
26
+
27
+ const PersonId = id("Person");
28
+ const PetId = id("Pet");
29
+
30
+ const QuerySchema = {
31
+ person: {
32
+ id: PersonId,
33
+ name: NonEmptyTrimmedString100,
34
+ },
35
+ pet: {
36
+ id: PetId,
37
+ name: NonEmptyTrimmedString100,
38
+ ownerId: PersonId,
39
+ },
40
+ };
41
+
42
+ const createQuery = createQueryBuilder(QuerySchema);
43
+
44
+ const NoteId = id("Note");
45
+ const AnotherQuerySchema = {
46
+ note: {
47
+ id: NoteId,
48
+ title: NonEmptyTrimmedString100,
49
+ },
50
+ };
51
+
52
+ const createAnotherQuery = createQueryBuilder(AnotherQuerySchema);
53
+
54
+ test("Query", () => {
55
+ const query1 = createQuery((db) =>
56
+ db.selectFrom("person").select(["id", "name"]),
57
+ );
58
+ const query2 = createAnotherQuery((db) =>
59
+ db.selectFrom("note").select(["id", "title"]),
60
+ );
61
+
62
+ // Ensure queries from different schemas are not assignable.
63
+ // @ts-expect-error - query1 should not be assignable to query2
64
+ const shouldError: typeof query2 = query1;
65
+
66
+ // @ts-expect-error - query2 should not be assignable to query1
67
+ const shouldAlsoError: typeof query1 = query2;
68
+
69
+ assertType<
70
+ typeof query1 extends Query<typeof QuerySchema> ? true : false,
71
+ true
72
+ >();
73
+ });
74
+
75
+ test("evoluJsonArrayFrom compiles a prefixed SQLite JSON array query", () => {
76
+ const query = createQuery((db) =>
77
+ db
78
+ .selectFrom("person")
79
+ .select(["person.id"])
80
+ .select((eb) => [
81
+ evoluJsonArrayFrom(
82
+ eb
83
+ .selectFrom("pet")
84
+ .select(["pet.id as petId", "pet.name", "ownerId"])
85
+ .whereRef("pet.ownerId", "=", "person.id"),
86
+ ).as("pets"),
87
+ ]),
88
+ );
89
+
90
+ const sqlQuery = sqliteQueryStringToSqliteQuery(query);
91
+
92
+ assertTrue(sqlQuery.sql.includes("json_group_array(json_object("));
93
+ assertTrue(sqlQuery.sql.includes(kyselyJsonIdentifier));
94
+ assertTrue(sqlQuery.sql.includes('"agg"."petId"'));
95
+ assertTrue(sqlQuery.sql.includes('"agg"."name"'));
96
+ assertTrue(sqlQuery.sql.includes('"agg"."ownerId"'));
97
+ });
98
+
99
+ test("evoluJsonObjectFrom compiles a prefixed SQLite JSON object query", () => {
100
+ const query = createQuery((db) =>
101
+ db
102
+ .selectFrom("person")
103
+ .select(["person.id"])
104
+ .select((eb) => [
105
+ evoluJsonObjectFrom(
106
+ eb
107
+ .selectFrom("pet")
108
+ .select(["id as petId", "name"])
109
+ .whereRef("pet.ownerId", "=", "person.id"),
110
+ ).as("favoritePet"),
111
+ ]),
112
+ );
113
+
114
+ const sqlQuery = sqliteQueryStringToSqliteQuery(query);
115
+
116
+ assertTrue(sqlQuery.sql.includes("json_object("));
117
+ assertTrue(sqlQuery.sql.includes(kyselyJsonIdentifier));
118
+ assertTrue(sqlQuery.sql.includes('"obj"."petId"'));
119
+ assertTrue(sqlQuery.sql.includes('"obj"."name"'));
120
+ });
121
+
122
+ test("evoluJsonBuildObject compiles a prefixed SQLite json_object expression", () => {
123
+ const query = createQuery((db) =>
124
+ db.selectFrom("person").select((eb) => [
125
+ evoluJsonBuildObject({
126
+ first: eb.ref("name"),
127
+ full: kyselySql<string>`name || '!'`,
128
+ }).as("profile"),
129
+ ]),
130
+ );
131
+
132
+ const sqlQuery = sqliteQueryStringToSqliteQuery(query);
133
+
134
+ assertTrue(sqlQuery.sql.includes("json_object("));
135
+ assertTrue(sqlQuery.sql.includes(kyselyJsonIdentifier));
136
+ assertTrue(sqlQuery.sql.includes("'first'"));
137
+ assertTrue(sqlQuery.sql.includes("'full'"));
138
+ });
139
+
140
+ test("getJsonObjectArgs handles alias, column, and reference selections", () => {
141
+ let operationNode: SelectQueryNode | undefined;
142
+
143
+ createQuery((db) => {
144
+ const subquery = db
145
+ .selectFrom("pet")
146
+ .select((eb) => [eb.ref("id").as("petId"), "name", "pet.ownerId"]);
147
+
148
+ operationNode = subquery.toOperationNode();
149
+ return db.selectFrom("pet").select(["pet.id"]);
150
+ });
151
+
152
+ assertNotUndefined(operationNode);
153
+
154
+ const args = getJsonObjectArgs(operationNode, "agg");
155
+
156
+ assertLength(args, 6);
157
+ });
158
+
159
+ test("getJsonObjectArgs handles unqualified column selections", () => {
160
+ const operationNode = {
161
+ selections: [{ selection: ColumnNode.create("name") }],
162
+ } as unknown as SelectQueryNode;
163
+
164
+ const args = getJsonObjectArgs(operationNode, "agg");
165
+
166
+ assertLength(args, 2);
167
+ });
168
+
169
+ test("getJsonObjectArgs rejects selections it cannot map to json_object", () => {
170
+ let operationNode: SelectQueryNode | undefined;
171
+
172
+ createQuery((db) => {
173
+ const subquery = db.selectFrom("pet").selectAll();
174
+ operationNode = subquery.toOperationNode();
175
+ return db.selectFrom("pet").select(["pet.id"]);
176
+ });
177
+
178
+ assertNotUndefined(operationNode);
179
+ const node = operationNode;
180
+
181
+ assertTrue(
182
+ assertThrowsInstanceOf(
183
+ () => getJsonObjectArgs(node, "agg"),
184
+ Error,
185
+ ).message.includes("can't extract column names from the select query node"),
186
+ );
187
+ });
188
+
189
+ test("getJsonObjectArgs returns empty array for nodes without selections", () => {
190
+ let operationNode: SelectQueryNode | undefined;
191
+
192
+ createQuery((db) => {
193
+ operationNode = db.selectFrom("pet").toOperationNode();
194
+ return db.selectFrom("pet").select(["pet.id"]);
195
+ });
196
+
197
+ assertNotUndefined(operationNode);
198
+
199
+ assertEqual(getJsonObjectArgs(operationNode, "agg"), []);
200
+ });
201
+
202
+ test("evoluJsonArrayFrom rejects selectAll subqueries", () => {
203
+ assertTrue(
204
+ assertThrowsInstanceOf(
205
+ () =>
206
+ createQuery((db) =>
207
+ db
208
+ .selectFrom("person")
209
+ .select((eb) => [
210
+ evoluJsonArrayFrom(eb.selectFrom("pet").selectAll()).as("pets"),
211
+ ]),
212
+ ),
213
+ Error,
214
+ ).message.includes(
215
+ "SQLite evoluJsonArrayFrom and evoluJsonObjectFrom can only handle explicit selections due to limitations of the json_object function. selectAll() is not allowed in the subquery.",
216
+ ),
217
+ );
218
+ });
219
+
220
+ test("makePatches", () => {
221
+ const row: Row = { a: 1 };
222
+ const rows: ReadonlyArray<Row> = [row];
223
+
224
+ assertLength(makePatches([], []), 0);
225
+ const p0 = [{ op: "replaceAll", value: [] }];
226
+ assertEqual(makePatches(rows, []), p0);
227
+
228
+ const p1 = makePatches([], rows);
229
+ assertEqual(p1, [{ op: "replaceAll", value: rows }]);
230
+ if (p1[0].op === "replaceAll") assertSame(p1[0].value, rows);
231
+
232
+ assertLength(makePatches(rows, rows), 0);
233
+
234
+ assertEqual(makePatches(rows, [{ a: 2 }]), [
235
+ { op: "replaceAll", value: [{ a: 2 }] },
236
+ ]);
237
+
238
+ assertEqual(makePatches([row, { b: 2 }], [row, { b: 3 }]), [
239
+ { op: "replaceAt", index: 1, value: { b: 3 } },
240
+ ]);
241
+
242
+ assertEqual(
243
+ makePatches([{ a: 1 }, row, { c: 4 }], [{ a: 0 }, row, { c: 1 }]),
244
+ [
245
+ { op: "replaceAt", index: 0, value: { a: 0 } },
246
+ { op: "replaceAt", index: 2, value: { c: 1 } },
247
+ ],
248
+ );
249
+
250
+ assertLength(
251
+ makePatches([{ a: new Uint8Array([1]) }], [{ a: new Uint8Array([1]) }]),
252
+ 0,
253
+ );
254
+ });
255
+
256
+ test("makePatches handles undefined previous rows", () => {
257
+ const rows: ReadonlyArray<Row> = [{ a: 1 }];
258
+ const patches = makePatches(undefined, rows);
259
+
260
+ assertEqual(patches, [{ op: "replaceAll", value: rows }]);
261
+ if (patches[0].op === "replaceAll") assertSame(patches[0].value, rows);
262
+ });
263
+
264
+ test("applyPatches", () => {
265
+ const current: ReadonlyArray<Row> = [];
266
+ assertSame(applyPatches([], current), current);
267
+
268
+ const value: ReadonlyArray<Row> = [];
269
+ assertEqual(applyPatches([{ op: "replaceAll", value }], current), value);
270
+
271
+ const replaceUntouched = { b: 2 };
272
+ const replaceAtResult = applyPatches(
273
+ [
274
+ { op: "replaceAt", index: 0, value: { a: 2 } },
275
+ { op: "replaceAt", index: 2, value: { c: 4 } },
276
+ ],
277
+ [{ a: 1 }, replaceUntouched, { c: 3 }],
278
+ );
279
+ assertEqual(replaceAtResult, [{ a: 2 }, { b: 2 }, { c: 4 }]);
280
+ assertSame(replaceAtResult[1], replaceUntouched);
281
+ });
282
+
283
+ test("applyPatches parses prefixed JSON in strings, arrays, and objects", () => {
284
+ const encodedObject = `${kyselyJsonIdentifier}{"x":1}`;
285
+ const encodedArray = `${kyselyJsonIdentifier}[1,2]`;
286
+
287
+ const result = applyPatches(
288
+ [
289
+ {
290
+ op: "replaceAll",
291
+ value: [
292
+ {
293
+ plain: "no-json",
294
+ objectValue: encodedObject,
295
+ arrayValue: [{ inside: encodedArray }],
296
+ nested: { inside: encodedObject },
297
+ },
298
+ ],
299
+ },
300
+ ],
301
+ [],
302
+ );
303
+
304
+ assertEqual(result, [
305
+ {
306
+ plain: "no-json",
307
+ objectValue: { x: 1 },
308
+ arrayValue: [{ inside: [1, 2] }],
309
+ nested: { inside: { x: 1 } },
310
+ },
311
+ ]);
312
+ });
313
+
314
+ test("applyPatches recursively parses prefixed JSON inside decoded JSON", () => {
315
+ const encodeJson = (value: unknown): string =>
316
+ `${kyselyJsonIdentifier}${JSON.stringify(value)}`;
317
+
318
+ const result = applyPatches(
319
+ [
320
+ {
321
+ op: "replaceAll",
322
+ value: [
323
+ {
324
+ nestedObject: encodeJson({
325
+ items: [
326
+ {
327
+ detail: encodeJson({ status: "ok" }),
328
+ },
329
+ ],
330
+ }),
331
+ },
332
+ ],
333
+ },
334
+ ],
335
+ [],
336
+ );
337
+
338
+ assertEqual(result, [
339
+ {
340
+ nestedObject: {
341
+ items: [
342
+ {
343
+ detail: { status: "ok" },
344
+ },
345
+ ],
346
+ },
347
+ },
348
+ ]);
349
+ });
@@ -58,11 +58,11 @@ export type { NotNull as KyselyNotNull } from "kysely";
58
58
  *
59
59
  * type AllTodosRow = typeof allTodos.Row;
60
60
  * assertType<
61
- * true,
62
- * typeof allTodos extends Query<typeof Schema> ? true : false
61
+ * typeof allTodos extends Query<typeof Schema> ? true : false,
62
+ * true
63
63
  * >();
64
- * assertType<TodoId, AllTodosRow["id"]>();
65
- * assertType<NonEmptyTrimmedString100 | null, AllTodosRow["title"]>();
64
+ * assertType<AllTodosRow["id"], TodoId>();
65
+ * assertType<AllTodosRow["title"], NonEmptyTrimmedString100 | null>();
66
66
  * ```
67
67
  */
68
68
  export type Query<
@@ -96,7 +96,7 @@ export type Query<
96
96
  * );
97
97
  *
98
98
  * type AllTodosRow = typeof allTodos.Row;
99
- * assertType<InferRow<typeof allTodos>, AllTodosRow>();
99
+ * assertType<AllTodosRow, InferRow<typeof allTodos>>();
100
100
  * ```
101
101
  */
102
102
  Row: R;
@@ -160,11 +160,11 @@ export interface Row {
160
160
  * );
161
161
  *
162
162
  * assertType<
163
+ * (typeof people.Row.pets)[number],
163
164
  * {
164
165
  * petId: typeof Schema.pet.id.Output;
165
166
  * name: NonEmptyTrimmedString100 | null;
166
- * },
167
- * (typeof people.Row.pets)[number]
167
+ * }
168
168
  * >();
169
169
  * ```
170
170
  */
@@ -225,11 +225,11 @@ export const evoluJsonArrayFrom = <O>(
225
225
  * );
226
226
  *
227
227
  * assertType<
228
+ * typeof people.Row.favoritePet,
228
229
  * {
229
230
  * petId: typeof Schema.pet.id.Output;
230
231
  * name: NonEmptyTrimmedString100 | null;
231
- * } | null,
232
- * typeof people.Row.favoritePet
232
+ * } | null
233
233
  * >();
234
234
  * ```
235
235
  */
@@ -285,12 +285,12 @@ export const evoluJsonObjectFrom = <O>(
285
285
  * );
286
286
  *
287
287
  * assertType<
288
+ * typeof people.Row.name,
288
289
  * {
289
290
  * first: NonEmptyTrimmedString100 | null;
290
291
  * last: NonEmptyTrimmedString100 | null;
291
292
  * full: string;
292
- * },
293
- * typeof people.Row.name
293
+ * }
294
294
  * >();
295
295
  * ```
296
296
  */
@@ -111,8 +111,8 @@ export interface RelayConfig extends StorageConfig {
111
111
  * },
112
112
  * );
113
113
  * assertType<
114
- * true,
115
- * typeof createTodoEvolu extends AnyTask ? true : false
114
+ * typeof createTodoEvolu extends AnyTask ? true : false,
115
+ * true
116
116
  * >();
117
117
  *
118
118
  * // Relay: accept owners allowed by the app's access policy.
@@ -98,7 +98,7 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
98
98
  * const ZodFiniteNumber = z
99
99
  * .number()
100
100
  * .transform((value): FiniteNumber => value as FiniteNumber);
101
- * assertType<FiniteNumber, z.output<typeof ZodFiniteNumber>>();
101
+ * assertType<z.output<typeof ZodFiniteNumber>, FiniteNumber>();
102
102
  *
103
103
  * const ZodSchema = {
104
104
  * todo: {
@@ -467,7 +467,6 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
467
467
  *
468
468
  * ```ts
469
469
  * import {
470
- * assertTrue,
471
470
  * assertType,
472
471
  * createQueryBuilder,
473
472
  * id,
@@ -493,14 +492,13 @@ export const evoluSchemaToSqliteSchema = <S extends EvoluSchema>(
493
492
  * );
494
493
  *
495
494
  * assertType<
495
+ * typeof todosQuery.Row,
496
496
  * {
497
497
  * id: TodoId;
498
498
  * title: NonEmptyTrimmedString100 | null;
499
499
  * isCompleted: SqliteBoolean | null;
500
- * },
501
- * typeof todosQuery.Row
500
+ * }
502
501
  * >();
503
- * assertTrue(typeof todosQuery === "string");
504
502
  * ```
505
503
  */
506
504
  export const createQueryBuilder = <S extends EvoluSchema>(