@e22m4u/js-repository 0.0.31
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/.c8rc +9 -0
- package/.commitlintrc +5 -0
- package/.editorconfig +13 -0
- package/.eslintignore +1 -0
- package/.eslintrc.cjs +27 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +9 -0
- package/.mocharc.cjs +7 -0
- package/.prettierrc +7 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/mocha.setup.js +10 -0
- package/package.json +57 -0
- package/src/adapter/adapter-loader.d.ts +16 -0
- package/src/adapter/adapter-loader.js +63 -0
- package/src/adapter/adapter-loader.spec.js +31 -0
- package/src/adapter/adapter-registry.d.ts +14 -0
- package/src/adapter/adapter-registry.js +36 -0
- package/src/adapter/adapter-registry.spec.js +36 -0
- package/src/adapter/adapter.d.ts +118 -0
- package/src/adapter/adapter.js +181 -0
- package/src/adapter/adapter.spec.js +144 -0
- package/src/adapter/builtin/memory-adapter.d.ts +118 -0
- package/src/adapter/builtin/memory-adapter.js +342 -0
- package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
- package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
- package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
- package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
- package/src/adapter/decorator/data-validation-decorator.js +41 -0
- package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
- package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
- package/src/adapter/decorator/default-values-decorator.js +57 -0
- package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
- package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
- package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
- package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
- package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
- package/src/adapter/decorator/inclusion-decorator.js +78 -0
- package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
- package/src/adapter/decorator/index.d.ts +5 -0
- package/src/adapter/decorator/index.js +5 -0
- package/src/adapter/index.d.ts +3 -0
- package/src/adapter/index.js +3 -0
- package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
- package/src/definition/datasource/datasource-definition-validator.js +33 -0
- package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
- package/src/definition/datasource/datasource-definition.d.ts +7 -0
- package/src/definition/datasource/index.d.ts +2 -0
- package/src/definition/datasource/index.js +1 -0
- package/src/definition/definition-registry.d.ts +50 -0
- package/src/definition/definition-registry.js +98 -0
- package/src/definition/definition-registry.spec.js +78 -0
- package/src/definition/index.d.ts +3 -0
- package/src/definition/index.js +3 -0
- package/src/definition/model/index.d.ts +7 -0
- package/src/definition/model/index.js +6 -0
- package/src/definition/model/model-data-sanitizer.d.ts +15 -0
- package/src/definition/model/model-data-sanitizer.js +33 -0
- package/src/definition/model/model-data-validator.d.ts +32 -0
- package/src/definition/model/model-data-validator.js +144 -0
- package/src/definition/model/model-data-validator.spec.js +1889 -0
- package/src/definition/model/model-definition-utils.d.ts +161 -0
- package/src/definition/model/model-definition-utils.js +371 -0
- package/src/definition/model/model-definition-utils.spec.js +1474 -0
- package/src/definition/model/model-definition-validator.d.ts +14 -0
- package/src/definition/model/model-definition-validator.js +83 -0
- package/src/definition/model/model-definition-validator.spec.js +143 -0
- package/src/definition/model/model-definition.d.ts +28 -0
- package/src/definition/model/properties/data-type.d.ts +11 -0
- package/src/definition/model/properties/data-type.js +11 -0
- package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/default-values-definition-validator.js +53 -0
- package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
- package/src/definition/model/properties/index.d.ts +5 -0
- package/src/definition/model/properties/index.js +4 -0
- package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
- package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
- package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
- package/src/definition/model/properties/properties-definition-validator.js +194 -0
- package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
- package/src/definition/model/properties/property-definition.d.ts +20 -0
- package/src/definition/model/relations/index.d.ts +3 -0
- package/src/definition/model/relations/index.js +2 -0
- package/src/definition/model/relations/relation-definition.d.ts +254 -0
- package/src/definition/model/relations/relation-type.d.ts +9 -0
- package/src/definition/model/relations/relation-type.js +9 -0
- package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
- package/src/definition/model/relations/relations-definition-validator.js +449 -0
- package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
- package/src/errors/index.d.ts +3 -0
- package/src/errors/index.js +3 -0
- package/src/errors/invalid-argument-error.d.ts +6 -0
- package/src/errors/invalid-argument-error.js +6 -0
- package/src/errors/invalid-argument-error.spec.js +33 -0
- package/src/errors/invalid-operator-value-error.d.ts +13 -0
- package/src/errors/invalid-operator-value-error.js +24 -0
- package/src/errors/invalid-operator-value-error.spec.js +11 -0
- package/src/errors/not-implemented-error.d.ts +6 -0
- package/src/errors/not-implemented-error.js +6 -0
- package/src/errors/not-implemented-error.spec.js +33 -0
- package/src/filter/fields-clause-tool.d.ts +38 -0
- package/src/filter/fields-clause-tool.js +88 -0
- package/src/filter/fields-clause-tool.spec.js +133 -0
- package/src/filter/filter.d.ts +335 -0
- package/src/filter/include-clause-tool.d.ts +53 -0
- package/src/filter/include-clause-tool.js +364 -0
- package/src/filter/include-clause-tool.spec.js +653 -0
- package/src/filter/index.d.ts +7 -0
- package/src/filter/index.js +6 -0
- package/src/filter/operator-clause-tool.d.ts +223 -0
- package/src/filter/operator-clause-tool.js +515 -0
- package/src/filter/operator-clause-tool.spec.js +1064 -0
- package/src/filter/order-clause-tool.d.ts +32 -0
- package/src/filter/order-clause-tool.js +97 -0
- package/src/filter/order-clause-tool.spec.js +438 -0
- package/src/filter/slice-clause-tool.d.ts +30 -0
- package/src/filter/slice-clause-tool.js +65 -0
- package/src/filter/slice-clause-tool.spec.js +117 -0
- package/src/filter/where-clause-tool.d.ts +23 -0
- package/src/filter/where-clause-tool.js +165 -0
- package/src/filter/where-clause-tool.spec.js +280 -0
- package/src/index.d.ts +9 -0
- package/src/index.js +8 -0
- package/src/relations/belongs-to-resolver.d.ts +46 -0
- package/src/relations/belongs-to-resolver.js +242 -0
- package/src/relations/belongs-to-resolver.spec.js +1047 -0
- package/src/relations/has-many-resolver.d.ts +67 -0
- package/src/relations/has-many-resolver.js +317 -0
- package/src/relations/has-many-resolver.spec.js +2911 -0
- package/src/relations/has-one-resolver.d.ts +67 -0
- package/src/relations/has-one-resolver.js +311 -0
- package/src/relations/has-one-resolver.spec.js +2274 -0
- package/src/relations/index.d.ts +4 -0
- package/src/relations/index.js +4 -0
- package/src/relations/references-many-resolver.d.ts +27 -0
- package/src/relations/references-many-resolver.js +113 -0
- package/src/relations/references-many-resolver.spec.js +631 -0
- package/src/repository/index.d.ts +2 -0
- package/src/repository/index.js +2 -0
- package/src/repository/repository-registry.d.ts +29 -0
- package/src/repository/repository-registry.js +57 -0
- package/src/repository/repository-registry.spec.js +38 -0
- package/src/repository/repository.d.ts +164 -0
- package/src/repository/repository.js +207 -0
- package/src/repository/repository.spec.js +202 -0
- package/src/schema.d.ts +37 -0
- package/src/schema.js +41 -0
- package/src/types.d.ts +30 -0
- package/src/utils/capitalize.d.ts +6 -0
- package/src/utils/capitalize.js +10 -0
- package/src/utils/capitalize.spec.js +14 -0
- package/src/utils/clone-deep.d.ts +6 -0
- package/src/utils/clone-deep.js +61 -0
- package/src/utils/clone-deep.spec.js +28 -0
- package/src/utils/exclude-object-keys.d.ts +10 -0
- package/src/utils/exclude-object-keys.js +20 -0
- package/src/utils/exclude-object-keys.spec.js +49 -0
- package/src/utils/get-ctor-name.d.ts +6 -0
- package/src/utils/get-ctor-name.js +11 -0
- package/src/utils/get-ctor-name.spec.js +17 -0
- package/src/utils/get-value-by-path.d.ts +12 -0
- package/src/utils/get-value-by-path.js +23 -0
- package/src/utils/get-value-by-path.spec.js +36 -0
- package/src/utils/index.d.ts +10 -0
- package/src/utils/index.js +10 -0
- package/src/utils/is-ctor.d.ts +7 -0
- package/src/utils/is-ctor.js +10 -0
- package/src/utils/is-ctor.spec.js +26 -0
- package/src/utils/is-pure-object.d.ts +6 -0
- package/src/utils/is-pure-object.js +15 -0
- package/src/utils/is-pure-object.spec.js +25 -0
- package/src/utils/select-object-keys.d.ts +10 -0
- package/src/utils/select-object-keys.js +37 -0
- package/src/utils/select-object-keys.spec.js +40 -0
- package/src/utils/singularize.d.ts +6 -0
- package/src/utils/singularize.js +22 -0
- package/src/utils/singularize.spec.js +23 -0
- package/src/utils/string-to-regexp.d.ts +10 -0
- package/src/utils/string-to-regexp.js +22 -0
- package/src/utils/string-to-regexp.spec.js +35 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {Service} from '@e22m4u/js-service';
|
|
2
|
+
import {Repository} from './repository.js';
|
|
3
|
+
import {InvalidArgumentError} from '../errors/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Repository registry.
|
|
7
|
+
*/
|
|
8
|
+
export class RepositoryRegistry extends Service {
|
|
9
|
+
/**
|
|
10
|
+
* Repositories.
|
|
11
|
+
*
|
|
12
|
+
* @type {object}
|
|
13
|
+
*/
|
|
14
|
+
_repositories = {};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Repository ctor.
|
|
18
|
+
*
|
|
19
|
+
* @type {typeof Repository}
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
_repositoryCtor = Repository;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Set repository ctor.
|
|
26
|
+
*
|
|
27
|
+
* @param {typeof Repository} ctor
|
|
28
|
+
*/
|
|
29
|
+
setRepositoryCtor(ctor) {
|
|
30
|
+
if (
|
|
31
|
+
!ctor ||
|
|
32
|
+
typeof ctor !== 'function' ||
|
|
33
|
+
!(ctor.prototype instanceof Repository)
|
|
34
|
+
) {
|
|
35
|
+
throw new InvalidArgumentError(
|
|
36
|
+
'The first argument of RepositoryRegistry.setRepositoryCtor ' +
|
|
37
|
+
'must inherit from Repository class, but %v given.',
|
|
38
|
+
ctor,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
this._repositoryCtor = ctor;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get repository.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} modelName
|
|
48
|
+
* @returns {Repository}
|
|
49
|
+
*/
|
|
50
|
+
getRepository(modelName) {
|
|
51
|
+
let repository = this._repositories[modelName];
|
|
52
|
+
if (repository) return repository;
|
|
53
|
+
repository = new this._repositoryCtor(this.container, modelName);
|
|
54
|
+
this._repositories[modelName] = repository;
|
|
55
|
+
return repository;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {Schema} from '../schema.js';
|
|
3
|
+
import {Repository} from './repository.js';
|
|
4
|
+
import {RepositoryRegistry} from './repository-registry.js';
|
|
5
|
+
|
|
6
|
+
describe('RepositoryRegistry', function () {
|
|
7
|
+
describe('setRepositoryCtor', function () {
|
|
8
|
+
it('sets a given class as the repository constructor', function () {
|
|
9
|
+
class MyRepository extends Repository {}
|
|
10
|
+
const schema = new Schema();
|
|
11
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
12
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
13
|
+
const registry = schema.getService(RepositoryRegistry);
|
|
14
|
+
registry.setRepositoryCtor(MyRepository);
|
|
15
|
+
const rep = registry.getRepository('model');
|
|
16
|
+
expect(rep).to.be.instanceof(Repository);
|
|
17
|
+
expect(rep).to.be.instanceof(MyRepository);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('getRepository', function () {
|
|
22
|
+
it('uses a given model name to return an existing repository or create the new', function () {
|
|
23
|
+
const schema = new Schema();
|
|
24
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
25
|
+
schema.defineModel({name: 'modelA', datasource: 'datasource'});
|
|
26
|
+
schema.defineModel({name: 'modelB', datasource: 'datasource'});
|
|
27
|
+
const registry = schema.getService(RepositoryRegistry);
|
|
28
|
+
const repA1 = registry.getRepository('modelA');
|
|
29
|
+
const repA2 = registry.getRepository('modelA');
|
|
30
|
+
const repB1 = registry.getRepository('modelB');
|
|
31
|
+
const repB2 = registry.getRepository('modelB');
|
|
32
|
+
expect(repA1).to.be.eq(repA2);
|
|
33
|
+
expect(repB1).to.be.eq(repB2);
|
|
34
|
+
expect(repA1).to.be.not.eq(repB1);
|
|
35
|
+
expect(repA2).to.be.not.eq(repB2);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {ModelId} from '../types.js';
|
|
2
|
+
import {Flatten} from '../types.js';
|
|
3
|
+
import {ModelData} from '../types.js';
|
|
4
|
+
import {PartialBy} from '../types.js';
|
|
5
|
+
import {Filter} from '../filter/index.js';
|
|
6
|
+
import {Service} from '@e22m4u/js-service';
|
|
7
|
+
import {Adapter} from '../adapter/index.js';
|
|
8
|
+
import {ItemFilter} from '../filter/index.js';
|
|
9
|
+
import {WhereClause} from '../filter/index.js';
|
|
10
|
+
import {ServiceContainer} from '@e22m4u/js-service';
|
|
11
|
+
import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from '../definition/index.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Repository.
|
|
15
|
+
*/
|
|
16
|
+
export declare class Repository<
|
|
17
|
+
Data extends ModelData = ModelData,
|
|
18
|
+
IdType extends ModelId = ModelId,
|
|
19
|
+
IdName extends string = DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
|
|
20
|
+
FlatData extends ModelData = Flatten<Data>,
|
|
21
|
+
> extends Service {
|
|
22
|
+
/**
|
|
23
|
+
* Model name.
|
|
24
|
+
*/
|
|
25
|
+
get modelName(): string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Datasource name.
|
|
29
|
+
*/
|
|
30
|
+
get datasourceName(): string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Constructor.
|
|
34
|
+
*
|
|
35
|
+
* @param container
|
|
36
|
+
* @param modelName
|
|
37
|
+
*/
|
|
38
|
+
constructor(container: ServiceContainer, modelName: string);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get adapter.
|
|
42
|
+
*/
|
|
43
|
+
getAdapter(): Promise<Adapter>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create.
|
|
47
|
+
*
|
|
48
|
+
* @param data
|
|
49
|
+
* @param filter
|
|
50
|
+
*/
|
|
51
|
+
create(
|
|
52
|
+
data: OptionalUnlessRequiredId<IdName, FlatData>,
|
|
53
|
+
filter?: ItemFilter,
|
|
54
|
+
): Promise<FlatData>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Replace by id.
|
|
58
|
+
*
|
|
59
|
+
* @param id
|
|
60
|
+
* @param data
|
|
61
|
+
* @param filter
|
|
62
|
+
*/
|
|
63
|
+
replaceById(
|
|
64
|
+
id: IdType,
|
|
65
|
+
data: WithoutId<IdName, FlatData>,
|
|
66
|
+
filter?: ItemFilter,
|
|
67
|
+
): Promise<FlatData>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Replace or create.
|
|
71
|
+
*
|
|
72
|
+
* @param data
|
|
73
|
+
* @param filter
|
|
74
|
+
*/
|
|
75
|
+
replaceOrCreate(
|
|
76
|
+
data: OptionalUnlessRequiredId<IdName, Data>,
|
|
77
|
+
filter?: ItemFilter,
|
|
78
|
+
): Promise<FlatData>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Patch by id.
|
|
82
|
+
*
|
|
83
|
+
* @param id
|
|
84
|
+
* @param data
|
|
85
|
+
* @param filter
|
|
86
|
+
*/
|
|
87
|
+
patchById(
|
|
88
|
+
id: IdType,
|
|
89
|
+
data: PartialWithoutId<IdName, Data>,
|
|
90
|
+
filter?: ItemFilter,
|
|
91
|
+
): Promise<FlatData>;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Find.
|
|
95
|
+
*
|
|
96
|
+
* @param filter
|
|
97
|
+
*/
|
|
98
|
+
find(filter?: Filter): Promise<FlatData[]>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Find one.
|
|
102
|
+
*
|
|
103
|
+
* @param filter
|
|
104
|
+
*/
|
|
105
|
+
findOne(filter?: ItemFilter): Promise<FlatData | undefined>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Find by id.
|
|
109
|
+
*
|
|
110
|
+
* @param id
|
|
111
|
+
* @param filter
|
|
112
|
+
*/
|
|
113
|
+
findById(id: IdType, filter?: ItemFilter): Promise<FlatData>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Delete.
|
|
117
|
+
*
|
|
118
|
+
* @param where
|
|
119
|
+
*/
|
|
120
|
+
delete(where?: WhereClause): Promise<number>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Delete by id.
|
|
124
|
+
*
|
|
125
|
+
* @param id
|
|
126
|
+
*/
|
|
127
|
+
deleteById(id: IdType): Promise<boolean>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Exists.
|
|
131
|
+
*
|
|
132
|
+
* @param id
|
|
133
|
+
*/
|
|
134
|
+
exists(id: IdType): Promise<boolean>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Count.
|
|
138
|
+
*
|
|
139
|
+
* @param where
|
|
140
|
+
*/
|
|
141
|
+
count(where?: WhereClause): Promise<number>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Removes id field.
|
|
146
|
+
*/
|
|
147
|
+
type WithoutId<IdName extends string, Data extends ModelData> = Flatten<
|
|
148
|
+
Omit<Data, IdName>
|
|
149
|
+
>;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Makes fields as optional and remove id field.
|
|
153
|
+
*/
|
|
154
|
+
type PartialWithoutId<IdName extends string, Data extends ModelData> = Flatten<
|
|
155
|
+
Partial<Omit<Data, IdName>>
|
|
156
|
+
>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Makes the required id field as optional.
|
|
160
|
+
*/
|
|
161
|
+
type OptionalUnlessRequiredId<
|
|
162
|
+
IdName extends string,
|
|
163
|
+
Data extends ModelData,
|
|
164
|
+
> = Flatten<Data extends {[K in IdName]: any} ? PartialBy<Data, IdName> : Data>;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {Service} from '@e22m4u/js-service';
|
|
2
|
+
import {Adapter} from '../adapter/index.js';
|
|
3
|
+
import {AdapterRegistry} from '../adapter/index.js';
|
|
4
|
+
import {InvalidArgumentError} from '../errors/index.js';
|
|
5
|
+
import {DefinitionRegistry} from '../definition/index.js';
|
|
6
|
+
import {ModelDefinitionUtils} from '../definition/index.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Repository.
|
|
10
|
+
*/
|
|
11
|
+
export class Repository extends Service {
|
|
12
|
+
/**
|
|
13
|
+
* Model name.
|
|
14
|
+
*
|
|
15
|
+
* @type {string}
|
|
16
|
+
*/
|
|
17
|
+
_modelName;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Model name.
|
|
21
|
+
*
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
get modelName() {
|
|
25
|
+
return this._modelName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Datasource name.
|
|
30
|
+
*
|
|
31
|
+
* @type {string}
|
|
32
|
+
*/
|
|
33
|
+
_datasourceName;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Datasource name.
|
|
37
|
+
*
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
get datasourceName() {
|
|
41
|
+
return this._datasourceName;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Constructor.
|
|
46
|
+
*
|
|
47
|
+
* @typedef {import('@e22m4u/js-service').ServiceContainer} ServiceContainer
|
|
48
|
+
* @param {ServiceContainer} container
|
|
49
|
+
* @param {string} modelName
|
|
50
|
+
*/
|
|
51
|
+
constructor(container, modelName) {
|
|
52
|
+
super(container);
|
|
53
|
+
this._modelName = modelName;
|
|
54
|
+
const modelDef = this.getService(DefinitionRegistry).getModel(modelName);
|
|
55
|
+
const datasourceName = modelDef.datasource;
|
|
56
|
+
if (!datasourceName)
|
|
57
|
+
throw new InvalidArgumentError(
|
|
58
|
+
'The model %v does not have a specified datasource.',
|
|
59
|
+
modelName,
|
|
60
|
+
);
|
|
61
|
+
this._datasourceName = datasourceName;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get adapter.
|
|
66
|
+
*
|
|
67
|
+
* @returns {Adapter}
|
|
68
|
+
*/
|
|
69
|
+
async getAdapter() {
|
|
70
|
+
return this.getService(AdapterRegistry).getAdapter(this.datasourceName);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create.
|
|
75
|
+
*
|
|
76
|
+
* @param {object} data
|
|
77
|
+
* @param {object|undefined} filter
|
|
78
|
+
* @returns {Promise<object>}
|
|
79
|
+
*/
|
|
80
|
+
async create(data, filter = undefined) {
|
|
81
|
+
const adapter = await this.getAdapter();
|
|
82
|
+
return adapter.create(this.modelName, data, filter);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Replace by id.
|
|
87
|
+
*
|
|
88
|
+
* @param {number|string} id
|
|
89
|
+
* @param {object} data
|
|
90
|
+
* @param {object|undefined} filter
|
|
91
|
+
* @returns {Promise<object>}
|
|
92
|
+
*/
|
|
93
|
+
async replaceById(id, data, filter = undefined) {
|
|
94
|
+
const adapter = await this.getAdapter();
|
|
95
|
+
return adapter.replaceById(this.modelName, id, data, filter);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Replace or create.
|
|
100
|
+
*
|
|
101
|
+
* @param {object} data
|
|
102
|
+
* @param {object|undefined} filter
|
|
103
|
+
* @returns {Promise<object>}
|
|
104
|
+
*/
|
|
105
|
+
async replaceOrCreate(data, filter = undefined) {
|
|
106
|
+
const pkPropName = this.getService(
|
|
107
|
+
ModelDefinitionUtils,
|
|
108
|
+
).getPrimaryKeyAsPropertyName(this.modelName);
|
|
109
|
+
const pkValue = data[pkPropName];
|
|
110
|
+
if (pkValue == null) return this.create(data, filter);
|
|
111
|
+
return this.replaceById(pkValue, data, filter);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Patch by id.
|
|
116
|
+
*
|
|
117
|
+
* @param {number|string} id
|
|
118
|
+
* @param {object} data
|
|
119
|
+
* @param {object|undefined} filter
|
|
120
|
+
* @returns {Promise<object>}
|
|
121
|
+
*/
|
|
122
|
+
async patchById(id, data, filter = undefined) {
|
|
123
|
+
const adapter = await this.getAdapter();
|
|
124
|
+
return adapter.patchById(this.modelName, id, data, filter);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Find.
|
|
129
|
+
*
|
|
130
|
+
* @param {object|undefined} filter
|
|
131
|
+
* @returns {Promise<object[]>}
|
|
132
|
+
*/
|
|
133
|
+
async find(filter = undefined) {
|
|
134
|
+
const adapter = await this.getAdapter();
|
|
135
|
+
return adapter.find(this.modelName, filter);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Find one.
|
|
140
|
+
*
|
|
141
|
+
* @param {object|undefined} filter
|
|
142
|
+
* @returns {Promise<object|undefined>}
|
|
143
|
+
*/
|
|
144
|
+
async findOne(filter = undefined) {
|
|
145
|
+
const adapter = await this.getAdapter();
|
|
146
|
+
filter = filter ?? {};
|
|
147
|
+
filter.limit = 1;
|
|
148
|
+
const result = await adapter.find(this.modelName, filter);
|
|
149
|
+
return result.length ? result[0] : undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Find by id.
|
|
154
|
+
*
|
|
155
|
+
* @param {number|string} id
|
|
156
|
+
* @param {object|undefined} filter
|
|
157
|
+
* @returns {Promise<object>}
|
|
158
|
+
*/
|
|
159
|
+
async findById(id, filter = undefined) {
|
|
160
|
+
const adapter = await this.getAdapter();
|
|
161
|
+
return adapter.findById(this.modelName, id, filter);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Delete.
|
|
166
|
+
*
|
|
167
|
+
* @param {object|undefined} where
|
|
168
|
+
* @returns {Promise<number>}
|
|
169
|
+
*/
|
|
170
|
+
async delete(where = undefined) {
|
|
171
|
+
const adapter = await this.getAdapter();
|
|
172
|
+
return adapter.delete(this.modelName, where);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Delete by id.
|
|
177
|
+
*
|
|
178
|
+
* @param {number|string} id
|
|
179
|
+
* @returns {Promise<boolean>}
|
|
180
|
+
*/
|
|
181
|
+
async deleteById(id) {
|
|
182
|
+
const adapter = await this.getAdapter();
|
|
183
|
+
return adapter.deleteById(this.modelName, id);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Exists.
|
|
188
|
+
*
|
|
189
|
+
* @param {number|string} id
|
|
190
|
+
* @returns {Promise<boolean>}
|
|
191
|
+
*/
|
|
192
|
+
async exists(id) {
|
|
193
|
+
const adapter = await this.getAdapter();
|
|
194
|
+
return adapter.exists(this.modelName, id);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Count.
|
|
199
|
+
*
|
|
200
|
+
* @param {object|undefined} where
|
|
201
|
+
* @returns {Promise<number>}
|
|
202
|
+
*/
|
|
203
|
+
async count(where = undefined) {
|
|
204
|
+
const adapter = await this.getAdapter();
|
|
205
|
+
return adapter.count(this.modelName, where);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {Schema} from '../schema.js';
|
|
3
|
+
import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
|
|
4
|
+
|
|
5
|
+
describe('Repository', function () {
|
|
6
|
+
describe('create', function () {
|
|
7
|
+
it('creates a new item from the given data', async function () {
|
|
8
|
+
const schema = new Schema();
|
|
9
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
10
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
11
|
+
const data = {foo: 'bar'};
|
|
12
|
+
const rep = schema.getRepository('model');
|
|
13
|
+
const result = await rep.create(data);
|
|
14
|
+
expect(result).to.be.eql({[DEF_PK]: result[DEF_PK], ...data});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('replaceById', function () {
|
|
19
|
+
it('replaces an item by the given id', async function () {
|
|
20
|
+
const schema = new Schema();
|
|
21
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
22
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
23
|
+
const rep = schema.getRepository('model');
|
|
24
|
+
const created = await rep.create({foo: 'bar'});
|
|
25
|
+
const result = await rep.replaceById(created[DEF_PK], {baz: 'qux'});
|
|
26
|
+
expect(result).to.be.eql({[DEF_PK]: created[DEF_PK], baz: 'qux'});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('replaceOrCreate', function () {
|
|
31
|
+
it('creates a new item from the given data', async function () {
|
|
32
|
+
const schema = new Schema();
|
|
33
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
34
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
35
|
+
const data = {foo: 'bar'};
|
|
36
|
+
const rep = schema.getRepository('model');
|
|
37
|
+
const result = await rep.replaceOrCreate(data);
|
|
38
|
+
expect(result).to.be.eql({[DEF_PK]: result[DEF_PK], ...data});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('replaces an existing item', async function () {
|
|
42
|
+
const schema = new Schema();
|
|
43
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
44
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
45
|
+
const rep = schema.getRepository('model');
|
|
46
|
+
const created = await rep.create({foo: 'bar'});
|
|
47
|
+
const replacer = {[DEF_PK]: created[DEF_PK], bar: 'qux'};
|
|
48
|
+
const result = await rep.replaceOrCreate(replacer);
|
|
49
|
+
expect(result).to.be.eql(replacer);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('patchById', function () {
|
|
54
|
+
it('patches an item by the given id', async function () {
|
|
55
|
+
const schema = new Schema();
|
|
56
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
57
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
58
|
+
const rep = schema.getRepository('model');
|
|
59
|
+
const created = await rep.create({foo: 'bar'});
|
|
60
|
+
const result = await rep.patchById(created[DEF_PK], {baz: 'qux'});
|
|
61
|
+
expect(result).to.be.eql({
|
|
62
|
+
[DEF_PK]: created[DEF_PK],
|
|
63
|
+
foo: 'bar',
|
|
64
|
+
baz: 'qux',
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('find', function () {
|
|
70
|
+
it('returns all items', async function () {
|
|
71
|
+
const schema = new Schema();
|
|
72
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
73
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
74
|
+
const rep = schema.getRepository('model');
|
|
75
|
+
const created1 = await rep.create({foo: 'bar'});
|
|
76
|
+
const created2 = await rep.create({baz: 'qux'});
|
|
77
|
+
const result = await rep.find();
|
|
78
|
+
expect(result).to.be.eql([created1, created2]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('returns found items by the "where" clause', async function () {
|
|
82
|
+
const schema = new Schema();
|
|
83
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
84
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
85
|
+
const rep = schema.getRepository('model');
|
|
86
|
+
await rep.create({foo: 'bar'});
|
|
87
|
+
const created = await rep.create({baz: 'qux'});
|
|
88
|
+
const result = await rep.find({where: {baz: 'qux'}});
|
|
89
|
+
expect(result).to.be.eql([created]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('findOne', function () {
|
|
94
|
+
it('returns a first item', async function () {
|
|
95
|
+
const schema = new Schema();
|
|
96
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
97
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
98
|
+
const rep = schema.getRepository('model');
|
|
99
|
+
const created = await rep.create({foo: 'bar'});
|
|
100
|
+
await rep.create({baz: 'qux'});
|
|
101
|
+
const result = await rep.findOne();
|
|
102
|
+
expect(result).to.be.eql(created);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('returns a found item by the "where" clause', async function () {
|
|
106
|
+
const schema = new Schema();
|
|
107
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
108
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
109
|
+
const rep = schema.getRepository('model');
|
|
110
|
+
await rep.create({foo: 'bar'});
|
|
111
|
+
const created = await rep.create({baz: 'qux'});
|
|
112
|
+
const result = await rep.findOne({where: {baz: 'qux'}});
|
|
113
|
+
expect(result).to.be.eql(created);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('findById', function () {
|
|
118
|
+
it('returns an item by the given id', async function () {
|
|
119
|
+
const schema = new Schema();
|
|
120
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
121
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
122
|
+
const rep = schema.getRepository('model');
|
|
123
|
+
const created = await rep.create({foo: 'bar'});
|
|
124
|
+
const result = await rep.findById(created[DEF_PK]);
|
|
125
|
+
expect(result).to.be.eql(created);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('delete', function () {
|
|
130
|
+
it('removes all items', async function () {
|
|
131
|
+
const schema = new Schema();
|
|
132
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
133
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
134
|
+
const rep = schema.getRepository('model');
|
|
135
|
+
await rep.create({foo: 'bar'});
|
|
136
|
+
await rep.create({baz: 'qux'});
|
|
137
|
+
const result = await rep.delete();
|
|
138
|
+
expect(result).to.be.eq(2);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('removes found items by the "where" clause', async function () {
|
|
142
|
+
const schema = new Schema();
|
|
143
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
144
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
145
|
+
const rep = schema.getRepository('model');
|
|
146
|
+
await rep.create({foo: 'bar'});
|
|
147
|
+
await rep.create({foo: 'bar'});
|
|
148
|
+
await rep.create({baz: 'qux'});
|
|
149
|
+
const result = await rep.delete({foo: 'bar'});
|
|
150
|
+
expect(result).to.be.eql(2);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('deleteById', function () {
|
|
155
|
+
it('removes an item by the given id', async function () {
|
|
156
|
+
const schema = new Schema();
|
|
157
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
158
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
159
|
+
const rep = schema.getRepository('model');
|
|
160
|
+
const created = await rep.create({foo: 'bar'});
|
|
161
|
+
const result = await rep.deleteById(created[DEF_PK]);
|
|
162
|
+
expect(result).to.be.true;
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('exists', function () {
|
|
167
|
+
it('returns true if the given id exists', async function () {
|
|
168
|
+
const schema = new Schema();
|
|
169
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
170
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
171
|
+
const rep = schema.getRepository('model');
|
|
172
|
+
const created = await rep.create({foo: 'bar'});
|
|
173
|
+
const result = await rep.exists(created[DEF_PK]);
|
|
174
|
+
expect(result).to.be.true;
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('count', function () {
|
|
179
|
+
it('counts all items', async function () {
|
|
180
|
+
const schema = new Schema();
|
|
181
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
182
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
183
|
+
const rep = schema.getRepository('model');
|
|
184
|
+
await rep.create({foo: 'bar'});
|
|
185
|
+
await rep.create({baz: 'qux'});
|
|
186
|
+
const result = await rep.count();
|
|
187
|
+
expect(result).to.be.eq(2);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('counts found items by the "where" clause', async function () {
|
|
191
|
+
const schema = new Schema();
|
|
192
|
+
schema.defineDatasource({name: 'datasource', adapter: 'memory'});
|
|
193
|
+
schema.defineModel({name: 'model', datasource: 'datasource'});
|
|
194
|
+
const rep = schema.getRepository('model');
|
|
195
|
+
await rep.create({foo: 'bar'});
|
|
196
|
+
await rep.create({foo: 'bar'});
|
|
197
|
+
await rep.create({baz: 'qux'});
|
|
198
|
+
const result = await rep.count({foo: 'bar'});
|
|
199
|
+
expect(result).to.be.eq(2);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
});
|
package/src/schema.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {ModelId} from './types.js';
|
|
2
|
+
import {ModelData} from './types.js';
|
|
3
|
+
import {Service} from '@e22m4u/js-service';
|
|
4
|
+
import {Repository} from './repository/index.js';
|
|
5
|
+
import {ModelDefinition} from './definition/index.js';
|
|
6
|
+
import {DatasourceDefinition} from './definition/index.js';
|
|
7
|
+
import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME} from './definition/index.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Schema.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Schema extends Service {
|
|
13
|
+
/**
|
|
14
|
+
* Define datasource.
|
|
15
|
+
*
|
|
16
|
+
* @param datasourceDef
|
|
17
|
+
*/
|
|
18
|
+
defineDatasource(datasourceDef: DatasourceDefinition): this;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Define model.
|
|
22
|
+
*
|
|
23
|
+
* @param modelDef
|
|
24
|
+
*/
|
|
25
|
+
defineModel(modelDef: ModelDefinition): this;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get repository.
|
|
29
|
+
*
|
|
30
|
+
* @param modelName
|
|
31
|
+
*/
|
|
32
|
+
getRepository<
|
|
33
|
+
Data extends ModelData = ModelData,
|
|
34
|
+
IdType extends ModelId = ModelId,
|
|
35
|
+
IdName extends string = DEFAULT_PRIMARY_KEY_PROPERTY_NAME,
|
|
36
|
+
>(modelName: string): Repository<Data, IdType, IdName>;
|
|
37
|
+
}
|