@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.
- package/.vscode/extensions.json +5 -0
- package/README.md +1280 -0
- package/angular-demo-app/README.md +84 -0
- package/angular-demo-app/angular.json +109 -0
- package/angular-demo-app/package-lock.json +14215 -0
- package/angular-demo-app/package.json +41 -0
- package/angular-demo-app/src/app/app.component.ts +481 -0
- package/angular-demo-app/src/app/app.routes.ts +8 -0
- package/angular-demo-app/src/app/components/actions.component.ts +202 -0
- package/angular-demo-app/src/app/components/cloud-sync-demo.component.ts +296 -0
- package/angular-demo-app/src/app/components/live-query-demo.component.ts +307 -0
- package/angular-demo-app/src/app/components/main-info.component.ts +148 -0
- package/angular-demo-app/src/app/components/posts-live-query-demo.component.ts +336 -0
- package/angular-demo-app/src/app/components/typescript-demo.component.ts +268 -0
- package/angular-demo-app/src/entities/post-tag.entity.ts +25 -0
- package/angular-demo-app/src/entities/post.entity.ts +49 -0
- package/angular-demo-app/src/entities/profile.entity.ts +42 -0
- package/angular-demo-app/src/entities/tag.entity.ts +36 -0
- package/angular-demo-app/src/entities/user.entity.ts +59 -0
- package/angular-demo-app/src/favicon.ico +1 -0
- package/angular-demo-app/src/index.html +16 -0
- package/angular-demo-app/src/main.ts +13 -0
- package/angular-demo-app/src/services/app-logic.service.ts +449 -0
- package/angular-demo-app/src/services/cloud-sync.service.ts +95 -0
- package/angular-demo-app/src/services/database.service.ts +26 -0
- package/angular-demo-app/src/services/live-query.service.ts +63 -0
- package/angular-demo-app/src/services/posts-live-query.service.ts +86 -0
- package/angular-demo-app/src/services/typescript-demo.service.ts +59 -0
- package/angular-demo-app/src/styles.scss +50 -0
- package/angular-demo-app/tsconfig.app.json +13 -0
- package/angular-demo-app/tsconfig.json +34 -0
- package/angular-demo-app/tsconfig.spec.json +13 -0
- package/dist/Database.d.ts +206 -0
- package/dist/Database.js +288 -0
- package/dist/decorators/Column.d.ts +79 -0
- package/dist/decorators/Column.js +236 -0
- package/dist/decorators/Entity.d.ts +32 -0
- package/dist/decorators/Entity.js +44 -0
- package/dist/decorators/Relation.d.ts +70 -0
- package/dist/decorators/Relation.js +120 -0
- package/dist/decorators/index.d.ts +3 -0
- package/dist/decorators/index.js +3 -0
- package/dist/errors/ValidationError.d.ts +4 -0
- package/dist/errors/ValidationError.js +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/metadata/Column.d.ts +8 -0
- package/dist/metadata/Column.js +44 -0
- package/dist/metadata/Entity.d.ts +11 -0
- package/dist/metadata/Entity.js +21 -0
- package/dist/metadata/Relation.d.ts +20 -0
- package/dist/metadata/Relation.js +74 -0
- package/dist/metadata/index.d.ts +3 -0
- package/dist/metadata/index.js +3 -0
- package/dist/services/AggregationService.d.ts +38 -0
- package/dist/services/AggregationService.js +229 -0
- package/dist/services/BaseEntity.d.ts +32 -0
- package/dist/services/BaseEntity.js +62 -0
- package/dist/services/CloudSyncService.d.ts +100 -0
- package/dist/services/CloudSyncService.js +196 -0
- package/dist/services/DecoratorUtils.d.ts +12 -0
- package/dist/services/DecoratorUtils.js +10 -0
- package/dist/services/EntityFactory.d.ts +25 -0
- package/dist/services/EntityFactory.js +27 -0
- package/dist/services/EntityRegistry.d.ts +61 -0
- package/dist/services/EntityRegistry.js +56 -0
- package/dist/services/EntitySchema.d.ts +56 -0
- package/dist/services/EntitySchema.js +125 -0
- package/dist/services/MigrationManager.d.ts +70 -0
- package/dist/services/MigrationManager.js +181 -0
- package/dist/services/RelationLoader.d.ts +66 -0
- package/dist/services/RelationLoader.js +310 -0
- package/dist/services/SchemaBuilder.d.ts +68 -0
- package/dist/services/SchemaBuilder.js +191 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.js +7 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.js +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.js +16 -0
- package/eslint.config.js +49 -0
- package/homepage/favicon.svg +36 -0
- package/homepage/index.html +1725 -0
- package/package.json +78 -0
- package/react-demo-app/README.md +61 -0
- package/react-demo-app/eslint.config.js +60 -0
- package/react-demo-app/index.html +13 -0
- package/react-demo-app/package-lock.json +4955 -0
- package/react-demo-app/package.json +39 -0
- package/react-demo-app/src/App.tsx +172 -0
- package/react-demo-app/src/assets/react.svg +1 -0
- package/react-demo-app/src/components/Actions.tsx +171 -0
- package/react-demo-app/src/components/CloudSyncDemo.tsx +191 -0
- package/react-demo-app/src/components/LiveQueryDemo.tsx +122 -0
- package/react-demo-app/src/components/MainInfo.tsx +75 -0
- package/react-demo-app/src/components/PostsLiveQueryDemo.tsx +185 -0
- package/react-demo-app/src/components/TypeScriptDemo.tsx +190 -0
- package/react-demo-app/src/database/Database.ts +30 -0
- package/react-demo-app/src/entities/Post.ts +48 -0
- package/react-demo-app/src/entities/PostTag.ts +26 -0
- package/react-demo-app/src/entities/Profile.ts +41 -0
- package/react-demo-app/src/entities/Tag.ts +35 -0
- package/react-demo-app/src/entities/User.ts +61 -0
- package/react-demo-app/src/hooks/useAppLogic.ts +565 -0
- package/react-demo-app/src/hooks/useCloudSyncDemo.ts +84 -0
- package/react-demo-app/src/hooks/useLiveQueryDemo.ts +68 -0
- package/react-demo-app/src/hooks/usePostsLiveQueryDemo.ts +64 -0
- package/react-demo-app/src/hooks/useTypeScriptDemo.ts +43 -0
- package/react-demo-app/src/index.css +26 -0
- package/react-demo-app/src/main.tsx +18 -0
- package/react-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
- package/react-demo-app/src/migrations/002-add-post-category.ts +37 -0
- package/react-demo-app/src/migrations/index.ts +8 -0
- package/react-demo-app/src/vite-env.d.ts +1 -0
- package/react-demo-app/tsconfig.app.json +22 -0
- package/react-demo-app/tsconfig.json +6 -0
- package/react-demo-app/vite.config.ts +10 -0
- package/src/Database.ts +405 -0
- package/src/errors/ValidationError.ts +9 -0
- package/src/index.ts +13 -0
- package/src/metadata/Column.ts +74 -0
- package/src/metadata/Entity.ts +42 -0
- package/src/metadata/Relation.ts +121 -0
- package/src/metadata/index.ts +5 -0
- package/src/services/AggregationService.ts +348 -0
- package/src/services/BaseEntity.ts +77 -0
- package/src/services/CloudSyncService.ts +248 -0
- package/src/services/EntityFactory.ts +35 -0
- package/src/services/EntityRegistry.ts +109 -0
- package/src/services/EntitySchema.ts +154 -0
- package/src/services/MigrationManager.ts +276 -0
- package/src/services/RelationLoader.ts +532 -0
- package/src/services/SchemaBuilder.ts +237 -0
- package/src/services/index.ts +7 -0
- package/src/types.d.ts +1 -0
- package/src/types.ts +169 -0
- package/src/utils/logger.ts +40 -0
- package/svelte-demo-app/README.md +61 -0
- package/svelte-demo-app/package-lock.json +3000 -0
- package/svelte-demo-app/package.json +30 -0
- package/svelte-demo-app/src/app.d.ts +12 -0
- package/svelte-demo-app/src/app.html +13 -0
- package/svelte-demo-app/src/components/Actions.svelte +121 -0
- package/svelte-demo-app/src/components/CloudSyncDemo.svelte +333 -0
- package/svelte-demo-app/src/components/LiveQueryDemo.svelte +191 -0
- package/svelte-demo-app/src/components/MainInfo.svelte +133 -0
- package/svelte-demo-app/src/components/PostsLiveQueryDemo.svelte +330 -0
- package/svelte-demo-app/src/components/TypeScriptDemo.svelte +251 -0
- package/svelte-demo-app/src/database/Database.ts +29 -0
- package/svelte-demo-app/src/entities/Post.ts +46 -0
- package/svelte-demo-app/src/entities/PostTag.ts +22 -0
- package/svelte-demo-app/src/entities/Profile.ts +39 -0
- package/svelte-demo-app/src/entities/Tag.ts +33 -0
- package/svelte-demo-app/src/entities/User.ts +62 -0
- package/svelte-demo-app/src/lib/database/Database.ts +30 -0
- package/svelte-demo-app/src/lib/entities/Post.ts +47 -0
- package/svelte-demo-app/src/lib/entities/PostTag.ts +23 -0
- package/svelte-demo-app/src/lib/entities/Profile.ts +40 -0
- package/svelte-demo-app/src/lib/entities/Tag.ts +34 -0
- package/svelte-demo-app/src/lib/entities/User.ts +59 -0
- package/svelte-demo-app/src/lib/index.ts +7 -0
- package/svelte-demo-app/src/lib/migrations/001-add-user-email-index.ts +17 -0
- package/svelte-demo-app/src/lib/migrations/002-add-post-category.ts +37 -0
- package/svelte-demo-app/src/lib/migrations/index.ts +8 -0
- package/svelte-demo-app/src/migrations/001-add-user-email-index.ts +17 -0
- package/svelte-demo-app/src/migrations/002-add-post-category.ts +37 -0
- package/svelte-demo-app/src/migrations/index.ts +8 -0
- package/svelte-demo-app/src/routes/+layout.js +3 -0
- package/svelte-demo-app/src/routes/+layout.svelte +228 -0
- package/svelte-demo-app/src/routes/+page.js +3 -0
- package/svelte-demo-app/src/routes/+page.svelte +1305 -0
- package/svelte-demo-app/src/stores/appStore.js +603 -0
- package/svelte-demo-app/svelte.config.js +18 -0
- package/svelte-demo-app/tsconfig.json +14 -0
- package/svelte-demo-app/vite.config.ts +6 -0
- package/tests/aggregation.e2e.test.ts +87 -0
- package/tests/base-entity.e2e.test.ts +47 -0
- package/tests/database-api.e2e.test.ts +177 -0
- package/tests/decorators.e2e.test.ts +40 -0
- package/tests/entity-schema.e2e.test.ts +58 -0
- package/tests/relation-loader-table-names.test.ts +192 -0
- package/tests/relations.e2e.test.ts +178 -0
- package/tests/zod-runtime.e2e.test.ts +69 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +21 -0
- package/vitest.setup.ts +27 -0
- package/vue-demo-app/README.md +61 -0
- package/vue-demo-app/index.html +13 -0
- package/vue-demo-app/package-lock.json +1537 -0
- package/vue-demo-app/package.json +27 -0
- package/vue-demo-app/src/App.vue +100 -0
- package/vue-demo-app/src/components/Actions.vue +135 -0
- package/vue-demo-app/src/components/CloudSyncDemo.vue +139 -0
- package/vue-demo-app/src/components/LiveQueryDemo.vue +122 -0
- package/vue-demo-app/src/components/MainInfo.vue +80 -0
- package/vue-demo-app/src/components/PostsLiveQueryDemo.vue +136 -0
- package/vue-demo-app/src/components/TypeScriptDemo.vue +133 -0
- package/vue-demo-app/src/database/Database.ts +29 -0
- package/vue-demo-app/src/entities/Post.ts +48 -0
- package/vue-demo-app/src/entities/PostTag.ts +24 -0
- package/vue-demo-app/src/entities/Profile.ts +41 -0
- package/vue-demo-app/src/entities/Tag.ts +35 -0
- package/vue-demo-app/src/entities/User.ts +61 -0
- package/vue-demo-app/src/main.ts +29 -0
- package/vue-demo-app/src/migrations/001-add-user-email-index.ts +23 -0
- package/vue-demo-app/src/migrations/002-add-post-category.ts +46 -0
- package/vue-demo-app/src/migrations/index.ts +14 -0
- package/vue-demo-app/src/services/useAppLogic.ts +565 -0
- package/vue-demo-app/src/services/useCloudSyncDemo.ts +84 -0
- package/vue-demo-app/src/services/useLiveQueryDemo.ts +82 -0
- package/vue-demo-app/src/services/usePostsLiveQueryDemo.ts +77 -0
- package/vue-demo-app/src/services/useTypeScriptDemo.ts +56 -0
- package/vue-demo-app/src/vite-env.d.ts +1 -0
- package/vue-demo-app/tsconfig.json +25 -0
- package/vue-demo-app/tsconfig.node.json +10 -0
- package/vue-demo-app/vite.config.ts +16 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
beforeEach, describe, expect, it,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
defineEntity, newEntity,
|
|
7
|
+
} from '../src';
|
|
8
|
+
import { Database } from '../src/Database';
|
|
9
|
+
import { BaseEntity } from '../src/services/BaseEntity';
|
|
10
|
+
|
|
11
|
+
class User extends BaseEntity<number> {
|
|
12
|
+
name: string;
|
|
13
|
+
profile?: Profile;
|
|
14
|
+
posts?: Post[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
defineEntity(User, {
|
|
18
|
+
tableName: 'users',
|
|
19
|
+
columns: { name: { required: true } },
|
|
20
|
+
relations: {
|
|
21
|
+
profile: { type: 'one-to-one', target: 'profiles', foreignKey: 'userId', cascade: true },
|
|
22
|
+
posts: { type: 'one-to-many', target: 'posts', foreignKey: 'authorId', cascade: true },
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
class Profile extends BaseEntity<number> {
|
|
27
|
+
bio?: string;
|
|
28
|
+
userId?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
defineEntity(Profile, {
|
|
32
|
+
tableName: 'profiles',
|
|
33
|
+
columns: {
|
|
34
|
+
bio: {},
|
|
35
|
+
userId: { indexed: true },
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
class Post extends BaseEntity<number> {
|
|
40
|
+
title!: string;
|
|
41
|
+
tags?: Tag[];
|
|
42
|
+
authorId?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
defineEntity(Post, {
|
|
46
|
+
tableName: 'posts',
|
|
47
|
+
columns: {
|
|
48
|
+
title: { required: true },
|
|
49
|
+
authorId: { indexed: true },
|
|
50
|
+
},
|
|
51
|
+
relations: {
|
|
52
|
+
tags: { type: 'many-to-many', target: 'tags', joinTable: 'post_tags', cascade: true },
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
class Tag extends BaseEntity<number> {
|
|
57
|
+
name!: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
defineEntity(Tag, {
|
|
61
|
+
tableName: 'tags',
|
|
62
|
+
columns: { name: { required: true } },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
class PostTag extends BaseEntity<number> {
|
|
66
|
+
sourceId!: number;
|
|
67
|
+
targetId!: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
defineEntity(PostTag, {
|
|
71
|
+
tableName: 'post_tags',
|
|
72
|
+
columns: {
|
|
73
|
+
sourceId: { indexed: true },
|
|
74
|
+
targetId: { indexed: true },
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const ENTITIES = [User, Profile, Post, Tag, PostTag];
|
|
79
|
+
|
|
80
|
+
describe('Relations', () => {
|
|
81
|
+
let db: Database;
|
|
82
|
+
|
|
83
|
+
beforeEach(async () => {
|
|
84
|
+
db = Database.createDatabase({
|
|
85
|
+
name: `rel-db-${Date.now()}-${Math.random()}`,
|
|
86
|
+
version: 1,
|
|
87
|
+
entities: ENTITIES,
|
|
88
|
+
config: { onSchemaChangeStrategy: 'all' },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await db.clearAllData();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('one-to-one: load and cascade delete', async () => {
|
|
95
|
+
const users = db.getRepository(User);
|
|
96
|
+
const profiles = db.getRepository(Profile);
|
|
97
|
+
|
|
98
|
+
const u = newEntity(User, { name: 'U' });
|
|
99
|
+
const userId = await users.add(u);
|
|
100
|
+
|
|
101
|
+
const profile = newEntity(Profile, { bio: 'Bio', userId });
|
|
102
|
+
const saved = await db
|
|
103
|
+
.saveWithRelations({ entity: profile, entityClass: Profile });
|
|
104
|
+
|
|
105
|
+
const loaded = await db.loadRelationByName({
|
|
106
|
+
entity: { id: userId },
|
|
107
|
+
entityClass: User,
|
|
108
|
+
relationName: 'profile',
|
|
109
|
+
});
|
|
110
|
+
expect(loaded!.bio).toBe('Bio');
|
|
111
|
+
|
|
112
|
+
await db.deleteWithRelations({ entity: saved, entityClass: Profile });
|
|
113
|
+
const after = await profiles.get(saved.id!);
|
|
114
|
+
expect(after).toBeUndefined();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('one-to-many: load and cascade delete', async () => {
|
|
118
|
+
const users = db.getRepository(User);
|
|
119
|
+
const posts = db.getRepository(Post);
|
|
120
|
+
|
|
121
|
+
const u = newEntity(User, { name: 'U' });
|
|
122
|
+
const userId = await users.add(u);
|
|
123
|
+
|
|
124
|
+
const p1 = newEntity(Post, { title: 'P1', authorId: userId });
|
|
125
|
+
const p2 = newEntity(Post, { title: 'P2', authorId: userId });
|
|
126
|
+
|
|
127
|
+
await db.saveWithRelations({ entity: p1, entityClass: Post });
|
|
128
|
+
await db.saveWithRelations({ entity: p2, entityClass: Post });
|
|
129
|
+
|
|
130
|
+
const loaded = await db.loadRelationByName({
|
|
131
|
+
entity: { id: userId },
|
|
132
|
+
entityClass: User,
|
|
133
|
+
relationName: 'posts',
|
|
134
|
+
});
|
|
135
|
+
expect((loaded as Post[]).length).toBe(2);
|
|
136
|
+
|
|
137
|
+
const first = await posts.where('authorId').equals(userId).first();
|
|
138
|
+
await db.deleteWithRelations({ entity: first!, entityClass: Post });
|
|
139
|
+
|
|
140
|
+
const remaining = await posts.where('authorId').equals(userId).toArray();
|
|
141
|
+
expect(remaining.length).toBe(1);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('many-to-many: load and cascade delete removes join links', async () => {
|
|
145
|
+
const posts = db.getRepository(Post);
|
|
146
|
+
const tags = db.getRepository(Tag);
|
|
147
|
+
const join = db.table('post_tags');
|
|
148
|
+
|
|
149
|
+
const pNew = newEntity(Post, { title: 'P' });
|
|
150
|
+
const postId = await posts.add(pNew);
|
|
151
|
+
|
|
152
|
+
const tA = newEntity(Tag, { name: 'a' });
|
|
153
|
+
const tagAId = await tags.add(tA);
|
|
154
|
+
|
|
155
|
+
const tB = newEntity(Tag, { name: 'b' });
|
|
156
|
+
const tagBId = await tags.add(tB);
|
|
157
|
+
|
|
158
|
+
const p = newEntity(Post, {
|
|
159
|
+
id: postId,
|
|
160
|
+
title: 'P',
|
|
161
|
+
tags: [{ id: tagAId } as Tag, { id: tagBId } as Tag],
|
|
162
|
+
});
|
|
163
|
+
await db.saveWithRelations({ entity: p, entityClass: Post });
|
|
164
|
+
|
|
165
|
+
const loaded = await db.loadRelationByName({
|
|
166
|
+
entity: { id: postId } as Post,
|
|
167
|
+
entityClass: Post,
|
|
168
|
+
relationName: 'tags',
|
|
169
|
+
});
|
|
170
|
+
expect((loaded as Tag[]).length).toBe(2);
|
|
171
|
+
|
|
172
|
+
await db
|
|
173
|
+
.deleteWithRelations({ entity: { id: postId } as Post, entityClass: Post });
|
|
174
|
+
|
|
175
|
+
const links = await join.where('sourceId').equals(postId).toArray();
|
|
176
|
+
expect(links.length).toBe(0);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
beforeEach, describe, expect, it,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
import { defineEntity } from '../src';
|
|
7
|
+
import { Database } from '../src/Database';
|
|
8
|
+
import { BaseEntity } from '../src/services/BaseEntity';
|
|
9
|
+
import { EntitySchema } from '../src/services/EntitySchema';
|
|
10
|
+
|
|
11
|
+
class Product extends BaseEntity<number> {
|
|
12
|
+
name?: string;
|
|
13
|
+
price?: number;
|
|
14
|
+
static schema = z.object({
|
|
15
|
+
name: z.string(),
|
|
16
|
+
price: z.number().positive(),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
defineEntity(Product, { tableName: 'products' });
|
|
21
|
+
|
|
22
|
+
describe('Zod runtime validation', () => {
|
|
23
|
+
let db: Database;
|
|
24
|
+
|
|
25
|
+
beforeEach(async () => {
|
|
26
|
+
db = Database.createDatabase({
|
|
27
|
+
name: `zod-db-${Date.now()}-${Math.random()}`,
|
|
28
|
+
version: 1,
|
|
29
|
+
entities: [Product],
|
|
30
|
+
config: { onSchemaChangeStrategy: 'all' },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await db.clearAllData();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('BaseEntity.validate and validateOrThrow (registered entity)', () => {
|
|
37
|
+
const entityCtor = db.getEntity('products')!;
|
|
38
|
+
expect(entityCtor).toBe(Product);
|
|
39
|
+
|
|
40
|
+
const ok = new Product();
|
|
41
|
+
Object.assign(ok, { name: 'X', price: 1 });
|
|
42
|
+
|
|
43
|
+
const okRes = ok.validate();
|
|
44
|
+
expect(okRes.isValid).toBe(true);
|
|
45
|
+
|
|
46
|
+
const bad = new Product();
|
|
47
|
+
Object.assign(bad, { name: 'Y', price: -2 });
|
|
48
|
+
|
|
49
|
+
const badRes = bad.validate();
|
|
50
|
+
expect(badRes.isValid).toBe(false);
|
|
51
|
+
expect(() => bad.validateOrThrow()).toThrowError();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('EntitySchema.validate with schema and create', () => {
|
|
55
|
+
const schema = new EntitySchema(Product, Product.schema);
|
|
56
|
+
|
|
57
|
+
const valid = schema.validate({ name: 'A', price: 2 });
|
|
58
|
+
expect(valid.isValid).toBe(true);
|
|
59
|
+
|
|
60
|
+
const invalid = schema
|
|
61
|
+
.validate({ name: 'A', price: -1 } as Partial<Product>);
|
|
62
|
+
|
|
63
|
+
expect(invalid.isValid).toBe(false);
|
|
64
|
+
|
|
65
|
+
const p = schema.create({ name: 'B', price: 3 });
|
|
66
|
+
expect(p.name).toBe('B');
|
|
67
|
+
expect(p.price).toBe(3);
|
|
68
|
+
});
|
|
69
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2022", "DOM"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"experimentalDecorators": false,
|
|
14
|
+
"emitDecoratorMetadata": false,
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
"resolveJsonModule": true
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "demo-app"]
|
|
21
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: 'node',
|
|
6
|
+
setupFiles: ['./vitest.setup.ts'],
|
|
7
|
+
include: ['tests/**/*.test.ts'],
|
|
8
|
+
globals: true,
|
|
9
|
+
},
|
|
10
|
+
esbuild: {
|
|
11
|
+
tsconfigRaw: {
|
|
12
|
+
compilerOptions: {
|
|
13
|
+
experimentalDecorators: true,
|
|
14
|
+
useDefineForClassFields: false,
|
|
15
|
+
target: 'ES2022',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
|
package/vitest.setup.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import FDBFactory from 'fake-indexeddb/lib/FDBFactory';
|
|
4
|
+
import FDBKeyRange from 'fake-indexeddb/lib/FDBKeyRange';
|
|
5
|
+
|
|
6
|
+
if (!(globalThis as any).indexedDB) {
|
|
7
|
+
(globalThis as any).indexedDB = new FDBFactory();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!(globalThis as any).IDBKeyRange) {
|
|
11
|
+
(globalThis as any).IDBKeyRange = FDBKeyRange;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class MemoryLocalStorage {
|
|
15
|
+
private store = new Map<string, string>();
|
|
16
|
+
getItem(key: string):
|
|
17
|
+
string | null { return this.store.has(key) ? this.store.get(key)! : null; }
|
|
18
|
+
setItem(key: string, value: string): void { this.store.set(key, String(value)); }
|
|
19
|
+
removeItem(key: string): void { this.store.delete(key); }
|
|
20
|
+
clear(): void { this.store.clear(); }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!(globalThis as any).localStorage) {
|
|
24
|
+
(globalThis as any).localStorage = new MemoryLocalStorage();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Dexie ORM Demo App
|
|
2
|
+
|
|
3
|
+
A demonstration app showcasing the capabilities of the **Dexie ORM for IndexedDB** library.
|
|
4
|
+
|
|
5
|
+
## Library Features
|
|
6
|
+
|
|
7
|
+
- **Entity Configuration** - define entities using `defineEntity()`
|
|
8
|
+
- **Automatic Schema** - automatic schema generation with primary keys and indexes
|
|
9
|
+
- **Relations** - entity relationships with helpers
|
|
10
|
+
- **Zod Validation** - runtime validation
|
|
11
|
+
- **Aggregations** - aggregate functions (count, avg, sum)
|
|
12
|
+
- **Live Queries** - reactive queries with `useLiveQuery()`
|
|
13
|
+
- **TypeScript** - full type safety
|
|
14
|
+
- **Cloud Sync** - synchronization with Dexie Cloud
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Requirements
|
|
19
|
+
- Node.js 18+
|
|
20
|
+
- npm or yarn
|
|
21
|
+
|
|
22
|
+
### Installation and Running
|
|
23
|
+
|
|
24
|
+
1. **Install dependencies:**
|
|
25
|
+
```bash
|
|
26
|
+
npm install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
2. **Run in development mode:**
|
|
30
|
+
```bash
|
|
31
|
+
npm run dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
3. **Open in browser:**
|
|
35
|
+
```
|
|
36
|
+
http://localhost:5173
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Production Build
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## App Features
|
|
46
|
+
|
|
47
|
+
### Admin Tab
|
|
48
|
+
- **Overview** - library capabilities overview
|
|
49
|
+
- **Admin Actions** - function testing buttons
|
|
50
|
+
- **Live Query Demo** - reactive queries demonstration
|
|
51
|
+
- **TypeScript Demo** - type safety testing
|
|
52
|
+
- **Posts Demo** - advanced queries and aggregations
|
|
53
|
+
|
|
54
|
+
### Cloud Sync Tab
|
|
55
|
+
- **Sync Status** - synchronization status
|
|
56
|
+
- **Sync Controls** - synchronization management buttons
|
|
57
|
+
- **Instructions** - configuration instructions
|
|
58
|
+
|
|
59
|
+
## More Information
|
|
60
|
+
|
|
61
|
+
For more information visit our official [page](https://idb-orm.com).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Dexie ORM Vue Demo</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|