@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,136 @@
1
+ <template>
2
+ <v-card
3
+ variant="outlined"
4
+ class="my-4"
5
+ style="border: 2px solid #9c27b0; background-color: #faf5ff;"
6
+ >
7
+ <v-card-title class="d-flex align-center">
8
+ <v-icon class="mr-2" color="primary">mdi-code-json</v-icon>
9
+ Posts useLiveQuery Demo
10
+ </v-card-title>
11
+ <v-card-text>
12
+ <v-btn
13
+ color="purple"
14
+ variant="elevated"
15
+ @click="addSamplePost"
16
+ class="mb-4"
17
+ >
18
+ Add sample post
19
+ </v-btn>
20
+
21
+ <v-row>
22
+ <v-col cols="12" md="4">
23
+ <v-card variant="outlined" class="h-100">
24
+ <v-card-title class="d-flex align-center">
25
+ <v-icon class="mr-2" color="primary">mdi-chart-bar</v-icon>
26
+ Statistics
27
+ </v-card-title>
28
+ <v-card-text>
29
+ <div v-if="postStats">
30
+ <p><strong>Total posts:</strong> {{ postStats.total }}</p>
31
+ <p><strong>Published:</strong> {{ postStats.published }}</p>
32
+ <p><strong>Total likes:</strong> {{ postStats.totalLikes }}</p>
33
+ </div>
34
+ <div v-else>
35
+ <p>Loading statistics...</p>
36
+ </div>
37
+ </v-card-text>
38
+ </v-card>
39
+ </v-col>
40
+
41
+ <v-col cols="12" md="4">
42
+ <v-card variant="outlined" class="h-100">
43
+ <v-card-title class="d-flex align-center">
44
+ <v-icon class="mr-2" color="primary">mdi-trending-up</v-icon>
45
+ Top 3 posts
46
+ </v-card-title>
47
+ <v-card-text>
48
+ <div v-if="topPosts && topPosts.length > 0">
49
+ <v-card
50
+ v-for="(post, index) in topPosts"
51
+ :key="post.id"
52
+ variant="outlined"
53
+ class="mb-2 pa-2"
54
+ >
55
+ <strong>#{{ index + 1 }}</strong> {{ post.title }}
56
+ <span style="color: #9c27b0"> ❤️ {{ post.likes }}</span>
57
+ </v-card>
58
+ </div>
59
+ </v-card-text>
60
+ </v-card>
61
+ </v-col>
62
+
63
+ <v-col cols="12" md="4">
64
+ <v-card variant="outlined" class="h-100">
65
+ <v-card-title>Published posts</v-card-title>
66
+ <v-card-text>
67
+ <div v-if="publishedPosts && publishedPosts.length > 0" class="overflow-y-auto" style="max-height: 150px;">
68
+ <div
69
+ v-for="post in publishedPosts"
70
+ :key="post.id"
71
+ class="py-1 border-b text-caption"
72
+ >
73
+ <strong>{{ post.title }}</strong> ❤️ {{ post.likes }}
74
+ </div>
75
+ </div>
76
+ </v-card-text>
77
+ </v-card>
78
+ </v-col>
79
+ </v-row>
80
+
81
+ <div v-if="allPosts && allPosts.length > 0" class="mt-4">
82
+ <h3 class="d-flex align-center mb-2">
83
+ <v-icon class="mr-2" color="primary">mdi-format-list-bulleted</v-icon>
84
+ All posts (newest first)
85
+ </h3>
86
+ <v-card variant="outlined" class="overflow-y-auto" style="max-height: 200px;">
87
+ <v-card-text>
88
+ <div
89
+ v-for="post in allPosts"
90
+ :key="post.id"
91
+ class="py-2 border-b text-caption"
92
+ >
93
+ <div class="d-flex justify-space-between align-center">
94
+ <div>
95
+ <strong>{{ post.title }}</strong>
96
+ <v-chip
97
+ :color="post.published ? 'success' : 'warning'"
98
+ size="x-small"
99
+ class="ml-2"
100
+ >
101
+ {{ post.published ? 'Published' : 'Draft' }}
102
+ </v-chip>
103
+ </div>
104
+ <div style="color: #9c27b0">❤️ {{ post.likes }}</div>
105
+ </div>
106
+ <div class="text-medium-emphasis mt-1">
107
+ {{ post.content?.substring(0, 100) }}...
108
+ </div>
109
+ </div>
110
+ </v-card-text>
111
+ </v-card>
112
+ </div>
113
+
114
+ <v-alert
115
+ type="info"
116
+ variant="tonal"
117
+ class="mt-4"
118
+ prepend-icon="mdi-lightbulb"
119
+ >
120
+ <strong>Note:</strong> All data updates automatically! Add a post and see how all sections refresh in real time.
121
+ </v-alert>
122
+ </v-card-text>
123
+ </v-card>
124
+ </template>
125
+
126
+ <script setup lang="ts">
127
+ import { usePostsLiveQueryDemo } from '../services/usePostsLiveQueryDemo';
128
+
129
+ const {
130
+ allPosts,
131
+ publishedPosts,
132
+ topPosts,
133
+ postStats,
134
+ addSamplePost,
135
+ } = usePostsLiveQueryDemo();
136
+ </script>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <v-card
3
+ variant="outlined"
4
+ class="my-4"
5
+ style="border: 2px solid #ff9800; background-color: #fff8e1;"
6
+ >
7
+ <v-card-title class="d-flex align-center">
8
+ <v-icon class="mr-2" color="primary">mdi-code-tags</v-icon>
9
+ TypeScript Typing Test
10
+ </v-card-title>
11
+ <v-card-text>
12
+ <p class="text-body-2 text-medium-emphasis mb-4">
13
+ <strong>Instructions:</strong>
14
+ Hover over the variables below in your IDE and
15
+ verify TypeScript shows full types! Click items to
16
+ see auto-complete in the console.
17
+ </p>
18
+
19
+ <v-row>
20
+ <v-col cols="12" md="4">
21
+ <v-card variant="outlined" class="h-100">
22
+ <v-card-title class="d-flex align-center">
23
+ <v-icon class="mr-2" color="primary">mdi-account-group</v-icon>
24
+ Users (UserEntity[])
25
+ </v-card-title>
26
+ <v-card-text>
27
+ <p class="text-caption text-medium-emphasis mb-2">
28
+ Type: <code>UserEntity[] | undefined</code>
29
+ </p>
30
+ <v-card v-if="users && users.length > 0" variant="outlined" class="overflow-y-auto" style="max-height: 150px;">
31
+ <v-card-text>
32
+ <div
33
+ v-for="user in users"
34
+ :key="user.id"
35
+ @click="handleUserClick(user)"
36
+ class="py-1 border-b cursor-pointer hover:bg-grey-lighten-4"
37
+ title="Click to see auto-complete in the console"
38
+ >
39
+ <strong>{{ user.name }}</strong> - {{ user.email }}
40
+ </div>
41
+ </v-card-text>
42
+ </v-card>
43
+ </v-card-text>
44
+ </v-card>
45
+ </v-col>
46
+
47
+ <v-col cols="12" md="4">
48
+ <v-card variant="outlined" class="h-100">
49
+ <v-card-title class="d-flex align-center">
50
+ <v-icon class="mr-2" color="primary">mdi-file-document</v-icon>
51
+ Posts (PostEntity[])
52
+ </v-card-title>
53
+ <v-card-text>
54
+ <p class="text-caption text-medium-emphasis mb-2">
55
+ Type: <code>PostEntity[] | undefined</code>
56
+ </p>
57
+ <v-card v-if="posts && posts.length > 0" variant="outlined" class="overflow-y-auto" style="max-height: 150px;">
58
+ <v-card-text>
59
+ <div
60
+ v-for="post in posts"
61
+ :key="post.id"
62
+ @click="handlePostClick(post)"
63
+ class="py-1 border-b cursor-pointer hover:bg-grey-lighten-4"
64
+ title="Click to see auto-complete in the console"
65
+ >
66
+ <strong>{{ post.title }}</strong> - {{ post.published ? 'Published' : 'Draft' }}
67
+ </div>
68
+ </v-card-text>
69
+ </v-card>
70
+ </v-card-text>
71
+ </v-card>
72
+ </v-col>
73
+
74
+ <v-col cols="12" md="4">
75
+ <v-card variant="outlined" class="h-100">
76
+ <v-card-title class="d-flex align-center">
77
+ <v-icon class="mr-2" color="primary">mdi-account-circle</v-icon>
78
+ Profiles (ProfileEntity[])
79
+ </v-card-title>
80
+ <v-card-text>
81
+ <p class="text-caption text-medium-emphasis mb-2">
82
+ Type: <code>ProfileEntity[] | undefined</code>
83
+ </p>
84
+ <v-card v-if="profiles && profiles.length > 0" variant="outlined" class="overflow-y-auto" style="max-height: 150px;">
85
+ <v-card-text>
86
+ <div
87
+ v-for="profile in profiles"
88
+ :key="profile.id"
89
+ @click="handleProfileClick(profile)"
90
+ class="py-1 border-b cursor-pointer hover:bg-grey-lighten-4"
91
+ title="Click to see auto-complete in the console"
92
+ >
93
+ <strong>User {{ profile.userId }}</strong> -
94
+ {{ profile.bio?.substring(0, 30) }}...
95
+ </div>
96
+ </v-card-text>
97
+ </v-card>
98
+ </v-card-text>
99
+ </v-card>
100
+ </v-col>
101
+ </v-row>
102
+
103
+ <v-card variant="outlined" class="mt-4" color="primary">
104
+ <v-card-text>
105
+ <div class="text-body-2 text-medium-emphasis">
106
+ <div class="font-weight-bold">IDE Test:</div>
107
+ <br />
108
+ 1. Hover over variables <code>users</code>, <code>posts</code>, <code>profiles</code>
109
+ <br />
110
+ 2. Verify TypeScript shows full types: (UserEntity[], PostEntity[], ProfileEntity[])
111
+ <br />
112
+ 3. Click items to see auto-complete inside handle* functions
113
+ <br />
114
+ 4. Check that IDE suggests properties like <code>user.name</code>, <code>post.title</code>, <code>profile.bio</code>
115
+ </div>
116
+ </v-card-text>
117
+ </v-card>
118
+ </v-card-text>
119
+ </v-card>
120
+ </template>
121
+
122
+ <script setup lang="ts">
123
+ import { useTypeScriptDemo } from '../services/useTypeScriptDemo';
124
+
125
+ const {
126
+ users,
127
+ posts,
128
+ profiles,
129
+ handleUserClick,
130
+ handlePostClick,
131
+ handleProfileClick,
132
+ } = useTypeScriptDemo();
133
+ </script>
@@ -0,0 +1,29 @@
1
+ import { Database } from 'idb-orm';
2
+
3
+ import { PostEntity } from '../entities/Post';
4
+ import { PostTagEntity } from '../entities/PostTag';
5
+ import { ProfileEntity } from '../entities/Profile';
6
+ import { TagEntity } from '../entities/Tag';
7
+ import { UserEntity } from '../entities/User';
8
+ import { migrations } from '../migrations';
9
+
10
+ // Create database with entity registration
11
+ export const db = Database.createDatabase({
12
+ name: 'DexieORMDemo',
13
+ version: 6,
14
+ entities: [UserEntity, PostEntity, ProfileEntity, TagEntity, PostTagEntity],
15
+ config: {
16
+ // This will be ignored when migrations are provided
17
+ // onSchemaChangeStrategy: 'selective',
18
+ migrations: migrations, // Migrations take priority over reset strategy
19
+
20
+ // Cloud sync configuration (optional)
21
+ // cloudSync: {
22
+ // databaseUrl: 'https://your-database-url.dexie.cloud', // Replace with your actual URL
23
+ // enableOfflineSupport: true,
24
+ // syncInterval: 30000, // Sync every 30 seconds (optional)
25
+ // tables: ['users', 'posts', 'profiles'] // Specific tables to sync
26
+ // (optional - syncs all if empty)
27
+ // }
28
+ },
29
+ });
@@ -0,0 +1,48 @@
1
+ import {
2
+ BaseEntity, defineEntity,
3
+ } from 'idb-orm';
4
+ import { z } from 'zod';
5
+
6
+ import type { TagEntity } from './Tag';
7
+
8
+ const PostSchema = z.object({
9
+ id: z.number().optional(),
10
+ title: z.string().min(1, 'Title is required'),
11
+ content: z.string().min(1, 'Content is required'),
12
+ authorId: z.number().positive('Author ID must be positive'),
13
+ published: z.boolean().optional(),
14
+ postTags: z.array(z.string()).optional(),
15
+ likes: z.number().min(0, 'Likes must be non-negative').optional(),
16
+ createdAt: z.number().optional(),
17
+ updatedAt: z.number().optional(),
18
+ });
19
+
20
+ export class PostEntity extends BaseEntity<number> {
21
+ title!: string;
22
+ content!: string;
23
+ authorId!: number;
24
+ published?: boolean;
25
+ postTags?: string[];
26
+ likes?: number;
27
+ createdAt?: number;
28
+ updatedAt?: number;
29
+ tags?: TagEntity[];
30
+ }
31
+
32
+ defineEntity(PostEntity, {
33
+ tableName: 'posts',
34
+ schema: PostSchema,
35
+ columns: {
36
+ title: { required: true, indexed: true },
37
+ content: { required: true },
38
+ authorId: { required: true, indexed: true },
39
+ published: { default: false, indexed: true },
40
+ postTags: {},
41
+ likes: { default: 0, indexed: true },
42
+ createdAt: { default: () => Date.now(), indexed: true },
43
+ updatedAt: { default: () => Date.now() },
44
+ },
45
+ relations: {
46
+ tags: { type: 'many-to-many', target: 'tags', joinTable: 'post_tags' },
47
+ },
48
+ });
@@ -0,0 +1,24 @@
1
+ import {
2
+ BaseEntity, defineEntity,
3
+ } from 'idb-orm';
4
+ import { z } from 'zod';
5
+
6
+ const PostTagSchema = z.object({
7
+ id: z.number().optional(),
8
+ sourceId: z.number(),
9
+ targetId: z.number(),
10
+ });
11
+
12
+ export class PostTagEntity extends BaseEntity<number> {
13
+ sourceId!: number;
14
+ targetId!: number;
15
+ }
16
+
17
+ defineEntity(PostTagEntity, {
18
+ tableName: 'post_tags',
19
+ schema: PostTagSchema,
20
+ columns: {
21
+ sourceId: { indexed: true },
22
+ targetId: { indexed: true },
23
+ },
24
+ });
@@ -0,0 +1,41 @@
1
+ import {
2
+ BaseEntity, defineEntity,
3
+ } from 'idb-orm';
4
+ import { z } from 'zod';
5
+
6
+ const ProfileSchema = z.object({
7
+ id: z.number().optional(),
8
+ userId: z.number().positive('User ID must be positive'),
9
+ bio: z.string().optional(),
10
+ avatar: z.string().url().optional(),
11
+ website: z.string().url().optional(),
12
+ location: z.string().optional(),
13
+ createdAt: z.number(),
14
+ updatedAt: z.number(),
15
+ });
16
+
17
+ export type Profile = z.infer<typeof ProfileSchema>;
18
+
19
+ export class ProfileEntity extends BaseEntity<number> {
20
+ userId!: number;
21
+ bio?: string;
22
+ avatar?: string;
23
+ website?: string;
24
+ location?: string;
25
+ createdAt!: number;
26
+ updatedAt!: number;
27
+ }
28
+
29
+ defineEntity(ProfileEntity, {
30
+ tableName: 'profiles',
31
+ schema: ProfileSchema,
32
+ columns: {
33
+ userId: { indexed: true },
34
+ bio: { indexed: true },
35
+ avatar: {},
36
+ website: {},
37
+ location: {},
38
+ createdAt: { indexed: true },
39
+ updatedAt: { indexed: true },
40
+ },
41
+ });
@@ -0,0 +1,35 @@
1
+ import {
2
+ BaseEntity, defineEntity,
3
+ } from 'idb-orm';
4
+ import { z } from 'zod';
5
+
6
+ const TagSchema = z.object({
7
+ id: z.number().optional(),
8
+ name: z.string().min(1, 'Tag name is required'),
9
+ color: z.string().regex(/^#[0-9A-F]{6}$/i, 'Color must be a valid hex color'),
10
+ description: z.string().optional(),
11
+ createdAt: z.number(),
12
+ updatedAt: z.number(),
13
+ });
14
+
15
+ export type Tag = z.infer<typeof TagSchema>;
16
+
17
+ export class TagEntity extends BaseEntity<number> {
18
+ name!: string;
19
+ color!: string;
20
+ description?: string;
21
+ createdAt!: number;
22
+ updatedAt!: number;
23
+ }
24
+
25
+ defineEntity(TagEntity, {
26
+ tableName: 'tags',
27
+ schema: TagSchema,
28
+ columns: {
29
+ name: { required: true, unique: true, indexed: true },
30
+ color: { required: true },
31
+ description: {},
32
+ createdAt: { indexed: true },
33
+ updatedAt: { indexed: true },
34
+ },
35
+ });
@@ -0,0 +1,61 @@
1
+ import {
2
+ BaseEntity, defineEntity,
3
+ } from 'idb-orm';
4
+ import { z } from 'zod';
5
+
6
+ import type { PostEntity } from './Post';
7
+ import type { ProfileEntity } from './Profile';
8
+
9
+ // Zod schema for validation
10
+ export const UserSchema = z.object({
11
+ id: z.number().optional(),
12
+ name: z.string().min(2, 'Name must be at least 2 characters'),
13
+ email: z.string().email('Invalid email format'),
14
+ age: z.number().min(18, 'Must be at least 18 years old'),
15
+ createdAt: z.number(),
16
+ updatedAt: z.number(),
17
+ isActive: z.boolean().default(true),
18
+ tags: z.array(z.string()).default([]),
19
+ metadata: z.record(z.string(), z.unknown()).default({}),
20
+ // Note: '
21
+ // posts' and 'profile' relations are not in schema - they're loaded separately
22
+ });
23
+
24
+ export type User = z.infer<typeof UserSchema>;
25
+
26
+ export class UserEntity extends BaseEntity<number> {
27
+ name!: string;
28
+ email!: string;
29
+ age!: number;
30
+ createdAt!: number;
31
+ updatedAt!: number;
32
+ isActive!: boolean;
33
+ tags!: string[];
34
+ metadata!: Record<string, unknown>;
35
+ posts?: PostEntity[];
36
+ profile?: ProfileEntity;
37
+ }
38
+
39
+ defineEntity(UserEntity, {
40
+ tableName: 'users',
41
+ schema: UserSchema,
42
+ columns: {
43
+ name: { required: true, indexed: true },
44
+ email: { required: true, unique: true },
45
+ age: { indexed: true },
46
+ createdAt: { indexed: true },
47
+ updatedAt: { indexed: true },
48
+ isActive: { indexed: true },
49
+ tags: {},
50
+ metadata: { indexed: true },
51
+ },
52
+ compoundIndexes: [
53
+ { columns: ['name', 'email'], unique: false, name: 'name_email_index' },
54
+ { columns: ['age', 'isActive'], unique: false, name: 'age_active_index' },
55
+ { columns: ['email'], unique: true, name: 'unique_email_index' },
56
+ ],
57
+ relations: {
58
+ posts: { type: 'one-to-many', target: 'posts', foreignKey: 'authorId' },
59
+ profile: { type: 'one-to-one', target: 'profiles', foreignKey: 'userId' },
60
+ },
61
+ });
@@ -0,0 +1,29 @@
1
+ import 'vuetify/styles';
2
+ import '@mdi/font/css/materialdesignicons.css';
3
+
4
+ import { createApp } from 'vue';
5
+ import { createVuetify } from 'vuetify';
6
+ import * as components from 'vuetify/components';
7
+ import * as directives from 'vuetify/directives';
8
+ import {
9
+ aliases, mdi,
10
+ } from 'vuetify/iconsets/mdi';
11
+
12
+ import App from './App.vue';
13
+
14
+ const vuetify = createVuetify({
15
+ components,
16
+ directives,
17
+ icons: {
18
+ defaultSet: 'mdi',
19
+ aliases,
20
+ sets: {
21
+ mdi,
22
+ },
23
+ },
24
+ theme: {
25
+ defaultTheme: 'light',
26
+ },
27
+ });
28
+
29
+ createApp(App).use(vuetify).mount('#app');
@@ -0,0 +1,23 @@
1
+ // Migration type definition
2
+ interface Migration {
3
+ version: number;
4
+ name: string;
5
+ up: () => Promise<void>;
6
+ down: () => Promise<void>;
7
+ }
8
+
9
+ export const addUserEmailIndex: Migration = {
10
+ version: 1,
11
+ name: 'add-user-email-index',
12
+ up: async () => {
13
+ console.log('Adding email index to users table...');
14
+ // This migration would add an index to the email field
15
+ // In a real scenario, you might need to recreate the table with the new index
16
+ console.log('Email index added successfully');
17
+ },
18
+ down: async () => {
19
+ console.log('Removing email index from users table...');
20
+ // This would remove the index
21
+ console.log('Email index removed successfully');
22
+ },
23
+ };
@@ -0,0 +1,46 @@
1
+ // Migration type definition
2
+ interface Migration {
3
+ version: number;
4
+ name: string;
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ up: (_db: any) => Promise<void>;
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ down: (_db: any) => Promise<void>;
9
+ }
10
+
11
+ export const addPostCategory: Migration = {
12
+ version: 2,
13
+ name: 'add-post-category',
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ up: async (_db: any) => {
16
+ console.log('Adding category field to posts table...');
17
+
18
+ const posts = await _db.table('posts').toArray();
19
+ const updatedPosts = posts.map((post: Record<string, unknown>) => ({
20
+ ...post,
21
+ category: 'general',
22
+ }));
23
+
24
+ const postsRepo = _db.table('posts');
25
+ await postsRepo.clear();
26
+ await postsRepo.bulkAdd(updatedPosts);
27
+
28
+ console.log('Category field added to all existing posts');
29
+ },
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ down: async (_db: any) => {
32
+ console.log('Removing category field from posts table...');
33
+
34
+ const posts = await _db.table('posts').toArray();
35
+ const updatedPosts = posts
36
+ .map(({ _category, ...post }: Record<string, unknown>) => {
37
+ return post;
38
+ });
39
+
40
+ const postsRepo = _db.table('posts');
41
+ await postsRepo.clear();
42
+ await postsRepo.bulkAdd(updatedPosts);
43
+
44
+ console.log('Category field removed from all posts');
45
+ },
46
+ };
@@ -0,0 +1,14 @@
1
+ // Migration type definition
2
+ interface Migration {
3
+ version: number;
4
+ name: string;
5
+ up: (db?: any) => Promise<void>;
6
+ down: (db?: any) => Promise<void>;
7
+ }
8
+ import { addUserEmailIndex } from './001-add-user-email-index';
9
+ import { addPostCategory } from './002-add-post-category';
10
+
11
+ export const migrations: Migration[] = [
12
+ addUserEmailIndex,
13
+ addPostCategory,
14
+ ];