@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,70 @@
|
|
|
1
|
+
import type { ClassConstructor } from '../services/DecoratorUtils';
|
|
2
|
+
import type { EntityConstructor, RelationMetadata, RelationOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Relation decorator: defines a relation on a
|
|
5
|
+
* property (one-to-one/many-to-one/etc.).
|
|
6
|
+
* @param options - Relation options
|
|
7
|
+
* (type, target, foreignKey/joinTable, cascade, eager)
|
|
8
|
+
* @returns Property decorator function
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* class Post {
|
|
12
|
+
* @Relation({ type: 'many-to-many', target: 'tags', joinTable: 'post_tags' })
|
|
13
|
+
* tags?: Tag[];
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
export declare function Relation(options: RelationOptions): (...args: unknown[]) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Retrieve relation metadata for an entity class.
|
|
19
|
+
* @param entityClass - The entity class (constructor)
|
|
20
|
+
* @returns Map of propertyKey -> RelationMetadata, or undefined if none
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const relations = getRelationMetadata(User);
|
|
24
|
+
*/
|
|
25
|
+
export declare function getRelationMetadata(entityClass: ClassConstructor): Record<string, RelationMetadata> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Convenience decorator for one-to-one relations.
|
|
28
|
+
* @param params - target, optional foreignKey, and extra options
|
|
29
|
+
* @returns Property decorator function
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* class User {
|
|
33
|
+
* @OneToOne({ target: 'profiles', foreignKey: 'userId' }) profile?: Profile
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
export declare function OneToOne(params: {
|
|
37
|
+
target: EntityConstructor | string;
|
|
38
|
+
foreignKey?: string;
|
|
39
|
+
options?: Partial<RelationOptions>;
|
|
40
|
+
}): (...args: unknown[]) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Convenience decorator for one-to-many relations.
|
|
43
|
+
* @param params - target, required foreignKey, and extra options
|
|
44
|
+
* @returns Property decorator function
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* class User { @OneToMany(
|
|
48
|
+
* { target: 'posts', foreignKey: 'authorId' }) posts?: Post[]
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
export declare function OneToMany(params: {
|
|
52
|
+
target: EntityConstructor | string;
|
|
53
|
+
foreignKey: string;
|
|
54
|
+
options?: Partial<RelationOptions>;
|
|
55
|
+
}): (...args: unknown[]) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Convenience decorator for many-to-many relations.
|
|
58
|
+
* @param params - target, joinTable, and extra options
|
|
59
|
+
* @returns Property decorator function
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* class Post {
|
|
63
|
+
* @ManyToMany({ target: 'tags', joinTable: 'post_tags' }) tags?: Tag[]
|
|
64
|
+
* }
|
|
65
|
+
*/
|
|
66
|
+
export declare function ManyToMany(params: {
|
|
67
|
+
target: EntityConstructor | string;
|
|
68
|
+
joinTable: string;
|
|
69
|
+
options?: Partial<RelationOptions>;
|
|
70
|
+
}): (...args: unknown[]) => void;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// reflect-metadata no longer required
|
|
2
|
+
import { isFieldContext, isLegacyArgs, } from '../services/DecoratorUtils';
|
|
3
|
+
import { getDefinedRelations } from '../services/EntityRegistry';
|
|
4
|
+
const RELATIONS_METADATA_KEY = Symbol('relations');
|
|
5
|
+
/**
|
|
6
|
+
* Relation decorator: defines a relation on a
|
|
7
|
+
* property (one-to-one/many-to-one/etc.).
|
|
8
|
+
* @param options - Relation options
|
|
9
|
+
* (type, target, foreignKey/joinTable, cascade, eager)
|
|
10
|
+
* @returns Property decorator function
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* class Post {
|
|
14
|
+
* @Relation({ type: 'many-to-many', target: 'tags', joinTable: 'post_tags' })
|
|
15
|
+
* tags?: Tag[];
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
export function Relation(options) {
|
|
19
|
+
return function (...args) {
|
|
20
|
+
const apply = (ctor, propertyKey) => {
|
|
21
|
+
const existingRelations = getRelationMetadata(ctor) || {};
|
|
22
|
+
const relationMetadata = { propertyKey, ...options };
|
|
23
|
+
existingRelations[propertyKey] = relationMetadata;
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
const reflectDefine = Reflect?.defineMetadata?.bind(Reflect);
|
|
26
|
+
if (reflectDefine) {
|
|
27
|
+
reflectDefine(RELATIONS_METADATA_KEY, existingRelations, ctor);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// Legacy TS decorators
|
|
31
|
+
if (isLegacyArgs(args)) {
|
|
32
|
+
const [target, propertyKey] = args;
|
|
33
|
+
apply(target.constructor, propertyKey);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Standard decorators (TC39)
|
|
37
|
+
if (isFieldContext(args)) {
|
|
38
|
+
const [, context] = args;
|
|
39
|
+
const propertyKey = context.name;
|
|
40
|
+
context.addInitializer(function () {
|
|
41
|
+
apply(this.constructor, propertyKey);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Retrieve relation metadata for an entity class.
|
|
48
|
+
* @param entityClass - The entity class (constructor)
|
|
49
|
+
* @returns Map of propertyKey -> RelationMetadata, or undefined if none
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const relations = getRelationMetadata(User);
|
|
53
|
+
*/
|
|
54
|
+
export function getRelationMetadata(entityClass) {
|
|
55
|
+
const defined = getDefinedRelations(entityClass);
|
|
56
|
+
if (defined) {
|
|
57
|
+
const out = {};
|
|
58
|
+
for (const [key, rel] of Object.entries(defined)) {
|
|
59
|
+
out[key] = { propertyKey: key, ...rel };
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const reflectGet = Reflect?.getMetadata?.bind(Reflect);
|
|
65
|
+
return reflectGet ? (reflectGet(RELATIONS_METADATA_KEY, entityClass) || {}) : {};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Convenience decorator for one-to-one relations.
|
|
69
|
+
* @param params - target, optional foreignKey, and extra options
|
|
70
|
+
* @returns Property decorator function
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* class User {
|
|
74
|
+
* @OneToOne({ target: 'profiles', foreignKey: 'userId' }) profile?: Profile
|
|
75
|
+
* }
|
|
76
|
+
*/
|
|
77
|
+
export function OneToOne(params) {
|
|
78
|
+
return Relation({
|
|
79
|
+
type: 'one-to-one',
|
|
80
|
+
target: params.target,
|
|
81
|
+
foreignKey: params.foreignKey,
|
|
82
|
+
...params.options,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Convenience decorator for one-to-many relations.
|
|
87
|
+
* @param params - target, required foreignKey, and extra options
|
|
88
|
+
* @returns Property decorator function
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* class User { @OneToMany(
|
|
92
|
+
* { target: 'posts', foreignKey: 'authorId' }) posts?: Post[]
|
|
93
|
+
* }
|
|
94
|
+
*/
|
|
95
|
+
export function OneToMany(params) {
|
|
96
|
+
return Relation({
|
|
97
|
+
type: 'one-to-many',
|
|
98
|
+
target: params.target,
|
|
99
|
+
foreignKey: params.foreignKey,
|
|
100
|
+
...params.options,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Convenience decorator for many-to-many relations.
|
|
105
|
+
* @param params - target, joinTable, and extra options
|
|
106
|
+
* @returns Property decorator function
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* class Post {
|
|
110
|
+
* @ManyToMany({ target: 'tags', joinTable: 'post_tags' }) tags?: Tag[]
|
|
111
|
+
* }
|
|
112
|
+
*/
|
|
113
|
+
export function ManyToMany(params) {
|
|
114
|
+
return Relation({
|
|
115
|
+
type: 'many-to-many',
|
|
116
|
+
target: params.target,
|
|
117
|
+
joinTable: params.joinTable,
|
|
118
|
+
...params.options,
|
|
119
|
+
});
|
|
120
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Database } from './Database';
|
|
2
|
+
export { ValidationError } from './errors/ValidationError';
|
|
3
|
+
export { Entity, ManyToMany, OneToMany, OneToOne, Relation, } from './metadata';
|
|
4
|
+
export { BaseEntity } from './services/BaseEntity';
|
|
5
|
+
export { newEntity } from './services/EntityFactory';
|
|
6
|
+
export { defineEntity } from './services/EntityRegistry';
|
|
7
|
+
export { EntitySchema } from './services/EntitySchema';
|
|
8
|
+
export type { CloudSyncConfig, DatabaseConfig, EntityConstructor, EntityInstance, } from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Database } from './Database';
|
|
2
|
+
export { ValidationError } from './errors/ValidationError';
|
|
3
|
+
export { Entity, ManyToMany, OneToMany, OneToOne, Relation, } from './metadata';
|
|
4
|
+
export { BaseEntity } from './services/BaseEntity';
|
|
5
|
+
export { newEntity } from './services/EntityFactory';
|
|
6
|
+
export { defineEntity } from './services/EntityRegistry';
|
|
7
|
+
export { EntitySchema } from './services/EntitySchema';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type ClassConstructor<T = unknown> = abstract new (..._args: never[]) => T;
|
|
2
|
+
import type { ColumnOptions, CompoundIndexOptions } from '../types';
|
|
3
|
+
export interface ColumnMetadata extends ColumnOptions {
|
|
4
|
+
propertyKey: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getColumnMetadata(target: object | ClassConstructor): Record<string, ColumnMetadata>;
|
|
7
|
+
export declare function getCompoundIndexMetadata(target: object | ClassConstructor): CompoundIndexOptions[];
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getDefinedColumns, getDefinedCompoundIndexes, } from '../services/EntityRegistry';
|
|
2
|
+
const COLUMNS_METADATA_KEY = Symbol('columns');
|
|
3
|
+
const COMPOUND_INDEXES_METADATA_KEY = Symbol('compoundIndexes');
|
|
4
|
+
export function getColumnMetadata(target) {
|
|
5
|
+
const ctor = (typeof target === 'function')
|
|
6
|
+
? target
|
|
7
|
+
: target.constructor;
|
|
8
|
+
const defined = getDefinedColumns(ctor);
|
|
9
|
+
if (defined) {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const [key, cfg] of Object.entries(defined)) {
|
|
12
|
+
out[key] = { propertyKey: key, ...cfg };
|
|
13
|
+
}
|
|
14
|
+
const hasPrimary = Object.values(out).some(c => c.primaryKey);
|
|
15
|
+
if (!hasPrimary) {
|
|
16
|
+
if (!out.id) {
|
|
17
|
+
out.id = { propertyKey: 'id', primaryKey: true, autoIncrement: true };
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
out.id.primaryKey = true;
|
|
21
|
+
if (out.id.autoIncrement === undefined) {
|
|
22
|
+
out.id.autoIncrement = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
const reflectGet = Reflect?.getMetadata?.bind(Reflect);
|
|
30
|
+
return reflectGet ? (reflectGet(COLUMNS_METADATA_KEY, ctor) || {}) : {};
|
|
31
|
+
}
|
|
32
|
+
export function getCompoundIndexMetadata(target) {
|
|
33
|
+
const ctor = (typeof target === 'function')
|
|
34
|
+
? target
|
|
35
|
+
: target.constructor;
|
|
36
|
+
const defined = getDefinedCompoundIndexes(ctor);
|
|
37
|
+
if (defined) {
|
|
38
|
+
return defined
|
|
39
|
+
.map(ci => ({ name: ci.name, unique: ci.unique, columns: ci.columns }));
|
|
40
|
+
}
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
const reflectGet = Reflect?.getMetadata?.bind(Reflect);
|
|
43
|
+
return reflectGet ? (reflectGet(COMPOUND_INDEXES_METADATA_KEY, ctor) || []) : [];
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
type ClassConstructor<T = unknown> = abstract new (..._args: never[]) => T;
|
|
3
|
+
import type { EntityOptions } from '../types';
|
|
4
|
+
export interface EntityMetadata {
|
|
5
|
+
tableName: string;
|
|
6
|
+
schema?: z.ZodSchema<unknown>;
|
|
7
|
+
timestamps?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function Entity(_options?: EntityOptions): (_target: ClassConstructor) => void;
|
|
10
|
+
export declare function getEntityMetadata(target: ClassConstructor): EntityMetadata | undefined;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getDefinedEntityMeta } from '../services/EntityRegistry';
|
|
2
|
+
const ENTITY_METADATA_KEY = Symbol('entity');
|
|
3
|
+
export function Entity(_options = {}) {
|
|
4
|
+
return function (_target) { };
|
|
5
|
+
}
|
|
6
|
+
export function getEntityMetadata(target) {
|
|
7
|
+
const defined = getDefinedEntityMeta(target);
|
|
8
|
+
if (defined) {
|
|
9
|
+
return {
|
|
10
|
+
tableName: defined.tableName,
|
|
11
|
+
schema: defined.schema,
|
|
12
|
+
timestamps: defined.timestamps,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
const reflectGet = Reflect?.getMetadata?.bind(Reflect);
|
|
17
|
+
if (reflectGet) {
|
|
18
|
+
return reflectGet(ENTITY_METADATA_KEY, target);
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type ClassConstructor<T = unknown> = abstract new (..._args: never[]) => T;
|
|
2
|
+
import type { EntityConstructor, RelationMetadata, RelationOptions } from '../types';
|
|
3
|
+
export declare function Relation(options: RelationOptions): (..._args: unknown[]) => void;
|
|
4
|
+
export declare function getRelationMetadata(entityClass: ClassConstructor): Record<string, RelationMetadata> | undefined;
|
|
5
|
+
export declare function OneToOne(params: {
|
|
6
|
+
target: EntityConstructor | string;
|
|
7
|
+
foreignKey?: string;
|
|
8
|
+
options?: Partial<RelationOptions>;
|
|
9
|
+
}): (..._args: unknown[]) => void;
|
|
10
|
+
export declare function OneToMany(params: {
|
|
11
|
+
target: EntityConstructor | string;
|
|
12
|
+
foreignKey: string;
|
|
13
|
+
options?: Partial<RelationOptions>;
|
|
14
|
+
}): (..._args: unknown[]) => void;
|
|
15
|
+
export declare function ManyToMany(params: {
|
|
16
|
+
target: EntityConstructor | string;
|
|
17
|
+
joinTable: string;
|
|
18
|
+
options?: Partial<RelationOptions>;
|
|
19
|
+
}): (..._args: unknown[]) => void;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function isLegacyArgs(args) {
|
|
2
|
+
return Array.isArray(args) && typeof args[1] === 'string';
|
|
3
|
+
}
|
|
4
|
+
function isFieldContext(args) {
|
|
5
|
+
const ctx = args[1];
|
|
6
|
+
return !!ctx && typeof ctx === 'object' && ctx.kind === 'field' && typeof ctx.name === 'string';
|
|
7
|
+
}
|
|
8
|
+
import { getDefinedRelations } from '../services/EntityRegistry';
|
|
9
|
+
const RELATIONS_METADATA_KEY = Symbol('relations');
|
|
10
|
+
export function Relation(options) {
|
|
11
|
+
return function (...args) {
|
|
12
|
+
const apply = (ctor, propertyKey) => {
|
|
13
|
+
const existingRelations = getRelationMetadata(ctor) || {};
|
|
14
|
+
const relationMetadata = { propertyKey, ...options };
|
|
15
|
+
existingRelations[propertyKey] = relationMetadata;
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
const reflectDefine = Reflect?.defineMetadata?.bind(Reflect);
|
|
18
|
+
if (reflectDefine) {
|
|
19
|
+
reflectDefine(RELATIONS_METADATA_KEY, existingRelations, ctor);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
if (isLegacyArgs(args)) {
|
|
23
|
+
const [target, propertyKey] = args;
|
|
24
|
+
apply(target.constructor, propertyKey);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (isFieldContext(args)) {
|
|
28
|
+
const [, context] = args;
|
|
29
|
+
const propertyKey = context.name;
|
|
30
|
+
context.addInitializer(function (_this) {
|
|
31
|
+
apply(_this.constructor, propertyKey);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function getRelationMetadata(entityClass) {
|
|
37
|
+
const defined = getDefinedRelations(entityClass);
|
|
38
|
+
if (defined) {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [key, rel] of Object.entries(defined)) {
|
|
41
|
+
out[key] = { propertyKey: key, ...rel };
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
+
const reflectGet = Reflect?.getMetadata?.bind(Reflect);
|
|
47
|
+
return reflectGet
|
|
48
|
+
? (reflectGet(RELATIONS_METADATA_KEY, entityClass) || {})
|
|
49
|
+
: {};
|
|
50
|
+
}
|
|
51
|
+
export function OneToOne(params) {
|
|
52
|
+
return Relation({
|
|
53
|
+
type: 'one-to-one',
|
|
54
|
+
target: params.target,
|
|
55
|
+
foreignKey: params.foreignKey,
|
|
56
|
+
...params.options,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export function OneToMany(params) {
|
|
60
|
+
return Relation({
|
|
61
|
+
type: 'one-to-many',
|
|
62
|
+
target: params.target,
|
|
63
|
+
foreignKey: params.foreignKey,
|
|
64
|
+
...params.options,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function ManyToMany(params) {
|
|
68
|
+
return Relation({
|
|
69
|
+
type: 'many-to-many',
|
|
70
|
+
target: params.target,
|
|
71
|
+
joinTable: params.joinTable,
|
|
72
|
+
...params.options,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Database } from '../Database';
|
|
2
|
+
import type { AggregationOptions, AggregationResult, EntityConstructor } from '../types';
|
|
3
|
+
import { BaseEntity } from './BaseEntity';
|
|
4
|
+
export declare class AggregationService {
|
|
5
|
+
private db;
|
|
6
|
+
constructor(database: Database);
|
|
7
|
+
/**
|
|
8
|
+
* Perform aggregation operations on entity data
|
|
9
|
+
* @param entityClass - The entity class to aggregate
|
|
10
|
+
* @param options - Aggregation options including filters, sorting, grouping, etc.
|
|
11
|
+
* @returns Promise resolving to aggregation results
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const result = await aggregationService.aggregate(Post, {
|
|
15
|
+
* where: { category: 'tech' },
|
|
16
|
+
* sort: { field: 'views', direction: 'desc' },
|
|
17
|
+
* limit: 10,
|
|
18
|
+
* count: true,
|
|
19
|
+
* sum: ['views'],
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
aggregate<T extends BaseEntity>(entityClass: EntityConstructor<T>, options: AggregationOptions<T>): Promise<AggregationResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Load a specific relation based on metadata.
|
|
25
|
+
* @param entity - The source entity to load relation for
|
|
26
|
+
* @param relationMeta - Relation metadata (type, target, keys)
|
|
27
|
+
* @returns Promise resolving to the loaded relation data
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const related = await (aggregationService as any).loadRelation(record, {
|
|
31
|
+
* type: 'one-to-many', target: Post, foreignKey: 'authorId',
|
|
32
|
+
* });
|
|
33
|
+
*/
|
|
34
|
+
private loadRelation;
|
|
35
|
+
private loadOneToOne;
|
|
36
|
+
private loadOneToMany;
|
|
37
|
+
private loadManyToMany;
|
|
38
|
+
}
|