@indexeddb-orm/idb-orm 0.0.1

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 (216) hide show
  1. package/.vscode/extensions.json +5 -0
  2. package/README.md +1280 -0
  3. package/angular-demo-app/README.md +84 -0
  4. package/angular-demo-app/angular.json +109 -0
  5. package/angular-demo-app/package-lock.json +14215 -0
  6. package/angular-demo-app/package.json +41 -0
  7. package/angular-demo-app/src/app/app.component.ts +481 -0
  8. package/angular-demo-app/src/app/app.routes.ts +8 -0
  9. package/angular-demo-app/src/app/components/actions.component.ts +202 -0
  10. package/angular-demo-app/src/app/components/cloud-sync-demo.component.ts +296 -0
  11. package/angular-demo-app/src/app/components/live-query-demo.component.ts +307 -0
  12. package/angular-demo-app/src/app/components/main-info.component.ts +148 -0
  13. package/angular-demo-app/src/app/components/posts-live-query-demo.component.ts +336 -0
  14. package/angular-demo-app/src/app/components/typescript-demo.component.ts +268 -0
  15. package/angular-demo-app/src/entities/post-tag.entity.ts +25 -0
  16. package/angular-demo-app/src/entities/post.entity.ts +49 -0
  17. package/angular-demo-app/src/entities/profile.entity.ts +42 -0
  18. package/angular-demo-app/src/entities/tag.entity.ts +36 -0
  19. package/angular-demo-app/src/entities/user.entity.ts +59 -0
  20. package/angular-demo-app/src/favicon.ico +1 -0
  21. package/angular-demo-app/src/index.html +16 -0
  22. package/angular-demo-app/src/main.ts +13 -0
  23. package/angular-demo-app/src/services/app-logic.service.ts +449 -0
  24. package/angular-demo-app/src/services/cloud-sync.service.ts +95 -0
  25. package/angular-demo-app/src/services/database.service.ts +26 -0
  26. package/angular-demo-app/src/services/live-query.service.ts +63 -0
  27. package/angular-demo-app/src/services/posts-live-query.service.ts +86 -0
  28. package/angular-demo-app/src/services/typescript-demo.service.ts +59 -0
  29. package/angular-demo-app/src/styles.scss +50 -0
  30. package/angular-demo-app/tsconfig.app.json +13 -0
  31. package/angular-demo-app/tsconfig.json +34 -0
  32. package/angular-demo-app/tsconfig.spec.json +13 -0
  33. package/dist/Database.d.ts +206 -0
  34. package/dist/Database.js +288 -0
  35. package/dist/decorators/Column.d.ts +79 -0
  36. package/dist/decorators/Column.js +236 -0
  37. package/dist/decorators/Entity.d.ts +32 -0
  38. package/dist/decorators/Entity.js +44 -0
  39. package/dist/decorators/Relation.d.ts +70 -0
  40. package/dist/decorators/Relation.js +120 -0
  41. package/dist/decorators/index.d.ts +3 -0
  42. package/dist/decorators/index.js +3 -0
  43. package/dist/errors/ValidationError.d.ts +4 -0
  44. package/dist/errors/ValidationError.js +8 -0
  45. package/dist/index.d.ts +8 -0
  46. package/dist/index.js +7 -0
  47. package/dist/metadata/Column.d.ts +8 -0
  48. package/dist/metadata/Column.js +44 -0
  49. package/dist/metadata/Entity.d.ts +11 -0
  50. package/dist/metadata/Entity.js +21 -0
  51. package/dist/metadata/Relation.d.ts +20 -0
  52. package/dist/metadata/Relation.js +74 -0
  53. package/dist/metadata/index.d.ts +3 -0
  54. package/dist/metadata/index.js +3 -0
  55. package/dist/services/AggregationService.d.ts +38 -0
  56. package/dist/services/AggregationService.js +229 -0
  57. package/dist/services/BaseEntity.d.ts +32 -0
  58. package/dist/services/BaseEntity.js +62 -0
  59. package/dist/services/CloudSyncService.d.ts +100 -0
  60. package/dist/services/CloudSyncService.js +196 -0
  61. package/dist/services/DecoratorUtils.d.ts +12 -0
  62. package/dist/services/DecoratorUtils.js +10 -0
  63. package/dist/services/EntityFactory.d.ts +25 -0
  64. package/dist/services/EntityFactory.js +27 -0
  65. package/dist/services/EntityRegistry.d.ts +61 -0
  66. package/dist/services/EntityRegistry.js +56 -0
  67. package/dist/services/EntitySchema.d.ts +56 -0
  68. package/dist/services/EntitySchema.js +125 -0
  69. package/dist/services/MigrationManager.d.ts +70 -0
  70. package/dist/services/MigrationManager.js +181 -0
  71. package/dist/services/RelationLoader.d.ts +66 -0
  72. package/dist/services/RelationLoader.js +310 -0
  73. package/dist/services/SchemaBuilder.d.ts +68 -0
  74. package/dist/services/SchemaBuilder.js +191 -0
  75. package/dist/services/index.d.ts +7 -0
  76. package/dist/services/index.js +7 -0
  77. package/dist/types.d.ts +152 -0
  78. package/dist/types.js +1 -0
  79. package/dist/utils/logger.d.ts +12 -0
  80. package/dist/utils/logger.js +16 -0
  81. package/eslint.config.js +49 -0
  82. package/homepage/favicon.svg +36 -0
  83. package/homepage/index.html +1725 -0
  84. package/package.json +78 -0
  85. package/react-demo-app/README.md +61 -0
  86. package/react-demo-app/eslint.config.js +60 -0
  87. package/react-demo-app/index.html +13 -0
  88. package/react-demo-app/package-lock.json +4955 -0
  89. package/react-demo-app/package.json +39 -0
  90. package/react-demo-app/src/App.tsx +172 -0
  91. package/react-demo-app/src/assets/react.svg +1 -0
  92. package/react-demo-app/src/components/Actions.tsx +171 -0
  93. package/react-demo-app/src/components/CloudSyncDemo.tsx +191 -0
  94. package/react-demo-app/src/components/LiveQueryDemo.tsx +122 -0
  95. package/react-demo-app/src/components/MainInfo.tsx +75 -0
  96. package/react-demo-app/src/components/PostsLiveQueryDemo.tsx +185 -0
  97. package/react-demo-app/src/components/TypeScriptDemo.tsx +190 -0
  98. package/react-demo-app/src/database/Database.ts +30 -0
  99. package/react-demo-app/src/entities/Post.ts +48 -0
  100. package/react-demo-app/src/entities/PostTag.ts +26 -0
  101. package/react-demo-app/src/entities/Profile.ts +41 -0
  102. package/react-demo-app/src/entities/Tag.ts +35 -0
  103. package/react-demo-app/src/entities/User.ts +61 -0
  104. package/react-demo-app/src/hooks/useAppLogic.ts +565 -0
  105. package/react-demo-app/src/hooks/useCloudSyncDemo.ts +84 -0
  106. package/react-demo-app/src/hooks/useLiveQueryDemo.ts +68 -0
  107. package/react-demo-app/src/hooks/usePostsLiveQueryDemo.ts +64 -0
  108. package/react-demo-app/src/hooks/useTypeScriptDemo.ts +43 -0
  109. package/react-demo-app/src/index.css +26 -0
  110. package/react-demo-app/src/main.tsx +18 -0
  111. package/react-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
  112. package/react-demo-app/src/migrations/002-add-post-category.ts +37 -0
  113. package/react-demo-app/src/migrations/index.ts +8 -0
  114. package/react-demo-app/src/vite-env.d.ts +1 -0
  115. package/react-demo-app/tsconfig.app.json +22 -0
  116. package/react-demo-app/tsconfig.json +6 -0
  117. package/react-demo-app/vite.config.ts +10 -0
  118. package/src/Database.ts +405 -0
  119. package/src/errors/ValidationError.ts +9 -0
  120. package/src/index.ts +13 -0
  121. package/src/metadata/Column.ts +74 -0
  122. package/src/metadata/Entity.ts +42 -0
  123. package/src/metadata/Relation.ts +121 -0
  124. package/src/metadata/index.ts +5 -0
  125. package/src/services/AggregationService.ts +348 -0
  126. package/src/services/BaseEntity.ts +77 -0
  127. package/src/services/CloudSyncService.ts +248 -0
  128. package/src/services/EntityFactory.ts +35 -0
  129. package/src/services/EntityRegistry.ts +109 -0
  130. package/src/services/EntitySchema.ts +154 -0
  131. package/src/services/MigrationManager.ts +276 -0
  132. package/src/services/RelationLoader.ts +532 -0
  133. package/src/services/SchemaBuilder.ts +237 -0
  134. package/src/services/index.ts +7 -0
  135. package/src/types.d.ts +1 -0
  136. package/src/types.ts +169 -0
  137. package/src/utils/logger.ts +40 -0
  138. package/svelte-demo-app/README.md +61 -0
  139. package/svelte-demo-app/package-lock.json +3000 -0
  140. package/svelte-demo-app/package.json +30 -0
  141. package/svelte-demo-app/src/app.d.ts +12 -0
  142. package/svelte-demo-app/src/app.html +13 -0
  143. package/svelte-demo-app/src/components/Actions.svelte +121 -0
  144. package/svelte-demo-app/src/components/CloudSyncDemo.svelte +333 -0
  145. package/svelte-demo-app/src/components/LiveQueryDemo.svelte +191 -0
  146. package/svelte-demo-app/src/components/MainInfo.svelte +133 -0
  147. package/svelte-demo-app/src/components/PostsLiveQueryDemo.svelte +330 -0
  148. package/svelte-demo-app/src/components/TypeScriptDemo.svelte +251 -0
  149. package/svelte-demo-app/src/database/Database.ts +29 -0
  150. package/svelte-demo-app/src/entities/Post.ts +46 -0
  151. package/svelte-demo-app/src/entities/PostTag.ts +22 -0
  152. package/svelte-demo-app/src/entities/Profile.ts +39 -0
  153. package/svelte-demo-app/src/entities/Tag.ts +33 -0
  154. package/svelte-demo-app/src/entities/User.ts +62 -0
  155. package/svelte-demo-app/src/lib/database/Database.ts +30 -0
  156. package/svelte-demo-app/src/lib/entities/Post.ts +47 -0
  157. package/svelte-demo-app/src/lib/entities/PostTag.ts +23 -0
  158. package/svelte-demo-app/src/lib/entities/Profile.ts +40 -0
  159. package/svelte-demo-app/src/lib/entities/Tag.ts +34 -0
  160. package/svelte-demo-app/src/lib/entities/User.ts +59 -0
  161. package/svelte-demo-app/src/lib/index.ts +7 -0
  162. package/svelte-demo-app/src/lib/migrations/001-add-user-email-index.ts +17 -0
  163. package/svelte-demo-app/src/lib/migrations/002-add-post-category.ts +37 -0
  164. package/svelte-demo-app/src/lib/migrations/index.ts +8 -0
  165. package/svelte-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
  166. package/svelte-demo-app/src/migrations/002-add-post-category.ts +37 -0
  167. package/svelte-demo-app/src/migrations/index.ts +8 -0
  168. package/svelte-demo-app/src/routes/+layout.js +3 -0
  169. package/svelte-demo-app/src/routes/+layout.svelte +228 -0
  170. package/svelte-demo-app/src/routes/+page.js +3 -0
  171. package/svelte-demo-app/src/routes/+page.svelte +1305 -0
  172. package/svelte-demo-app/src/stores/appStore.js +603 -0
  173. package/svelte-demo-app/svelte.config.js +18 -0
  174. package/svelte-demo-app/tsconfig.json +14 -0
  175. package/svelte-demo-app/vite.config.ts +6 -0
  176. package/tests/aggregation.e2e.test.ts +87 -0
  177. package/tests/base-entity.e2e.test.ts +47 -0
  178. package/tests/database-api.e2e.test.ts +177 -0
  179. package/tests/decorators.e2e.test.ts +40 -0
  180. package/tests/entity-schema.e2e.test.ts +58 -0
  181. package/tests/relation-loader-table-names.test.ts +192 -0
  182. package/tests/relations.e2e.test.ts +178 -0
  183. package/tests/zod-runtime.e2e.test.ts +69 -0
  184. package/tsconfig.json +21 -0
  185. package/vitest.config.ts +21 -0
  186. package/vitest.setup.ts +27 -0
  187. package/vue-demo-app/README.md +61 -0
  188. package/vue-demo-app/index.html +13 -0
  189. package/vue-demo-app/package-lock.json +1537 -0
  190. package/vue-demo-app/package.json +27 -0
  191. package/vue-demo-app/src/App.vue +100 -0
  192. package/vue-demo-app/src/components/Actions.vue +135 -0
  193. package/vue-demo-app/src/components/CloudSyncDemo.vue +139 -0
  194. package/vue-demo-app/src/components/LiveQueryDemo.vue +122 -0
  195. package/vue-demo-app/src/components/MainInfo.vue +80 -0
  196. package/vue-demo-app/src/components/PostsLiveQueryDemo.vue +136 -0
  197. package/vue-demo-app/src/components/TypeScriptDemo.vue +133 -0
  198. package/vue-demo-app/src/database/Database.ts +29 -0
  199. package/vue-demo-app/src/entities/Post.ts +48 -0
  200. package/vue-demo-app/src/entities/PostTag.ts +24 -0
  201. package/vue-demo-app/src/entities/Profile.ts +41 -0
  202. package/vue-demo-app/src/entities/Tag.ts +35 -0
  203. package/vue-demo-app/src/entities/User.ts +61 -0
  204. package/vue-demo-app/src/main.ts +29 -0
  205. package/vue-demo-app/src/migrations/001-add-user-email-index.ts +23 -0
  206. package/vue-demo-app/src/migrations/002-add-post-category.ts +46 -0
  207. package/vue-demo-app/src/migrations/index.ts +14 -0
  208. package/vue-demo-app/src/services/useAppLogic.ts +565 -0
  209. package/vue-demo-app/src/services/useCloudSyncDemo.ts +84 -0
  210. package/vue-demo-app/src/services/useLiveQueryDemo.ts +82 -0
  211. package/vue-demo-app/src/services/usePostsLiveQueryDemo.ts +77 -0
  212. package/vue-demo-app/src/services/useTypeScriptDemo.ts +56 -0
  213. package/vue-demo-app/src/vite-env.d.ts +1 -0
  214. package/vue-demo-app/tsconfig.json +25 -0
  215. package/vue-demo-app/tsconfig.node.json +10 -0
  216. package/vue-demo-app/vite.config.ts +16 -0
