@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
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@e22m4u/js-repository",
3
+ "version": "0.0.31",
4
+ "description": "Абстракция для работы с базами данных для Node.js",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "engines": {
8
+ "node": ">=14"
9
+ },
10
+ "scripts": {
11
+ "lint": "tsc && eslint .",
12
+ "lint:fix": "tsc && eslint . --fix",
13
+ "format": "prettier --write \"./src/**/*.js\"",
14
+ "test": "npm run lint && c8 --reporter=text-summary mocha",
15
+ "test:coverage": "npm run lint && c8 --reporter=text mocha",
16
+ "prepare": "npx husky install"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/e22m4u/js-repository.git"
21
+ },
22
+ "keywords": [
23
+ "Repository",
24
+ "ORM",
25
+ "ODM",
26
+ "Database",
27
+ "Datasource",
28
+ "Relation",
29
+ "Inclusion",
30
+ "Memory"
31
+ ],
32
+ "author": "e22m4u <e22m4u@gmail.com>",
33
+ "license": "MIT",
34
+ "homepage": "https://github.com/e22m4u/js-repository",
35
+ "dependencies": {
36
+ "@e22m4u/js-service": "0.0.7",
37
+ "@e22m4u/js-format": "0.0.7"
38
+ },
39
+ "devDependencies": {
40
+ "@commitlint/cli": "^17.7.1",
41
+ "@commitlint/config-conventional": "^17.7.0",
42
+ "c8": "^8.0.1",
43
+ "chai": "^4.3.7",
44
+ "chai-as-promised": "^7.1.1",
45
+ "chai-spies": "^1.0.0",
46
+ "chai-subset": "^1.6.0",
47
+ "eslint": "^8.47.0",
48
+ "eslint-config-prettier": "^9.0.0",
49
+ "eslint-plugin-chai-expect": "^3.0.0",
50
+ "eslint-plugin-jsdoc": "^46.8.2",
51
+ "eslint-plugin-mocha": "^10.1.0",
52
+ "husky": "^8.0.3",
53
+ "mocha": "^10.2.0",
54
+ "prettier": "^3.0.1",
55
+ "typescript": "^5.2.2"
56
+ }
57
+ }
@@ -0,0 +1,16 @@
1
+ import {Adapter} from './adapter.js';
2
+ import {AnyObject} from '../types.js';
3
+ import {Service} from '@e22m4u/js-service';
4
+
5
+ /**
6
+ * Adapter loader.
7
+ */
8
+ export declare class AdapterLoader extends Service {
9
+ /**
10
+ * Load by name.
11
+ *
12
+ * @param adapterName
13
+ * @param settings
14
+ */
15
+ loadByName(adapterName: string, settings?: AnyObject): Promise<Adapter>;
16
+ }
@@ -0,0 +1,63 @@
1
+ import {Adapter} from './adapter.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+ import {InvalidArgumentError} from '../errors/index.js';
4
+
5
+ /**
6
+ * Adapter loader.
7
+ */
8
+ export class AdapterLoader extends Service {
9
+ /**
10
+ * Load by name.
11
+ *
12
+ * @param {string} adapterName
13
+ * @param {object|undefined} settings
14
+ * @returns {Promise<Adapter>}
15
+ */
16
+ async loadByName(adapterName, settings = undefined) {
17
+ if (!adapterName || typeof adapterName !== 'string')
18
+ throw new InvalidArgumentError(
19
+ 'The adapter name must be a non-empty String, but %v given.',
20
+ adapterName,
21
+ );
22
+ let adapterCtor;
23
+ try {
24
+ const module = await import(`./builtin/${adapterName}-adapter.js`);
25
+ adapterCtor = findAdapterCtorInModule(module);
26
+ } catch (e) {
27
+ /**/
28
+ }
29
+ if (!adapterCtor)
30
+ try {
31
+ const module = await import(
32
+ `@e22m4u/js-repository-${adapterName}-adapter`
33
+ );
34
+ adapterCtor = findAdapterCtorInModule(module);
35
+ } catch (e) {
36
+ /**/
37
+ }
38
+ if (!adapterCtor)
39
+ throw new InvalidArgumentError(
40
+ 'The adapter %v is not found.',
41
+ adapterName,
42
+ );
43
+ return new adapterCtor(this.container, settings);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Find adapter ctor in module.
49
+ *
50
+ * @param {object} module
51
+ * @returns {*}
52
+ */
53
+ function findAdapterCtorInModule(module) {
54
+ let adapterCtor;
55
+ if (!module || typeof module !== 'object' || Array.isArray(module)) return;
56
+ for (const ctor of Object.values(module)) {
57
+ if (typeof ctor === 'function' && ctor.prototype instanceof Adapter) {
58
+ adapterCtor = ctor;
59
+ break;
60
+ }
61
+ }
62
+ return adapterCtor;
63
+ }
@@ -0,0 +1,31 @@
1
+ import {expect} from 'chai';
2
+ import {Adapter} from './adapter.js';
3
+ import {AdapterLoader} from './adapter-loader.js';
4
+
5
+ const S = new AdapterLoader();
6
+
7
+ describe('AdapterLoader', function () {
8
+ describe('loadByName', function () {
9
+ it('requires an adapter name as a non-empty string', async function () {
10
+ const promise = S.loadByName('');
11
+ await expect(promise).to.be.rejectedWith(
12
+ 'The adapter name must be a non-empty String, but "" given.',
13
+ );
14
+ });
15
+
16
+ it('throws an error if a given adapter name is not found', async function () {
17
+ const promise = S.loadByName('unknown');
18
+ await expect(promise).to.be.rejectedWith(
19
+ 'The adapter "unknown" is not found.',
20
+ );
21
+ });
22
+
23
+ it('returns an adapter instance that is loaded from "builtin" folder', async function () {
24
+ const settings = {};
25
+ const adapter = await S.loadByName('memory', settings);
26
+ expect(adapter).to.be.instanceof(Adapter);
27
+ expect(adapter.container).to.be.eq(S.container);
28
+ expect(adapter.settings).to.be.eq(settings);
29
+ });
30
+ });
31
+ });
@@ -0,0 +1,14 @@
1
+ import {Adapter} from './adapter.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+
4
+ /**
5
+ * Adapter registry.
6
+ */
7
+ export declare class AdapterRegistry extends Service {
8
+ /**
9
+ * Get adapter.
10
+ *
11
+ * @param datasourceName
12
+ */
13
+ getAdapter(datasourceName: string): Promise<Adapter>;
14
+ }
@@ -0,0 +1,36 @@
1
+ import {Adapter} from './adapter.js';
2
+ import {Service} from '@e22m4u/js-service';
3
+ import {AdapterLoader} from './adapter-loader.js';
4
+ import {DefinitionRegistry} from '../definition/index.js';
5
+
6
+ /**
7
+ * Adapter registry.
8
+ */
9
+ export class AdapterRegistry extends Service {
10
+ /**
11
+ * Adapters.
12
+ *
13
+ * @type {object}
14
+ */
15
+ _adapters = {};
16
+
17
+ /**
18
+ * Get adapter.
19
+ *
20
+ * @param {string} datasourceName
21
+ * @returns {Promise<Adapter>}
22
+ */
23
+ async getAdapter(datasourceName) {
24
+ let adapter = this._adapters[datasourceName];
25
+ if (adapter) return adapter;
26
+ const datasource =
27
+ this.getService(DefinitionRegistry).getDatasource(datasourceName);
28
+ const adapterName = datasource.adapter;
29
+ adapter = await this.getService(AdapterLoader).loadByName(
30
+ adapterName,
31
+ datasource,
32
+ );
33
+ this._adapters[datasourceName] = adapter;
34
+ return adapter;
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ import {expect} from 'chai';
2
+ import {Schema} from '../schema.js';
3
+ import {AdapterRegistry} from './adapter-registry.js';
4
+ import {MemoryAdapter} from './builtin/memory-adapter.js';
5
+
6
+ describe('AdapterRegistry', function () {
7
+ describe('getAdapter', function () {
8
+ it('instantiates a new or returns an existing adapter by a given datasource name', async function () {
9
+ const S = new Schema();
10
+ S.defineDatasource({name: 'datasource', adapter: 'memory'});
11
+ const R = S.getService(AdapterRegistry);
12
+ const adapter = await R.getAdapter('datasource');
13
+ expect(adapter).to.be.instanceof(MemoryAdapter);
14
+ const sameAdapter = await R.getAdapter('datasource');
15
+ expect(sameAdapter).to.be.eq(adapter);
16
+ });
17
+
18
+ it('throws an error if a datasource is not exists', async function () {
19
+ const R = new AdapterRegistry();
20
+ const promise = R.getAdapter('unknown');
21
+ await expect(promise).to.be.rejectedWith(
22
+ 'The datasource "unknown" is not defined.',
23
+ );
24
+ });
25
+
26
+ it('throws an error if an adapter is not exists', async function () {
27
+ const S = new Schema();
28
+ S.defineDatasource({name: 'datasource', adapter: 'unknown'});
29
+ const R = S.getService(AdapterRegistry);
30
+ const promise = R.getAdapter('datasource');
31
+ await expect(promise).to.be.rejectedWith(
32
+ 'The adapter "unknown" is not found.',
33
+ );
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,118 @@
1
+ import {ModelId} from '../types.js';
2
+ import {AnyObject} from '../types.js';
3
+ import {ModelData} from '../types.js';
4
+ import {Filter} from '../filter/index.js';
5
+ import {Service} from '@e22m4u/js-service';
6
+ import {ItemFilter} from '../filter/index.js';
7
+ import {WhereClause} from '../filter/index.js';
8
+ import {ServiceContainer} from '@e22m4u/js-service';
9
+
10
+ /**
11
+ * Adapter.
12
+ */
13
+ export declare class Adapter extends Service {
14
+ /**
15
+ * Settings.
16
+ */
17
+ get settings(): AnyObject | undefined;
18
+
19
+ /**
20
+ * Constructor.
21
+ *
22
+ * @param container
23
+ * @param settings
24
+ */
25
+ constructor(container?: ServiceContainer, settings?: AnyObject);
26
+
27
+ /**
28
+ * Create.
29
+ *
30
+ * @param modelName
31
+ * @param modelData
32
+ * @param filter
33
+ */
34
+ create(
35
+ modelName: string,
36
+ modelData: ModelData,
37
+ filter?: ItemFilter,
38
+ ): Promise<ModelData>;
39
+
40
+ /**
41
+ * Replace by id.
42
+ *
43
+ * @param modelName
44
+ * @param id
45
+ * @param modelData
46
+ * @param filter
47
+ */
48
+ replaceById(
49
+ modelName: string,
50
+ id: ModelId,
51
+ modelData: ModelData,
52
+ filter?: ItemFilter,
53
+ ): Promise<ModelData>;
54
+
55
+ /**
56
+ * Patch by id.
57
+ *
58
+ * @param modelName
59
+ * @param id
60
+ * @param modelData
61
+ * @param filter
62
+ */
63
+ patchById(
64
+ modelName: string,
65
+ id: ModelId,
66
+ modelData: ModelData,
67
+ filter?: ItemFilter,
68
+ ): Promise<ModelData>;
69
+
70
+ /**
71
+ * Find.
72
+ *
73
+ * @param modelName
74
+ * @param filter
75
+ */
76
+ find(modelName: string, filter?: Filter): Promise<ModelData[]>;
77
+
78
+ /**
79
+ * Find by id.
80
+ *
81
+ * @param modelName
82
+ * @param id
83
+ * @param filter
84
+ */
85
+ findById(modelName: string, id: ModelId, filter?: Filter): Promise<ModelData>;
86
+
87
+ /**
88
+ * Delete.
89
+ *
90
+ * @param modelName
91
+ * @param where
92
+ */
93
+ delete(modelName: string, where?: WhereClause): Promise<number>;
94
+
95
+ /**
96
+ * Delete by id.
97
+ *
98
+ * @param modelName
99
+ * @param id
100
+ */
101
+ deleteById(modelName: string, id: ModelId): Promise<boolean>;
102
+
103
+ /**
104
+ * Exists.
105
+ *
106
+ * @param modelName
107
+ * @param id
108
+ */
109
+ exists(modelName: string, id: ModelId): Promise<boolean>;
110
+
111
+ /**
112
+ * Count.
113
+ *
114
+ * @param modelName
115
+ * @param where
116
+ */
117
+ count(modelName: string, where?: WhereClause): Promise<number>;
118
+ }
@@ -0,0 +1,181 @@
1
+ /* eslint no-unused-vars: 0 */
2
+ /* eslint jsdoc/require-returns-check: 0 */
3
+ import {Service} from '@e22m4u/js-service';
4
+ import {NotImplementedError} from '../errors/index.js';
5
+ import {InclusionDecorator} from './decorator/index.js';
6
+ import {DefaultValuesDecorator} from './decorator/index.js';
7
+ import {DataValidationDecorator} from './decorator/index.js';
8
+ import {DataSanitizingDecorator} from './decorator/index.js';
9
+ import {FieldsFilteringDecorator} from './decorator/index.js';
10
+
11
+ /**
12
+ * Adapter.
13
+ */
14
+ export class Adapter extends Service {
15
+ /**
16
+ * Settings.
17
+ *
18
+ * @type {object|undefined}
19
+ */
20
+ _settings;
21
+
22
+ /**
23
+ * Settings.
24
+ *
25
+ * @returns {object|undefined}
26
+ */
27
+ get settings() {
28
+ return this._settings;
29
+ }
30
+
31
+ /**
32
+ * Constructor.
33
+ *
34
+ * @param {object|undefined} container
35
+ * @param {object|undefined} settings
36
+ */
37
+ constructor(container = undefined, settings = undefined) {
38
+ super(container);
39
+ this._settings = settings;
40
+ // decorate only extended classes
41
+ if (this.constructor !== Adapter) {
42
+ this.getService(DataValidationDecorator).decorate(this);
43
+ this.getService(DataSanitizingDecorator).decorate(this);
44
+ this.getService(DefaultValuesDecorator).decorate(this);
45
+ this.getService(FieldsFilteringDecorator).decorate(this);
46
+ this.getService(InclusionDecorator).decorate(this);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Create.
52
+ *
53
+ * @param {string} modelName
54
+ * @param {object} modelData
55
+ * @param {object|undefined} filter
56
+ * @returns {Promise<object>}
57
+ */
58
+ create(modelName, modelData, filter = undefined) {
59
+ throw new NotImplementedError(
60
+ '%s.create is not implemented.',
61
+ this.constructor.name,
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Replace by id.
67
+ *
68
+ * @param {string} modelName
69
+ * @param {number|string} id
70
+ * @param {object} modelData
71
+ * @param {object|undefined} filter
72
+ * @returns {Promise<object>}
73
+ */
74
+ replaceById(modelName, id, modelData, filter = undefined) {
75
+ throw new NotImplementedError(
76
+ '%s.replaceById is not implemented.',
77
+ this.constructor.name,
78
+ );
79
+ }
80
+
81
+ /**
82
+ * Patch by id.
83
+ *
84
+ * @param {string} modelName
85
+ * @param {number|string} id
86
+ * @param {object} modelData
87
+ * @param {object|undefined} filter
88
+ * @returns {Promise<object>}
89
+ */
90
+ patchById(modelName, id, modelData, filter = undefined) {
91
+ throw new NotImplementedError(
92
+ '%s.patchById is not implemented.',
93
+ this.constructor.name,
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Find.
99
+ *
100
+ * @param {string} modelName
101
+ * @param {object|undefined} filter
102
+ * @returns {Promise<object[]>}
103
+ */
104
+ find(modelName, filter = undefined) {
105
+ throw new NotImplementedError(
106
+ '%s.find is not implemented.',
107
+ this.constructor.name,
108
+ );
109
+ }
110
+
111
+ /**
112
+ * Find by id.
113
+ *
114
+ * @param {string} modelName
115
+ * @param {number|string} id
116
+ * @param {object|undefined} filter
117
+ * @returns {Promise<object>}
118
+ */
119
+ findById(modelName, id, filter = undefined) {
120
+ throw new NotImplementedError(
121
+ '%s.findById is not implemented.',
122
+ this.constructor.name,
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Delete.
128
+ *
129
+ * @param {string} modelName
130
+ * @param {object|undefined} where
131
+ * @returns {Promise<number>}
132
+ */
133
+ delete(modelName, where = undefined) {
134
+ throw new NotImplementedError(
135
+ '%s.delete is not implemented.',
136
+ this.constructor.name,
137
+ );
138
+ }
139
+
140
+ /**
141
+ * Delete by id.
142
+ *
143
+ * @param {string} modelName
144
+ * @param {number|string} id
145
+ * @returns {Promise<boolean>}
146
+ */
147
+ deleteById(modelName, id) {
148
+ throw new NotImplementedError(
149
+ '%s.deleteById is not implemented.',
150
+ this.constructor.name,
151
+ );
152
+ }
153
+
154
+ /**
155
+ * Exists.
156
+ *
157
+ * @param {string} modelName
158
+ * @param {number|string} id
159
+ * @returns {Promise<boolean>}
160
+ */
161
+ exists(modelName, id) {
162
+ throw new NotImplementedError(
163
+ '%s.exists is not implemented.',
164
+ this.constructor.name,
165
+ );
166
+ }
167
+
168
+ /**
169
+ * Count.
170
+ *
171
+ * @param {string} modelName
172
+ * @param {object|undefined} where
173
+ * @returns {Promise<number>}
174
+ */
175
+ count(modelName, where = undefined) {
176
+ throw new NotImplementedError(
177
+ '%s.count is not implemented.',
178
+ this.constructor.name,
179
+ );
180
+ }
181
+ }
@@ -0,0 +1,144 @@
1
+ import chai from 'chai';
2
+ import {expect} from 'chai';
3
+ import {Schema} from '../schema.js';
4
+ import {Adapter} from './adapter.js';
5
+ import {Service} from '@e22m4u/js-service';
6
+ import {ServiceContainer} from '@e22m4u/js-service';
7
+ import {InclusionDecorator} from './decorator/index.js';
8
+ import {DefaultValuesDecorator} from './decorator/index.js';
9
+ import {DataValidationDecorator} from './decorator/index.js';
10
+ import {DataSanitizingDecorator} from './decorator/index.js';
11
+ import {FieldsFilteringDecorator} from './decorator/index.js';
12
+
13
+ const sandbox = chai.spy.sandbox();
14
+
15
+ describe('Adapter', function () {
16
+ describe('constructor', function () {
17
+ afterEach(function () {
18
+ sandbox.restore();
19
+ });
20
+
21
+ it('inherits from the Service class', function () {
22
+ const adapter = new Adapter();
23
+ expect(adapter).to.be.instanceof(Service);
24
+ });
25
+
26
+ it('sets given service container and settings', function () {
27
+ const container = new ServiceContainer();
28
+ const settings = {};
29
+ const adapter = new Adapter(container, settings);
30
+ expect(adapter.container).to.be.eq(container);
31
+ expect(adapter._settings).to.be.eq(settings);
32
+ });
33
+
34
+ it('decorates only extended adapter', function () {
35
+ const schema = new Schema();
36
+ const dec1 = schema.getService(DataValidationDecorator);
37
+ const dec2 = schema.getService(DataSanitizingDecorator);
38
+ const dec3 = schema.getService(DefaultValuesDecorator);
39
+ const dec4 = schema.getService(FieldsFilteringDecorator);
40
+ const dec5 = schema.getService(InclusionDecorator);
41
+ const order = [];
42
+ const decorate = function (ctx) {
43
+ expect(ctx).to.be.instanceof(Adapter);
44
+ order.push(this);
45
+ };
46
+ sandbox.on(dec1, 'decorate', decorate);
47
+ sandbox.on(dec2, 'decorate', decorate);
48
+ sandbox.on(dec3, 'decorate', decorate);
49
+ sandbox.on(dec4, 'decorate', decorate);
50
+ sandbox.on(dec5, 'decorate', decorate);
51
+ new Adapter(schema.container);
52
+ expect(order).to.be.empty;
53
+ expect(dec1.decorate).to.be.not.called;
54
+ expect(dec2.decorate).to.be.not.called;
55
+ expect(dec3.decorate).to.be.not.called;
56
+ expect(dec4.decorate).to.be.not.called;
57
+ expect(dec5.decorate).to.be.not.called;
58
+ class ExtendedAdapter extends Adapter {}
59
+ new ExtendedAdapter(schema.container);
60
+ expect(order[0]).to.be.eql(dec1);
61
+ expect(order[1]).to.be.eql(dec2);
62
+ expect(order[2]).to.be.eql(dec3);
63
+ expect(order[3]).to.be.eql(dec4);
64
+ expect(order[4]).to.be.eql(dec5);
65
+ expect(dec1.decorate).to.be.called.once;
66
+ expect(dec2.decorate).to.be.called.once;
67
+ expect(dec3.decorate).to.be.called.once;
68
+ expect(dec4.decorate).to.be.called.once;
69
+ expect(dec5.decorate).to.be.called.once;
70
+ });
71
+ });
72
+
73
+ describe('create', function () {
74
+ it('throws the "Not implemented"', function () {
75
+ const adapter = new Adapter();
76
+ const throwable = () => adapter.create();
77
+ expect(throwable).to.throw('Adapter.create is not implemented.');
78
+ });
79
+ });
80
+
81
+ describe('replaceById', function () {
82
+ it('throws the "Not implemented"', function () {
83
+ const adapter = new Adapter();
84
+ const throwable = () => adapter.replaceById();
85
+ expect(throwable).to.throw('Adapter.replaceById is not implemented.');
86
+ });
87
+ });
88
+
89
+ describe('patchById', function () {
90
+ it('throws the "Not implemented"', function () {
91
+ const adapter = new Adapter();
92
+ const throwable = () => adapter.patchById();
93
+ expect(throwable).to.throw('Adapter.patchById is not implemented.');
94
+ });
95
+ });
96
+
97
+ describe('find', function () {
98
+ it('throws the "Not implemented"', function () {
99
+ const adapter = new Adapter();
100
+ const throwable = () => adapter.find();
101
+ expect(throwable).to.throw('Adapter.find is not implemented.');
102
+ });
103
+ });
104
+
105
+ describe('findById', function () {
106
+ it('throws the "Not implemented"', function () {
107
+ const adapter = new Adapter();
108
+ const throwable = () => adapter.findById();
109
+ expect(throwable).to.throw('Adapter.findById is not implemented.');
110
+ });
111
+ });
112
+
113
+ describe('delete', function () {
114
+ it('throws the "Not implemented"', function () {
115
+ const adapter = new Adapter();
116
+ const throwable = () => adapter.delete();
117
+ expect(throwable).to.throw('Adapter.delete is not implemented.');
118
+ });
119
+ });
120
+
121
+ describe('deleteById', function () {
122
+ it('throws the "Not implemented"', function () {
123
+ const adapter = new Adapter();
124
+ const throwable = () => adapter.deleteById();
125
+ expect(throwable).to.throw('Adapter.deleteById is not implemented.');
126
+ });
127
+ });
128
+
129
+ describe('exists', function () {
130
+ it('throws the "Not implemented"', function () {
131
+ const adapter = new Adapter();
132
+ const throwable = () => adapter.exists();
133
+ expect(throwable).to.throw('Adapter.exists is not implemented.');
134
+ });
135
+ });
136
+
137
+ describe('count', function () {
138
+ it('throws the "Not implemented"', function () {
139
+ const adapter = new Adapter();
140
+ const throwable = () => adapter.count();
141
+ expect(throwable).to.throw('Adapter.count is not implemented.');
142
+ });
143
+ });
144
+ });