@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
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
|
+
});
|