@@ -0,0 +1,603 @@
1
+ import { writable } from 'svelte/store';
2
+ import { browser } from '$app/environment';
3
+ import { db } from '$lib/database/Database';
4
+ import { newEntity } from '../../../src/services/EntityFactory';
5
+ import { UserEntity } from '$lib/entities/User';
6
+ import { PostEntity } from '$lib/entities/Post';
7
+ import { ProfileEntity } from '$lib/entities/Profile';
8
+ import { TagEntity } from '$lib/entities/Tag';
9
+
10
+ // State stores
11
+ export const users = writable([]);
12
+ export const tabIndex = writable(0);
13
+ export const mobileOpen = writable(false);
14
+ export const syncStatus = writable({ enabled: false, isOnline: false, lastSync: undefined });
15
+ export const userStats = writable({ totalUsers: 0, adultUsers: 0, firstUser: '' });
16
+ export const allUsers = writable([]);
17
+ export const allPosts = writable([]);
18
+ export const allProfiles = writable([]);
19
+ export const postStats = writable({ total: 0, published: 0, totalLikes: 0 });
20
+
21
+ // Actions
22
+ export function setTabIndex(index) {
23
+ tabIndex.set(index);
24
+ }
25
+
26
+ export function toggleMobileOpen() {
27
+ mobileOpen.update(open => !open);
28
+ }
29
+
30
+ export async function loadUsers() {
31
+ if (!browser || !db) return;
32
+ try {
33
+ const userList = await db.getRepository(UserEntity).toArray();
34
+ users.set(userList);
35
+ allUsers.set(userList);
36
+ } catch (error) {
37
+ console.error('Error loading users:', error);
38
+ }
39
+ }
40
+
41
+ export async function addUser() {
42
+ if (!browser || !db) return;
43
+ try {
44
+ const user = newEntity(UserEntity, {
45
+ name: `User ${Date.now()}`,
46
+ email: `user${Date.now()}@example.com`,
47
+ age: Math.floor(Math.random() * 50) + 18,
48
+ isActive: true,
49
+ tags: ['demo', 'svelte'],
50
+ metadata: { source: 'svelte-demo' },
51
+ createdAt: Date.now(),
52
+ updatedAt: Date.now(),
53
+ });
54
+
55
+ await db.saveWithRelations({
56
+ entity: user,
57
+ entityClass: UserEntity,
58
+ });
59
+
60
+ await loadUsers();
61
+ alert('User added successfully!');
62
+ } catch (error) {
63
+ console.error('Error adding user:', error);
64
+ alert('Error adding user: ' + error.message);
65
+ }
66
+ }
67
+
68
+ export async function testZodValidation() {
69
+ if (!browser || !db) return;
70
+ try {
71
+ console.log('Testing Zod validation...');
72
+
73
+ // Test 1: Manual validation of an invalid object
74
+ console.log('Test 1: Manual validation of invalid object');
75
+ const invalidUser = newEntity(UserEntity, {
76
+ name: 'A', // Too short (min 2 chars)
77
+ email: 'invalid-email', // Invalid email
78
+ age: 15, // Too young (min 18)
79
+ tags: ['test'],
80
+ metadata: { source: 'validation-test' },
81
+ createdAt: Date.now(),
82
+ updatedAt: Date.now(),
83
+ });
84
+
85
+ console.log('Object to validate:', invalidUser);
86
+
87
+ // Manual call to .validate() on the object
88
+ const validationResult = invalidUser.validate();
89
+ console.log('Validation result:', validationResult);
90
+
91
+ if (!validationResult.isValid) {
92
+ console.log('Validation errors:');
93
+ validationResult.errors.forEach((error, index) => {
94
+ console.log(` ${index + 1}. ${error}`);
95
+ });
96
+ }
97
+
98
+ // Test 2: Manual validation of a valid object
99
+ console.log('\nTest 2: Manual validation of a valid object');
100
+ const validUser = newEntity(UserEntity, {
101
+ name: 'John Doe', // Valid
102
+ email: 'john@example.com', // Valid
103
+ age: 25, // Valid
104
+ tags: ['developer', 'typescript'],
105
+ metadata: { source: 'validation-test', role: 'admin' },
106
+ createdAt: Date.now(),
107
+ updatedAt: Date.now(),
108
+ });
109
+
110
+ console.log('Object to validate:', validUser);
111
+
112
+ const validResult = validUser.validate();
113
+ console.log('Validation result:', validResult);
114
+
115
+ if (validResult.isValid) {
116
+ console.log('Validation passed successfully!');
117
+
118
+ // Add the valid user to the DB
119
+ const userRepository = db.getRepository(UserEntity);
120
+ await userRepository.add(validUser);
121
+ console.log('Valid user added to the database');
122
+ await loadUsers();
123
+ }
124
+
125
+ // Test 3: validateOrThrow() - throwing errors
126
+ console.log('\nTest 3: validateOrThrow() - throwing errors');
127
+ try {
128
+ invalidUser.validateOrThrow();
129
+ console.log(
130
+ 'validateOrThrow() did not throw - this should not happen',
131
+ );
132
+ } catch (error) {
133
+ console.log(
134
+ 'validateOrThrow() threw as expected:',
135
+ error.message,
136
+ );
137
+ }
138
+
139
+ alert(
140
+ `Validation test finished!\n\nInvalid object:
141
+ ${validationResult.errors.length} errors\n` +
142
+ `Valid object: ${validResult.isValid ? 'OK' : 'ERRORS'}\n\nCheck console for details.`,
143
+ );
144
+ } catch (error) {
145
+ console.log('Zod validation caught the error:', error);
146
+ alert(`Zod validation working! Error: ${error.message}`);
147
+ }
148
+ }
149
+
150
+ export async function testSchemaMigration() {
151
+ if (!browser || !db) return;
152
+ try {
153
+ console.log('Testing schema migration...');
154
+
155
+ // Check if schema has changed
156
+ const hasChanged = await db.checkSchemaChanges();
157
+
158
+ if (hasChanged) {
159
+ alert('Schema changed! Database was reset.');
160
+ await loadUsers(); // Reload data
161
+ } else {
162
+ alert('No schema changes detected.');
163
+ }
164
+ } catch (error) {
165
+ console.error('Schema migration test error:', error);
166
+ alert(`Schema migration test error: ${error.message}`);
167
+ }
168
+ }
169
+
170
+ export async function toggleAutoReset() {
171
+ if (!browser) return;
172
+ try {
173
+ // Show current status
174
+ const currentStatus =
175
+ localStorage.getItem('DexieORMDemo_auto_reset') !== 'false';
176
+
177
+ const newStatus = !currentStatus;
178
+ localStorage.setItem('DexieORMDemo_auto_reset', newStatus.toString());
179
+
180
+ alert(
181
+ `Auto-reset ${newStatus ? 'enabled' : 'disabled'}! ${
182
+ newStatus
183
+ ? 'Database will reset on schema changes.'
184
+ : 'Database will not reset on schema changes.'
185
+ }`,
186
+ );
187
+ } catch (error) {
188
+ console.error('Error toggling auto-reset:', error);
189
+ alert(`Error toggling auto-reset: ${error.message}`);
190
+ }
191
+ }
192
+
193
+ export async function testTransactions() {
194
+ if (!browser || !db) return;
195
+ try {
196
+ console.log('Testing Dexie transactions with our ORM...');
197
+
198
+ // Test 1: Simple transaction using Dexie's transaction method
199
+ const result = await db.transaction(
200
+ 'rw',
201
+ [db.getRepository(UserEntity), db.getRepository(ProfileEntity)],
202
+ async (trans) => {
203
+ // Create user
204
+ const user = newEntity(UserEntity, {
205
+ name: 'Transaction Test User',
206
+ email: `transaction-${Date.now()}@example.com`,
207
+ age: 30,
208
+ tags: ['transaction-test'],
209
+ metadata: { source: 'transaction-test' },
210
+ createdAt: Date.now(),
211
+ updatedAt: Date.now(),
212
+ });
213
+
214
+ const userId = await trans.table('users').add(user);
215
+ console.log('User created in transaction:', userId);
216
+
217
+ // Create profile for the user
218
+ const profile = newEntity(ProfileEntity, {
219
+ userId: userId,
220
+ bio: 'Transaction test profile',
221
+ avatar: 'https://example.com/avatar.jpg',
222
+ website: 'https://example.com',
223
+ location: 'Test City',
224
+ createdAt: Date.now(),
225
+ updatedAt: Date.now(),
226
+ });
227
+
228
+ const profileId = await trans.table('profiles').add(profile);
229
+ console.log('Profile created in transaction:', profileId);
230
+
231
+ return { userId, profileId };
232
+ },
233
+ );
234
+
235
+ console.log('Transaction completed successfully:', result);
236
+
237
+ // Test 2: Read-only transaction
238
+ const userCount = await db.transaction(
239
+ 'r',
240
+ [db.getRepository(UserEntity)],
241
+ async (trans) => {
242
+ const users = await trans.table('users').toArray();
243
+ console.log('Users read in read-only transaction:', users.length);
244
+
245
+ return users.length;
246
+ },
247
+ );
248
+
249
+ console.log('Read transaction completed, user count:', userCount);
250
+
251
+ // Test 3: Transaction with error (rollback)
252
+ try {
253
+ await db.transaction('rw', [db.getRepository(UserEntity)], async (trans) => {
254
+ const user = newEntity(UserEntity, {
255
+ name: 'Rollback Test User',
256
+ email: `rollback-${Date.now()}@example.com`,
257
+ age: 25,
258
+ tags: ['rollback-test'],
259
+ metadata: { source: 'rollback-test' },
260
+ createdAt: Date.now(),
261
+ updatedAt: Date.now(),
262
+ });
263
+
264
+ await trans.table('users').add(user);
265
+ console.log('User added before error');
266
+
267
+ // Simulate error
268
+ throw new Error('Simulated transaction error');
269
+ });
270
+ } catch (error) {
271
+ console.log(
272
+ 'Transaction rolled back as expected:',
273
+ error.message,
274
+ );
275
+ }
276
+
277
+ alert('Transactions test completed! Check console for details.');
278
+ await loadUsers();
279
+ } catch (error) {
280
+ console.error('Error testing transactions:', error);
281
+ alert(`Transactions test error: ${error.message}`);
282
+ }
283
+ }
284
+
285
+ export async function testCompoundIndexes() {
286
+ if (!browser || !db) return;
287
+ try {
288
+ console.log('Testing compound indexes...');
289
+
290
+ // Test 1: Query using compound index (name + email)
291
+ console.log('Test 1: Query using compound index (name + email)');
292
+ const usersByNameEmail = await db
293
+ .getRepository(UserEntity)
294
+ .where(['name', 'email'])
295
+ .equals(['John Doe', 'john@example.com'])
296
+ .toArray();
297
+ console.log('Users by name+email:', usersByNameEmail);
298
+
299
+ // Test 2: Query using compound index (age + isActive)
300
+ console.log('Test 2: Query using compound index (age + isActive)');
301
+ const activeAdults = await db
302
+ .getRepository(UserEntity)
303
+ .where(['age', 'isActive'])
304
+ .above([18, 1])
305
+ .toArray();
306
+ console.log('Active adults (age > 18, isActive = true):', activeAdults);
307
+
308
+ // Test 3: Query using unique compound index (email)
309
+ console.log('Test 3: Query using unique compound index (email)');
310
+ const userByEmail = await db
311
+ .getRepository(UserEntity)
312
+ .where('email')
313
+ .equals('john@example.com')
314
+ .first();
315
+ console.log('User by email:', userByEmail);
316
+
317
+ // Test 4: Add some test data to demonstrate compound indexes
318
+ console.log('Test 4: Adding test data for compound indexes');
319
+ const testUser1 = newEntity(UserEntity, {
320
+ name: 'Alice Smith',
321
+ email: 'alice@example.com',
322
+ age: 25,
323
+ isActive: true,
324
+ tags: ['test'],
325
+ metadata: { source: 'compound-test' },
326
+ createdAt: Date.now(),
327
+ updatedAt: Date.now(),
328
+ });
329
+
330
+ const testUser2 = newEntity(UserEntity, {
331
+ name: 'Bob Johnson',
332
+ email: 'bob@example.com',
333
+ age: 30,
334
+ isActive: false,
335
+ tags: ['test'],
336
+ metadata: { source: 'compound-test' },
337
+ createdAt: Date.now(),
338
+ updatedAt: Date.now(),
339
+ });
340
+
341
+ await db.getRepository(UserEntity).bulkAdd([testUser1, testUser2]);
342
+ console.log('Test users added');
343
+
344
+ // Test 5: Query with compound index after adding data
345
+ console.log('Test 5: Query with compound index after adding data');
346
+ const allActiveUsers = await db
347
+ .getRepository(UserEntity)
348
+ .where('isActive')
349
+ .equals(1)
350
+ .toArray();
351
+ console.log('All active users:', allActiveUsers);
352
+
353
+ await loadUsers();
354
+ alert('Compound indexes test completed! Check console for details.');
355
+ } catch (error) {
356
+ console.error('Error testing compound indexes:', error);
357
+ alert(`Compound indexes test error: ${error.message}`);
358
+ }
359
+ }
360
+
361
+ export async function testRelations() {
362
+ if (!browser || !db) return;
363
+ try {
364
+ console.log('Testing relations...');
365
+
366
+ // Clear existing test data first
367
+ console.log('Clearing existing test data...');
368
+ // Get all users and filter by metadata.source in JavaScript
369
+ const allUsersData = await db.getRepository(UserEntity).toArray();
370
+ const testUsers = allUsersData.filter(user => user.metadata?.source === 'relation-test');
371
+ if (testUsers.length > 0) {
372
+ await db.getRepository(UserEntity).bulkDelete(testUsers.map(u => u.id));
373
+ }
374
+ await db.getRepository(ProfileEntity).where('bio').equals('Full-stack developer').delete();
375
+ await db.getRepository(PostEntity).where('title').startsWith('My First Post').delete();
376
+ await db.getRepository(PostEntity).where('title').startsWith('Learning Dexie ORM').delete();
377
+ await db.getRepository(TagEntity).where('name').equals('javascript').delete();
378
+ await db.getRepository(TagEntity).where('name').equals('typescript').delete();
379
+
380
+ // Create a user with profile and posts
381
+ const user = newEntity(UserEntity, {
382
+ name: 'John Doe',
383
+ email: `john+${Date.now()}@example.com`, // Unique email to avoid conflicts
384
+ age: 30,
385
+ tags: ['developer'],
386
+ metadata: { source: 'relation-test' },
387
+ createdAt: Date.now(),
388
+ updatedAt: Date.now(),
389
+ });
390
+
391
+ // Create profile
392
+ newEntity(ProfileEntity, {
393
+ bio: 'Full-stack developer',
394
+ avatar: 'https://example.com/avatar.jpg',
395
+ website: 'https://johndoe.com',
396
+ location: 'New York',
397
+ createdAt: Date.now(),
398
+ updatedAt: Date.now(),
399
+ });
400
+
401
+ // Create posts
402
+ newEntity(PostEntity, {
403
+ title: 'My First Post',
404
+ content: 'This is my first blog post about Dexie ORM!',
405
+ published: true,
406
+ likes: 42,
407
+ postTags: ['javascript', 'dexie'],
408
+ createdAt: Date.now(),
409
+ updatedAt: Date.now(),
410
+ });
411
+
412
+ newEntity(PostEntity, {
413
+ title: 'Learning Dexie ORM',
414
+ content: 'Learning how to use Dexie ORM with TypeScript and Zod validation.',
415
+ published: false,
416
+ likes: 15,
417
+ postTags: ['typescript', 'orm'],
418
+ createdAt: Date.now(),
419
+ updatedAt: Date.now(),
420
+ });
421
+
422
+ console.log('Saving user with relations...');
423
+ const savedUser = await db.saveWithRelations({
424
+ entity: user,
425
+ entityClass: UserEntity,
426
+ });
427
+
428
+ // Load user with all relations
429
+ await db.loadRelations({
430
+ entity: savedUser,
431
+ entityClass: UserEntity,
432
+ relationNames: ['profile', 'posts'],
433
+ });
434
+
435
+ // Load user with only specific relations
436
+ const userWithProfileOnly = await db.loadRelations({
437
+ entity: savedUser,
438
+ entityClass: UserEntity,
439
+ relationNames: ['profile'],
440
+ });
441
+ console.log('User with profile only:', userWithProfileOnly);
442
+
443
+ // Load single relation by name
444
+ const userProfile = await db.loadRelationByName({
445
+ entity: savedUser,
446
+ entityClass: UserEntity,
447
+ relationName: 'profile',
448
+ });
449
+ console.log('Profile loaded separately:', userProfile);
450
+
451
+ alert('Relations test completed! Check console for details.');
452
+ await loadUsers();
453
+ } catch (error) {
454
+ console.error('Error testing relations:', error);
455
+ alert(`Relations test error: ${error.message}`);
456
+ }
457
+ }
458
+
459
+ export async function testAggregations() {
460
+ if (!browser || !db) return;
461
+ try {
462
+ console.log('Testing aggregations...');
463
+
464
+ // Test 1: Basic statistics
465
+ console.log('Test 1: Basic user statistics');
466
+ const userStatsData = await db.aggregate({
467
+ entityClass: UserEntity,
468
+ options: {
469
+ count: true,
470
+ avg: ['age'],
471
+ min: ['age'],
472
+ max: ['age'],
473
+ },
474
+ });
475
+ console.log('User stats:', userStatsData);
476
+
477
+ // Test 2: Group by age
478
+ console.log('Test 2: Users grouped by age');
479
+ const usersByAge = await db.aggregate({
480
+ entityClass: UserEntity,
481
+ options: {
482
+ groupBy: 'age',
483
+ count: true,
484
+ avg: ['age'],
485
+ },
486
+ });
487
+ console.log('Users by age:', usersByAge);
488
+
489
+ // Test 3: Active users only
490
+ console.log('Test 3: Active users statistics');
491
+ const activeUserStats = await db.aggregate({
492
+ entityClass: UserEntity,
493
+ options: {
494
+ where: { isActive: true },
495
+ count: true,
496
+ avg: ['age'],
497
+ },
498
+ });
499
+ console.log('Active user stats:', activeUserStats);
500
+
501
+ // Test 4: Post statistics
502
+ console.log('Test 4: Post statistics');
503
+ const postStatsData = await db.aggregate({
504
+ entityClass: PostEntity,
505
+ options: {
506
+ where: { published: true },
507
+ count: true,
508
+ sum: ['likes'],
509
+ avg: ['likes'],
510
+ },
511
+ });
512
+ console.log('Post stats:', postStatsData);
513
+
514
+ // Test 5: Posts grouped by author
515
+ console.log('Test 5: Posts grouped by author');
516
+ const postsByAuthor = await db.aggregate({
517
+ entityClass: PostEntity,
518
+ options: {
519
+ groupBy: 'authorId',
520
+ count: true,
521
+ sum: ['likes'],
522
+ },
523
+ });
524
+ console.log('Posts by author:', postsByAuthor);
525
+
526
+ // Test 6: Top 5 oldest users
527
+ console.log('Test 6: Top 5 oldest users');
528
+ const oldestUsers = await db.aggregate({
529
+ entityClass: UserEntity,
530
+ options: {
531
+ sort: { field: 'createdAt', direction: 'asc' },
532
+ limit: 5,
533
+ },
534
+ });
535
+ console.log('Oldest users:', oldestUsers);
536
+
537
+ alert(
538
+ 'Aggregations test completed! Check console for detailed results.',
539
+ );
540
+ await loadUsers();
541
+ } catch (error) {
542
+ console.error('Error testing aggregations:', error);
543
+ alert(`Aggregations test error: ${error.message}`);
544
+ }
545
+ }
546
+
547
+ export async function clearAll() {
548
+ if (!browser || !db) return;
549
+ try {
550
+ await db.getRepository(UserEntity).clear();
551
+ await db.getRepository(PostEntity).clear();
552
+ await db.getRepository(ProfileEntity).clear();
553
+ await db.getRepository(TagEntity).clear();
554
+ await loadUsers();
555
+ alert('All data cleared!');
556
+ } catch (error) {
557
+ console.error('Error clearing data:', error);
558
+ alert(`Error clearing data: ${error.message}`);
559
+ }
560
+ }
561
+
562
+ export async function loadLiveQueryData() {
563
+ if (!browser || !db) return;
564
+ try {
565
+ // Load all users
566
+ const userList = await db.getRepository(UserEntity).toArray();
567
+ allUsers.set(userList);
568
+
569
+ // Load adult users
570
+ const adultUsersData = await db.getRepository(UserEntity).where('age').above(18).toArray();
571
+
572
+ // Load user count
573
+ const userCount = await db.getRepository(UserEntity).count();
574
+
575
+ // Load first user
576
+ const firstUserData = await db.getRepository(UserEntity).orderBy('id').first();
577
+
578
+ // Load all posts
579
+ const postList = await db.getRepository(PostEntity).toArray();
580
+ allPosts.set(postList);
581
+
582
+ // Load all profiles
583
+ const profileList = await db.getRepository(ProfileEntity).toArray();
584
+ allProfiles.set(profileList);
585
+
586
+ // Update user stats
587
+ userStats.set({
588
+ totalUsers: userCount,
589
+ adultUsers: adultUsersData.length,
590
+ firstUser: firstUserData?.name || 'None'
591
+ });
592
+
593
+ // Update post stats
594
+ const total = await db.getRepository(PostEntity).count();
595
+ const published = await db.getRepository(PostEntity).where('published').equals(1).count();
596
+ const allPostsData = await db.getRepository(PostEntity).toArray();
597
+ const totalLikes = allPostsData.reduce((sum, post) => sum + (post.likes || 0), 0);
598
+
599
+ postStats.set({ total, published, totalLikes });
600
+ } catch (error) {
601
+ console.error('Error loading live query data:', error);
602
+ }
603
+ }
@@ -0,0 +1,18 @@
1
+ import adapter from '@sveltejs/adapter-auto';
2
+
3
+ /** @type {import('@sveltejs/kit').Config} */
4
+ const config = {
5
+ kit: {
6
+ adapter: adapter(),
7
+ // Disable SSR for IndexedDB compatibility
8
+ prerender: {
9
+ handleHttpError: 'warn'
10
+ }
11
+ },
12
+ // Disable SSR for client-side only rendering
13
+ ssr: {
14
+ noExternal: ['idb-orm']
15
+ }
16
+ };
17
+
18
+ export default config;
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "./.svelte-kit/tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "checkJs": true,
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "resolveJsonModule": true,
9
+ "skipLibCheck": true,
10
+ "sourceMap": true,
11
+ "strict": true,
12
+ "allowSyntheticDefaultImports": true
13
+ }
14
+ }
@@ -0,0 +1,6 @@
1
+ import { sveltekit } from '@sveltejs/kit/vite';
2
+ import { defineConfig } from 'vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()]
6
+ });