@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,95 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+
4
+ @Injectable({
5
+ providedIn: 'root',
6
+ })
7
+ export class CloudSyncService {
8
+ private syncStatusSubject = new BehaviorSubject<{
9
+ enabled: boolean;
10
+ isOnline?: boolean;
11
+ lastSync?: Date;
12
+ }>({
13
+ enabled: false,
14
+ isOnline: undefined,
15
+ lastSync: undefined,
16
+ });
17
+ private isLoadingSubject = new BehaviorSubject<boolean>(false);
18
+
19
+ public syncStatus$ = this.syncStatusSubject.asObservable();
20
+ public isLoading$ = this.isLoadingSubject.asObservable();
21
+
22
+ async handleManualSync(): Promise<void> {
23
+ this.isLoadingSubject.next(true);
24
+ this.syncStatusSubject.next({
25
+ ...this.syncStatusSubject.value,
26
+ lastSync: new Date(),
27
+ });
28
+
29
+ try {
30
+ // Simulate sync process
31
+ await new Promise(resolve => setTimeout(resolve, 2000));
32
+ this.syncStatusSubject.next({
33
+ ...this.syncStatusSubject.value,
34
+ lastSync: new Date(),
35
+ });
36
+ } catch (error) {
37
+ console.error('Sync error:', error);
38
+ } finally {
39
+ this.isLoadingSubject.next(false);
40
+ }
41
+ }
42
+
43
+ async handleEnableCloudSync(): Promise<void> {
44
+ this.isLoadingSubject.next(true);
45
+
46
+ try {
47
+ // Simulate enabling cloud sync
48
+ await new Promise(resolve => setTimeout(resolve, 1000));
49
+ this.syncStatusSubject.next({
50
+ enabled: true,
51
+ isOnline: true,
52
+ lastSync: new Date(),
53
+ });
54
+ } catch (error) {
55
+ console.error('Enable cloud sync error:', error);
56
+ } finally {
57
+ this.isLoadingSubject.next(false);
58
+ }
59
+ }
60
+
61
+ async handleDisableCloudSync(): Promise<void> {
62
+ this.isLoadingSubject.next(true);
63
+
64
+ try {
65
+ // Simulate disabling cloud sync
66
+ await new Promise(resolve => setTimeout(resolve, 1000));
67
+ this.syncStatusSubject.next({
68
+ enabled: false,
69
+ isOnline: false,
70
+ lastSync: this.syncStatusSubject.value.lastSync,
71
+ });
72
+ } catch (error) {
73
+ console.error('Disable cloud sync error:', error);
74
+ } finally {
75
+ this.isLoadingSubject.next(false);
76
+ }
77
+ }
78
+
79
+ async handleSyncTables(): Promise<void> {
80
+ this.isLoadingSubject.next(true);
81
+
82
+ try {
83
+ // Simulate table sync
84
+ await new Promise(resolve => setTimeout(resolve, 1500));
85
+ this.syncStatusSubject.next({
86
+ ...this.syncStatusSubject.value,
87
+ lastSync: new Date(),
88
+ });
89
+ } catch (error) {
90
+ console.error('Table sync error:', error);
91
+ } finally {
92
+ this.isLoadingSubject.next(false);
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,26 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Database } from 'idb-orm';
3
+
4
+ import { PostEntity } from '../entities/post.entity';
5
+ import { PostTagEntity } from '../entities/post-tag.entity';
6
+ import { ProfileEntity } from '../entities/profile.entity';
7
+ import { TagEntity } from '../entities/tag.entity';
8
+ import { UserEntity } from '../entities/user.entity';
9
+
10
+ @Injectable({
11
+ providedIn: 'root',
12
+ })
13
+ export class DatabaseService {
14
+ public db: Database;
15
+
16
+ constructor() {
17
+ this.db = Database.createDatabase({
18
+ name: 'DexieORMDemo',
19
+ version: 6,
20
+ entities: [UserEntity, PostEntity, ProfileEntity, TagEntity, PostTagEntity],
21
+ config: {
22
+ migrations: [],
23
+ },
24
+ });
25
+ }
26
+ }
@@ -0,0 +1,63 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+
4
+ import { ProfileEntity } from '../entities/profile.entity';
5
+ import { UserEntity } from '../entities/user.entity';
6
+ import { DatabaseService } from './database.service';
7
+
8
+ @Injectable({
9
+ providedIn: 'root',
10
+ })
11
+ export class LiveQueryService {
12
+ private _usersWithProfilesSubject =
13
+ new BehaviorSubject<(UserEntity & { profile?: ProfileEntity })[]>([]);
14
+ private allUsersSubject = new BehaviorSubject<UserEntity[]>([]);
15
+ private userStatsSubject = new BehaviorSubject<{
16
+ totalUsers: number;
17
+ adultUsers: number;
18
+ firstUser: string;
19
+ }>({ totalUsers: 0, adultUsers: 0, firstUser: '' });
20
+
21
+ public usersWithProfiles$ = this._usersWithProfilesSubject.asObservable();
22
+ public allUsers$ = this.allUsersSubject.asObservable();
23
+ public userStats$ = this.userStatsSubject.asObservable();
24
+
25
+ constructor(private _dbService: DatabaseService) {
26
+ this.loadData();
27
+ }
28
+
29
+ private async loadData(): Promise<void> {
30
+ try {
31
+ // Load users with profiles
32
+ const users = await this._dbService.db.getRepository(UserEntity).toArray();
33
+ const profiles = await this._dbService.
34
+ db.getRepository(ProfileEntity).toArray();
35
+
36
+ const usersWithProfiles = users.map(user => {
37
+ const profile = profiles.find(p => p.userId === user.id);
38
+
39
+ return Object.assign(user, { profile });
40
+ });
41
+
42
+ this._usersWithProfilesSubject.next(usersWithProfiles);
43
+ this.allUsersSubject.next(users);
44
+
45
+ // Calculate stats
46
+ const totalUsers = users.length;
47
+ const adultUsers = users.filter(u => u.age >= 18).length;
48
+ const firstUser = users[0]?.name || '';
49
+
50
+ this.userStatsSubject.next({
51
+ totalUsers,
52
+ adultUsers,
53
+ firstUser,
54
+ });
55
+ } catch (error) {
56
+ console.error('Error loading live query data:', error);
57
+ }
58
+ }
59
+
60
+ refresh(): void {
61
+ this.loadData();
62
+ }
63
+ }
@@ -0,0 +1,86 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { newEntity } from 'idb-orm';
3
+ import { BehaviorSubject } from 'rxjs';
4
+
5
+ import { PostEntity } from '../entities/post.entity';
6
+ import { DatabaseService } from './database.service';
7
+
8
+ @Injectable({
9
+ providedIn: 'root',
10
+ })
11
+ export class PostsLiveQueryService {
12
+ private allPostsSubject = new BehaviorSubject<PostEntity[]>([]);
13
+ private topPostsSubject = new BehaviorSubject<PostEntity[]>([]);
14
+ private publishedPostsSubject = new BehaviorSubject<PostEntity[]>([]);
15
+ private postStatsSubject = new BehaviorSubject<{
16
+ total: number;
17
+ published: number;
18
+ totalLikes: number;
19
+ }>({ total: 0, published: 0, totalLikes: 0 });
20
+
21
+ public allPosts$ = this.allPostsSubject.asObservable();
22
+ public topPosts$ = this.topPostsSubject.asObservable();
23
+ public publishedPosts$ = this.publishedPostsSubject.asObservable();
24
+ public postStats$ = this.postStatsSubject.asObservable();
25
+
26
+ constructor(private _dbService: DatabaseService) {
27
+ this.loadData();
28
+ }
29
+
30
+ private async loadData(): Promise<void> {
31
+ try {
32
+ const allPosts = await this._dbService.db.getRepository(PostEntity).toArray();
33
+ const topPosts = await this._dbService.db.getRepository(PostEntity)
34
+ .orderBy('likes')
35
+ .reverse()
36
+ .limit(3)
37
+ .toArray();
38
+ const publishedPosts = await this._dbService.db.getRepository(PostEntity)
39
+ .where('published').equals(1)
40
+ .toArray();
41
+
42
+ this.allPostsSubject.next(allPosts);
43
+ this.topPostsSubject.next(topPosts);
44
+ this.publishedPostsSubject.next(publishedPosts);
45
+
46
+ // Calculate stats
47
+ const totalPosts = allPosts.length;
48
+ const published = publishedPosts.length;
49
+ const totalLikes = allPosts.reduce((sum, post) => sum + (post.likes || 0), 0);
50
+
51
+ this.postStatsSubject.next({
52
+ total: totalPosts,
53
+ published,
54
+ totalLikes,
55
+ });
56
+ } catch (error) {
57
+ console.error('Error loading posts live query data:', error);
58
+ }
59
+ }
60
+
61
+ async addSamplePost(): Promise<void> {
62
+ try {
63
+ const post = newEntity(PostEntity, {
64
+ title: `Sample Post ${Date.now()}`,
65
+ content: 'This is a sample post created by the demo app.',
66
+ published: Math.random() > 0.5,
67
+ likes: Math.floor(Math.random() * 100),
68
+ createdAt: Date.now(),
69
+ authorId: 1, // Assuming user with ID 1 exists
70
+ });
71
+
72
+ await this._dbService.db.saveWithRelations({
73
+ entity: post,
74
+ entityClass: PostEntity,
75
+ });
76
+
77
+ this.loadData();
78
+ } catch (error) {
79
+ console.error('Error adding sample post:', error);
80
+ }
81
+ }
82
+
83
+ refresh(): void {
84
+ this.loadData();
85
+ }
86
+ }
@@ -0,0 +1,59 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from 'rxjs';
3
+
4
+ import { PostEntity } from '../entities/post.entity';
5
+ import { ProfileEntity } from '../entities/profile.entity';
6
+ import { UserEntity } from '../entities/user.entity';
7
+ import { DatabaseService } from './database.service';
8
+
9
+ @Injectable({
10
+ providedIn: 'root',
11
+ })
12
+ export class TypeScriptDemoService {
13
+ private usersSubject = new BehaviorSubject<UserEntity[]>([]);
14
+ private postsSubject = new BehaviorSubject<PostEntity[]>([]);
15
+ private profilesSubject = new BehaviorSubject<ProfileEntity[]>([]);
16
+
17
+ public users$ = this.usersSubject.asObservable();
18
+ public posts$ = this.postsSubject.asObservable();
19
+ public profiles$ = this.profilesSubject.asObservable();
20
+
21
+ constructor(private _dbService: DatabaseService) {
22
+ this.loadData();
23
+ }
24
+
25
+ private async loadData(): Promise<void> {
26
+ try {
27
+ const [users, posts, profiles] = await Promise.all([
28
+ this._dbService.db.getRepository(UserEntity).toArray(),
29
+ this._dbService.db.getRepository(PostEntity).toArray(),
30
+ this._dbService.db.getRepository(ProfileEntity).toArray(),
31
+ ]);
32
+
33
+ this.usersSubject.next(users);
34
+ this.postsSubject.next(posts);
35
+ this.profilesSubject.next(profiles);
36
+ } catch (error) {
37
+ console.error('Error loading TypeScript demo data:', error);
38
+ }
39
+ }
40
+
41
+ onUserClick(user: UserEntity): void {
42
+ console.log('User clicked:', user);
43
+ alert(`User clicked: ${user.name} (${user.email})`);
44
+ }
45
+
46
+ onPostClick(post: PostEntity): void {
47
+ console.log('Post clicked:', post);
48
+ alert(`Post clicked: ${post.title} - ${post.published ? 'Published' : 'Draft'}`);
49
+ }
50
+
51
+ onProfileClick(profile: ProfileEntity): void {
52
+ console.log('Profile clicked:', profile);
53
+ alert(`Profile clicked: ${profile.bio}`);
54
+ }
55
+
56
+ refresh(): void {
57
+ this.loadData();
58
+ }
59
+ }
@@ -0,0 +1,50 @@
1
+ /* You can add global styles to this file, and also import other style files */
2
+
3
+ /* Reset and base styles */
4
+ * {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html, body {
9
+ margin: 0;
10
+ padding: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ overflow-x: hidden;
14
+ }
15
+
16
+ body {
17
+ font-family: Roboto, "Helvetica Neue", sans-serif;
18
+ }
19
+
20
+ #root {
21
+ width: 100%;
22
+ min-height: 100vh;
23
+ }
24
+
25
+ /* Angular Material overrides */
26
+ .mat-mdc-card {
27
+ margin-bottom: 16px;
28
+ }
29
+
30
+ .mat-mdc-button {
31
+ text-transform: none !important;
32
+ }
33
+
34
+ /* Custom scrollbar */
35
+ ::-webkit-scrollbar {
36
+ width: 8px;
37
+ }
38
+
39
+ ::-webkit-scrollbar-track {
40
+ background: #f1f1f1;
41
+ }
42
+
43
+ ::-webkit-scrollbar-thumb {
44
+ background: #c1c1c1;
45
+ border-radius: 4px;
46
+ }
47
+
48
+ ::-webkit-scrollbar-thumb:hover {
49
+ background: #a8a8a8;
50
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./out-tsc/app",
5
+ "types": []
6
+ },
7
+ "files": [
8
+ "src/main.ts"
9
+ ],
10
+ "include": [
11
+ "src/**/*.d.ts"
12
+ ]
13
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "compileOnSave": false,
3
+ "compilerOptions": {
4
+ "baseUrl": "./",
5
+ "outDir": "./dist/out-tsc",
6
+ "forceConsistentCasingInFileNames": true,
7
+ "strict": true,
8
+ "noImplicitOverride": true,
9
+ "noPropertyAccessFromIndexSignature": true,
10
+ "noImplicitReturns": true,
11
+ "noFallthroughCasesInSwitch": true,
12
+ "sourceMap": true,
13
+ "declaration": false,
14
+ "downlevelIteration": true,
15
+ "experimentalDecorators": true,
16
+ "moduleResolution": "node",
17
+ "importHelpers": true,
18
+ "target": "ES2022",
19
+ "module": "ES2022",
20
+ "skipLibCheck": true,
21
+ "useDefineForClassFields": false,
22
+ "allowSyntheticDefaultImports": true,
23
+ "lib": [
24
+ "ES2022",
25
+ "dom"
26
+ ]
27
+ },
28
+ "angularCompilerOptions": {
29
+ "enableI18nLegacyMessageIdFormat": false,
30
+ "strictInjectionParameters": true,
31
+ "strictInputAccessModifiers": true,
32
+ "strictTemplates": true
33
+ }
34
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./out-tsc/spec",
5
+ "types": [
6
+ "jasmine"
7
+ ]
8
+ },
9
+ "include": [
10
+ "src/**/*.spec.ts",
11
+ "src/**/*.d.ts"
12
+ ]
13
+ }
@@ -0,0 +1,206 @@
1
+ import Dexie, { type Table } from 'dexie';
2
+ import { BaseEntity } from './services/BaseEntity';
3
+ import type { AggregationOptions, AggregationResult, CloudSyncConfig, DatabaseConfig, EntityConstructor, Migration } from './types';
4
+ export declare class Database extends Dexie {
5
+ private entitySchemas;
6
+ private migrationManager;
7
+ private relationLoader;
8
+ private aggregationService;
9
+ private cloudSyncService;
10
+ migrationMetadata: Table<{
11
+ key: string;
12
+ value: string | number;
13
+ updatedAt: number;
14
+ }>;
15
+ constructor(config: DatabaseConfig);
16
+ /**
17
+ * Get repository for entity (TypeORM style)
18
+ *
19
+ * @example
20
+ * const users = db.getRepository(User);
21
+ * const id = await users.add({ name: 'Ann' } as User);
22
+ */
23
+ getRepository<T extends BaseEntity, TKey extends Extract<NonNullable<T['id']>, string | number> = Extract<NonNullable<T['id']>, string | number>>(entityClass: EntityConstructor<T>): Table<T, TKey>;
24
+ /**
25
+ * Perform aggregation on entity data
26
+ *
27
+ * @example
28
+ * const result = await db.aggregate({
29
+ * entityClass: Post,
30
+ * options: { where: { category: 'tech' } },
31
+ * });
32
+ */
33
+ aggregate<T extends BaseEntity>(params: {
34
+ entityClass: EntityConstructor<T>;
35
+ options: AggregationOptions<T>;
36
+ }): Promise<AggregationResult>;
37
+ /**
38
+ * Create database with entity registration
39
+ *
40
+ * @example
41
+ * const db = Database.createDatabase({
42
+ * name: 'app-db',
43
+ * version: 1,
44
+ * entities: [User, Post],
45
+ * });
46
+ */
47
+ static createDatabase(params: {
48
+ name: string;
49
+ version: number;
50
+ entities: EntityConstructor[];
51
+ config?: Partial<DatabaseConfig>;
52
+ }): Database;
53
+ /**
54
+ * Clear all data from database
55
+ *
56
+ * @example
57
+ * await db.clearAllData();
58
+ */
59
+ clearAllData(): Promise<void>;
60
+ /**
61
+ * Reset database when schema changes
62
+ *
63
+ * @example
64
+ * await db.resetDatabase();
65
+ */
66
+ resetDatabase(): Promise<void>;
67
+ /**
68
+ * Check if schema has changed and reset if needed
69
+ *
70
+ * @example
71
+ * const changed = await db.checkSchemaChanges();
72
+ */
73
+ checkSchemaChanges(): Promise<boolean>;
74
+ /**
75
+ * Manually perform selective reset for changed tables only
76
+ *
77
+ * @example
78
+ * await db.performSelectiveReset();
79
+ */
80
+ performSelectiveReset(): Promise<void>;
81
+ /**
82
+ * Run migrations for schema changes
83
+ *
84
+ * @example
85
+ * await db.runMigrations(migrations);
86
+ */
87
+ runMigrations(migrations: Migration[]): Promise<void>;
88
+ /**
89
+ * Get typed table for entity
90
+ *
91
+ * @example
92
+ * const posts = db.getTypedTable(Post);
93
+ */
94
+ getTypedTable<T extends BaseEntity, TKey extends Extract<NonNullable<T['id']>, string | number> = Extract<NonNullable<T['id']>, string | number>>(entityClass: EntityConstructor<T>): Table<T, TKey>;
95
+ /**
96
+ * Get table with proper typing for specific entity
97
+ *
98
+ * @example
99
+ * const users = db.getTableForEntity(User);
100
+ */
101
+ getTableForEntity<T extends BaseEntity, TKey extends Extract<NonNullable<T['id']>, string | number> = Extract<NonNullable<T['id']>, string | number>>(entityClass: EntityConstructor<T>): Table<T, TKey>;
102
+ /**
103
+ * Get all entities
104
+ *
105
+ * @example
106
+ * const all = db.getEntities();
107
+ */
108
+ getEntities(): EntityConstructor[];
109
+ /**
110
+ * Get entity by table name
111
+ *
112
+ * @example
113
+ * const UserClass = db.getEntity('users');
114
+ */
115
+ getEntity(tableName: string): EntityConstructor | undefined;
116
+ /**
117
+ * Load relations for an entity
118
+ *
119
+ * @example
120
+ * const userWithRelations = await db.loadRelations({
121
+ * entity: user,
122
+ * entityClass: User,
123
+ * relationNames: ['posts'],
124
+ * });
125
+ */
126
+ loadRelations<T extends BaseEntity>(params: {
127
+ entity: T;
128
+ entityClass: EntityConstructor<T>;
129
+ relationNames?: string[];
130
+ }): Promise<T>;
131
+ /**
132
+ * Load a specific relation by name
133
+ *
134
+ * @example
135
+ * const posts = await db.loadRelationByName({
136
+ * entity: { id: userId },
137
+ * entityClass: User,
138
+ * relationName: 'posts',
139
+ * });
140
+ */
141
+ loadRelationByName<T extends BaseEntity, K extends keyof T>(params: {
142
+ entity: T | {
143
+ id: string | number;
144
+ };
145
+ entityClass: EntityConstructor<T>;
146
+ relationName: K;
147
+ }): Promise<T[K]>;
148
+ /**
149
+ * Save entity with relations
150
+ *
151
+ * @example
152
+ * const saved = await db.saveWithRelations({
153
+ * entity: user,
154
+ * entityClass: User,
155
+ * });
156
+ */
157
+ saveWithRelations<T extends BaseEntity>(params: {
158
+ entity: T;
159
+ entityClass: EntityConstructor<T>;
160
+ }): Promise<T>;
161
+ /**
162
+ * Delete entity with cascade handling for relations
163
+ *
164
+ * @example
165
+ * await db.deleteWithRelations({
166
+ * entity: user,
167
+ * entityClass: User,
168
+ * });
169
+ */
170
+ deleteWithRelations<T extends BaseEntity>(params: {
171
+ entity: T;
172
+ entityClass: EntityConstructor<T>;
173
+ }): Promise<void>;
174
+ /**
175
+ * Manual sync with cloud
176
+ */
177
+ sync(): Promise<void>;
178
+ /**
179
+ * Get sync status
180
+ */
181
+ getSyncStatus(): {
182
+ enabled: boolean;
183
+ lastSync?: Date;
184
+ isOnline?: boolean;
185
+ };
186
+ /**
187
+ * Enable cloud sync (if not already enabled)
188
+ */
189
+ enableCloudSync(config: CloudSyncConfig): Promise<void>;
190
+ /**
191
+ * Disable cloud sync
192
+ */
193
+ disableCloudSync(): void;
194
+ /**
195
+ * Check if cloud sync is enabled
196
+ */
197
+ isCloudSyncEnabled(): boolean;
198
+ /**
199
+ * Get cloud sync configuration
200
+ */
201
+ getCloudSyncConfig(): CloudSyncConfig | undefined;
202
+ /**
203
+ * Force sync specific tables
204
+ */
205
+ syncTables(tableNames: string[]): Promise<void>;
206
+ }