@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.
Files changed (183) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.eslintignore +1 -0
  5. package/.eslintrc.cjs +27 -0
  6. package/.husky/commit-msg +4 -0
  7. package/.husky/pre-commit +9 -0
  8. package/.mocharc.cjs +7 -0
  9. package/.prettierrc +7 -0
  10. package/LICENSE +21 -0
  11. package/README.md +523 -0
  12. package/mocha.setup.js +10 -0
  13. package/package.json +57 -0
  14. package/src/adapter/adapter-loader.d.ts +16 -0
  15. package/src/adapter/adapter-loader.js +63 -0
  16. package/src/adapter/adapter-loader.spec.js +31 -0
  17. package/src/adapter/adapter-registry.d.ts +14 -0
  18. package/src/adapter/adapter-registry.js +36 -0
  19. package/src/adapter/adapter-registry.spec.js +36 -0
  20. package/src/adapter/adapter.d.ts +118 -0
  21. package/src/adapter/adapter.js +181 -0
  22. package/src/adapter/adapter.spec.js +144 -0
  23. package/src/adapter/builtin/memory-adapter.d.ts +118 -0
  24. package/src/adapter/builtin/memory-adapter.js +342 -0
  25. package/src/adapter/builtin/memory-adapter.spec.js +2925 -0
  26. package/src/adapter/decorator/data-sanitizing-decorator.d.ts +13 -0
  27. package/src/adapter/decorator/data-sanitizing-decorator.js +44 -0
  28. package/src/adapter/decorator/data-sanitizing-decorator.spec.js +59 -0
  29. package/src/adapter/decorator/data-validation-decorator.d.ts +13 -0
  30. package/src/adapter/decorator/data-validation-decorator.js +41 -0
  31. package/src/adapter/decorator/data-validation-decorator.spec.js +59 -0
  32. package/src/adapter/decorator/default-values-decorator.d.ts +13 -0
  33. package/src/adapter/decorator/default-values-decorator.js +57 -0
  34. package/src/adapter/decorator/default-values-decorator.spec.js +141 -0
  35. package/src/adapter/decorator/fields-filtering-decorator.d.ts +13 -0
  36. package/src/adapter/decorator/fields-filtering-decorator.js +72 -0
  37. package/src/adapter/decorator/fields-filtering-decorator.spec.js +119 -0
  38. package/src/adapter/decorator/inclusion-decorator.d.ts +13 -0
  39. package/src/adapter/decorator/inclusion-decorator.js +78 -0
  40. package/src/adapter/decorator/inclusion-decorator.spec.js +117 -0
  41. package/src/adapter/decorator/index.d.ts +5 -0
  42. package/src/adapter/decorator/index.js +5 -0
  43. package/src/adapter/index.d.ts +3 -0
  44. package/src/adapter/index.js +3 -0
  45. package/src/definition/datasource/datasource-definition-validator.d.ts +14 -0
  46. package/src/definition/datasource/datasource-definition-validator.js +33 -0
  47. package/src/definition/datasource/datasource-definition-validator.spec.js +63 -0
  48. package/src/definition/datasource/datasource-definition.d.ts +7 -0
  49. package/src/definition/datasource/index.d.ts +2 -0
  50. package/src/definition/datasource/index.js +1 -0
  51. package/src/definition/definition-registry.d.ts +50 -0
  52. package/src/definition/definition-registry.js +98 -0
  53. package/src/definition/definition-registry.spec.js +78 -0
  54. package/src/definition/index.d.ts +3 -0
  55. package/src/definition/index.js +3 -0
  56. package/src/definition/model/index.d.ts +7 -0
  57. package/src/definition/model/index.js +6 -0
  58. package/src/definition/model/model-data-sanitizer.d.ts +15 -0
  59. package/src/definition/model/model-data-sanitizer.js +33 -0
  60. package/src/definition/model/model-data-validator.d.ts +32 -0
  61. package/src/definition/model/model-data-validator.js +144 -0
  62. package/src/definition/model/model-data-validator.spec.js +1889 -0
  63. package/src/definition/model/model-definition-utils.d.ts +161 -0
  64. package/src/definition/model/model-definition-utils.js +371 -0
  65. package/src/definition/model/model-definition-utils.spec.js +1474 -0
  66. package/src/definition/model/model-definition-validator.d.ts +14 -0
  67. package/src/definition/model/model-definition-validator.js +83 -0
  68. package/src/definition/model/model-definition-validator.spec.js +143 -0
  69. package/src/definition/model/model-definition.d.ts +28 -0
  70. package/src/definition/model/properties/data-type.d.ts +11 -0
  71. package/src/definition/model/properties/data-type.js +11 -0
  72. package/src/definition/model/properties/default-values-definition-validator.d.ts +15 -0
  73. package/src/definition/model/properties/default-values-definition-validator.js +53 -0
  74. package/src/definition/model/properties/default-values-definition-validator.spec.js +136 -0
  75. package/src/definition/model/properties/index.d.ts +5 -0
  76. package/src/definition/model/properties/index.js +4 -0
  77. package/src/definition/model/properties/primary-keys-definition-validator.d.ts +15 -0
  78. package/src/definition/model/properties/primary-keys-definition-validator.js +55 -0
  79. package/src/definition/model/properties/primary-keys-definition-validator.spec.js +145 -0
  80. package/src/definition/model/properties/properties-definition-validator.d.ts +15 -0
  81. package/src/definition/model/properties/properties-definition-validator.js +194 -0
  82. package/src/definition/model/properties/properties-definition-validator.spec.js +373 -0
  83. package/src/definition/model/properties/property-definition.d.ts +20 -0
  84. package/src/definition/model/relations/index.d.ts +3 -0
  85. package/src/definition/model/relations/index.js +2 -0
  86. package/src/definition/model/relations/relation-definition.d.ts +254 -0
  87. package/src/definition/model/relations/relation-type.d.ts +9 -0
  88. package/src/definition/model/relations/relation-type.js +9 -0
  89. package/src/definition/model/relations/relations-definition-validator.d.ts +15 -0
  90. package/src/definition/model/relations/relations-definition-validator.js +449 -0
  91. package/src/definition/model/relations/relations-definition-validator.spec.js +772 -0
  92. package/src/errors/index.d.ts +3 -0
  93. package/src/errors/index.js +3 -0
  94. package/src/errors/invalid-argument-error.d.ts +6 -0
  95. package/src/errors/invalid-argument-error.js +6 -0
  96. package/src/errors/invalid-argument-error.spec.js +33 -0
  97. package/src/errors/invalid-operator-value-error.d.ts +13 -0
  98. package/src/errors/invalid-operator-value-error.js +24 -0
  99. package/src/errors/invalid-operator-value-error.spec.js +11 -0
  100. package/src/errors/not-implemented-error.d.ts +6 -0
  101. package/src/errors/not-implemented-error.js +6 -0
  102. package/src/errors/not-implemented-error.spec.js +33 -0
  103. package/src/filter/fields-clause-tool.d.ts +38 -0
  104. package/src/filter/fields-clause-tool.js +88 -0
  105. package/src/filter/fields-clause-tool.spec.js +133 -0
  106. package/src/filter/filter.d.ts +335 -0
  107. package/src/filter/include-clause-tool.d.ts +53 -0
  108. package/src/filter/include-clause-tool.js +364 -0
  109. package/src/filter/include-clause-tool.spec.js +653 -0
  110. package/src/filter/index.d.ts +7 -0
  111. package/src/filter/index.js +6 -0
  112. package/src/filter/operator-clause-tool.d.ts +223 -0
  113. package/src/filter/operator-clause-tool.js +515 -0
  114. package/src/filter/operator-clause-tool.spec.js +1064 -0
  115. package/src/filter/order-clause-tool.d.ts +32 -0
  116. package/src/filter/order-clause-tool.js +97 -0
  117. package/src/filter/order-clause-tool.spec.js +438 -0
  118. package/src/filter/slice-clause-tool.d.ts +30 -0
  119. package/src/filter/slice-clause-tool.js +65 -0
  120. package/src/filter/slice-clause-tool.spec.js +117 -0
  121. package/src/filter/where-clause-tool.d.ts +23 -0
  122. package/src/filter/where-clause-tool.js +165 -0
  123. package/src/filter/where-clause-tool.spec.js +280 -0
  124. package/src/index.d.ts +9 -0
  125. package/src/index.js +8 -0
  126. package/src/relations/belongs-to-resolver.d.ts +46 -0
  127. package/src/relations/belongs-to-resolver.js +242 -0
  128. package/src/relations/belongs-to-resolver.spec.js +1047 -0
  129. package/src/relations/has-many-resolver.d.ts +67 -0
  130. package/src/relations/has-many-resolver.js +317 -0
  131. package/src/relations/has-many-resolver.spec.js +2911 -0
  132. package/src/relations/has-one-resolver.d.ts +67 -0
  133. package/src/relations/has-one-resolver.js +311 -0
  134. package/src/relations/has-one-resolver.spec.js +2274 -0
  135. package/src/relations/index.d.ts +4 -0
  136. package/src/relations/index.js +4 -0
  137. package/src/relations/references-many-resolver.d.ts +27 -0
  138. package/src/relations/references-many-resolver.js +113 -0
  139. package/src/relations/references-many-resolver.spec.js +631 -0
  140. package/src/repository/index.d.ts +2 -0
  141. package/src/repository/index.js +2 -0
  142. package/src/repository/repository-registry.d.ts +29 -0
  143. package/src/repository/repository-registry.js +57 -0
  144. package/src/repository/repository-registry.spec.js +38 -0
  145. package/src/repository/repository.d.ts +164 -0
  146. package/src/repository/repository.js +207 -0
  147. package/src/repository/repository.spec.js +202 -0
  148. package/src/schema.d.ts +37 -0
  149. package/src/schema.js +41 -0
  150. package/src/types.d.ts +30 -0
  151. package/src/utils/capitalize.d.ts +6 -0
  152. package/src/utils/capitalize.js +10 -0
  153. package/src/utils/capitalize.spec.js +14 -0
  154. package/src/utils/clone-deep.d.ts +6 -0
  155. package/src/utils/clone-deep.js +61 -0
  156. package/src/utils/clone-deep.spec.js +28 -0
  157. package/src/utils/exclude-object-keys.d.ts +10 -0
  158. package/src/utils/exclude-object-keys.js +20 -0
  159. package/src/utils/exclude-object-keys.spec.js +49 -0
  160. package/src/utils/get-ctor-name.d.ts +6 -0
  161. package/src/utils/get-ctor-name.js +11 -0
  162. package/src/utils/get-ctor-name.spec.js +17 -0
  163. package/src/utils/get-value-by-path.d.ts +12 -0
  164. package/src/utils/get-value-by-path.js +23 -0
  165. package/src/utils/get-value-by-path.spec.js +36 -0
  166. package/src/utils/index.d.ts +10 -0
  167. package/src/utils/index.js +10 -0
  168. package/src/utils/is-ctor.d.ts +7 -0
  169. package/src/utils/is-ctor.js +10 -0
  170. package/src/utils/is-ctor.spec.js +26 -0
  171. package/src/utils/is-pure-object.d.ts +6 -0
  172. package/src/utils/is-pure-object.js +15 -0
  173. package/src/utils/is-pure-object.spec.js +25 -0
  174. package/src/utils/select-object-keys.d.ts +10 -0
  175. package/src/utils/select-object-keys.js +37 -0
  176. package/src/utils/select-object-keys.spec.js +40 -0
  177. package/src/utils/singularize.d.ts +6 -0
  178. package/src/utils/singularize.js +22 -0
  179. package/src/utils/singularize.spec.js +23 -0
  180. package/src/utils/string-to-regexp.d.ts +10 -0
  181. package/src/utils/string-to-regexp.js +22 -0
  182. package/src/utils/string-to-regexp.spec.js +35 -0
  183. 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
+ });
@@ -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
+ }