@e22m4u/js-repository-mongodb-adapter 0.0.14
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/.eslintrc.cjs +20 -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 +81 -0
- package/mocha.setup.js +13 -0
- package/package.json +59 -0
- package/setup.sh +39 -0
- package/src/index.js +1 -0
- package/src/mongodb-adapter.js +825 -0
- package/src/mongodb-adapter.spec.js +2391 -0
- package/src/utils/create-mongodb-url.js +87 -0
- package/src/utils/create-mongodb-url.spec.js +29 -0
- package/src/utils/index.js +3 -0
- package/src/utils/is-iso-date.js +13 -0
- package/src/utils/is-object-id.js +14 -0
- package/src/utils/is-object-id.spec.js +24 -0
- package/src/utils/transform-values-deep.js +38 -0
- package/src/utils/transform-values-deep.spec.js +47 -0
- package/test.env +4 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '@e22m4u/js-repository';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate the mongodb URL from the options.
|
|
5
|
+
*/
|
|
6
|
+
export function createMongodbUrl(options = {}) {
|
|
7
|
+
if (!options || typeof options !== 'object' || Array.isArray(options))
|
|
8
|
+
throw new InvalidArgumentError(
|
|
9
|
+
'The first argument of "createMongodbUrl" must be an Object, but %v given.',
|
|
10
|
+
options,
|
|
11
|
+
);
|
|
12
|
+
if (options.protocol && typeof options.protocol !== 'string')
|
|
13
|
+
throw new InvalidArgumentError(
|
|
14
|
+
'MongoDB option "protocol" must be a string, but %v given.',
|
|
15
|
+
options.protocol,
|
|
16
|
+
);
|
|
17
|
+
if (options.hostname && typeof options.hostname !== 'string')
|
|
18
|
+
throw new InvalidArgumentError(
|
|
19
|
+
'MongoDB option "hostname" must be a String, but %v given.',
|
|
20
|
+
options.hostname,
|
|
21
|
+
);
|
|
22
|
+
if (options.host && typeof options.host !== 'string')
|
|
23
|
+
throw new InvalidArgumentError(
|
|
24
|
+
'MongoDB option "host" must be a String, but %v given.',
|
|
25
|
+
options.host,
|
|
26
|
+
);
|
|
27
|
+
if (
|
|
28
|
+
options.port &&
|
|
29
|
+
typeof options.port !== 'number' &&
|
|
30
|
+
typeof options.port !== 'string'
|
|
31
|
+
) {
|
|
32
|
+
throw new InvalidArgumentError(
|
|
33
|
+
'MongoDB option "port" must be a Number or a String, but %v given.',
|
|
34
|
+
options.port,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (options.database && typeof options.database !== 'string')
|
|
38
|
+
throw new InvalidArgumentError(
|
|
39
|
+
'MongoDB option "database" must be a String, but %v given.',
|
|
40
|
+
options.database,
|
|
41
|
+
);
|
|
42
|
+
if (options.db && typeof options.db !== 'string')
|
|
43
|
+
throw new InvalidArgumentError(
|
|
44
|
+
'MongoDB option "db" must be a String, but %v given.',
|
|
45
|
+
options.db,
|
|
46
|
+
);
|
|
47
|
+
if (options.username && typeof options.username !== 'string')
|
|
48
|
+
throw new InvalidArgumentError(
|
|
49
|
+
'MongoDB option "username" must be a String, but %v given.',
|
|
50
|
+
options.username,
|
|
51
|
+
);
|
|
52
|
+
if (
|
|
53
|
+
options.password &&
|
|
54
|
+
typeof options.password !== 'string' &&
|
|
55
|
+
typeof options.password !== 'number'
|
|
56
|
+
) {
|
|
57
|
+
throw new InvalidArgumentError(
|
|
58
|
+
'MongoDB option "password" must be a String or a Number, but %v given.',
|
|
59
|
+
options.password,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
options.pass &&
|
|
64
|
+
typeof options.pass !== 'string' &&
|
|
65
|
+
typeof options.pass !== 'number'
|
|
66
|
+
) {
|
|
67
|
+
throw new InvalidArgumentError(
|
|
68
|
+
'MongoDB option "pass" must be a String or a Number, but %v given.',
|
|
69
|
+
options.pass,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const protocol = options.protocol || 'mongodb';
|
|
73
|
+
const hostname = options.hostname || options.host || '127.0.0.1';
|
|
74
|
+
const port = options.port || 27017;
|
|
75
|
+
const database = options.database || options.db || 'database';
|
|
76
|
+
const username = options.username || options.user;
|
|
77
|
+
const password = options.password || options.pass || undefined;
|
|
78
|
+
let portUrl = '';
|
|
79
|
+
if (protocol !== 'mongodb+srv') {
|
|
80
|
+
portUrl = ':' + port;
|
|
81
|
+
}
|
|
82
|
+
if (username && password) {
|
|
83
|
+
return `${protocol}://${username}:${password}@${hostname}${portUrl}/${database}`;
|
|
84
|
+
} else {
|
|
85
|
+
return `${protocol}://${hostname}${portUrl}/${database}`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {format} from '@e22m4u/js-format';
|
|
3
|
+
import {createMongodbUrl} from './create-mongodb-url.js';
|
|
4
|
+
|
|
5
|
+
describe('createMongodbUrl', function () {
|
|
6
|
+
it('returns a string representation of default values', function () {
|
|
7
|
+
const value = createMongodbUrl();
|
|
8
|
+
expect(value).to.be.eq('mongodb://127.0.0.1:27017/database');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('throws an error when the first argument is a non-object value', function () {
|
|
12
|
+
const throwable = v => () => createMongodbUrl(v);
|
|
13
|
+
const error = v =>
|
|
14
|
+
format(
|
|
15
|
+
'The first argument of "createMongodbUrl" must be an Object, but %s given.',
|
|
16
|
+
v,
|
|
17
|
+
);
|
|
18
|
+
expect(throwable('')).to.throw(error('""'));
|
|
19
|
+
expect(throwable('str')).to.throw(error('"str"'));
|
|
20
|
+
expect(throwable(0)).to.throw(error('0'));
|
|
21
|
+
expect(throwable(10)).to.throw(error('10'));
|
|
22
|
+
expect(throwable(true)).to.throw(error('true'));
|
|
23
|
+
expect(throwable(false)).to.throw(error('false'));
|
|
24
|
+
expect(throwable([])).to.throw(error('Array'));
|
|
25
|
+
expect(throwable(null)).to.throw(error('null'));
|
|
26
|
+
throwable(undefined)();
|
|
27
|
+
throwable({})();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is iso date string.
|
|
3
|
+
*
|
|
4
|
+
* @param value
|
|
5
|
+
* @return {boolean}
|
|
6
|
+
*/
|
|
7
|
+
export function isIsoDate(value) {
|
|
8
|
+
if (!value) return false;
|
|
9
|
+
if (value instanceof Date) return true;
|
|
10
|
+
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(value)) return false;
|
|
11
|
+
const d = new Date(value);
|
|
12
|
+
return d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === value;
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ObjectId} from 'mongodb';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Is object id.
|
|
5
|
+
*
|
|
6
|
+
* @param value
|
|
7
|
+
* @return {boolean}
|
|
8
|
+
*/
|
|
9
|
+
export function isObjectId(value) {
|
|
10
|
+
if (!value) return false;
|
|
11
|
+
if (value instanceof ObjectId) return true;
|
|
12
|
+
if (typeof value !== 'string') return false;
|
|
13
|
+
return value.match(/^[a-fA-F0-9]{24}$/) != null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {isObjectId} from './is-object-id.js';
|
|
3
|
+
import {ObjectId} from 'mongodb';
|
|
4
|
+
|
|
5
|
+
describe('isObjectId', function () {
|
|
6
|
+
it('returns true for a valid ObjectId string or an instance', function () {
|
|
7
|
+
expect(isObjectId('')).to.be.false;
|
|
8
|
+
expect(isObjectId('123')).to.be.false;
|
|
9
|
+
expect(isObjectId(0)).to.be.false;
|
|
10
|
+
expect(isObjectId(10)).to.be.false;
|
|
11
|
+
expect(isObjectId(true)).to.be.false;
|
|
12
|
+
expect(isObjectId(false)).to.be.false;
|
|
13
|
+
expect(isObjectId({})).to.be.false;
|
|
14
|
+
expect(isObjectId({foo: 'bar'})).to.be.false;
|
|
15
|
+
expect(isObjectId([])).to.be.false;
|
|
16
|
+
expect(isObjectId(['foo'])).to.be.false;
|
|
17
|
+
expect(isObjectId(new Date())).to.be.false;
|
|
18
|
+
expect(isObjectId(null)).to.be.false;
|
|
19
|
+
expect(isObjectId(undefined)).to.be.false;
|
|
20
|
+
//
|
|
21
|
+
expect(isObjectId(new ObjectId())).to.be.true;
|
|
22
|
+
expect(isObjectId(String(new ObjectId()))).to.be.true;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {InvalidArgumentError} from '@e22m4u/js-repository';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transform values deep.
|
|
5
|
+
*
|
|
6
|
+
* @param value
|
|
7
|
+
* @param transformer
|
|
8
|
+
* @return {*}
|
|
9
|
+
*/
|
|
10
|
+
export function transformValuesDeep(value, transformer) {
|
|
11
|
+
if (!transformer || typeof transformer !== 'function')
|
|
12
|
+
throw new InvalidArgumentError(
|
|
13
|
+
'The second argument of "transformValuesDeep" ' +
|
|
14
|
+
'must be a Function, but %s given.',
|
|
15
|
+
transformer,
|
|
16
|
+
);
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
value.forEach((v, i) => (value[i] = transformValuesDeep(v, transformer)));
|
|
19
|
+
return value;
|
|
20
|
+
} else if (value && typeof value === 'object') {
|
|
21
|
+
// pure object
|
|
22
|
+
if (
|
|
23
|
+
!value.constructor ||
|
|
24
|
+
(value.constructor && value.constructor.name === 'Object')
|
|
25
|
+
) {
|
|
26
|
+
Object.keys(value).forEach(key => {
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
28
|
+
value[key] = transformValuesDeep(value[key], transformer);
|
|
29
|
+
});
|
|
30
|
+
return value;
|
|
31
|
+
// Date, ObjectId etc..
|
|
32
|
+
} else {
|
|
33
|
+
return transformer(value);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
return transformer(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {transformValuesDeep} from './transform-values-deep.js';
|
|
3
|
+
|
|
4
|
+
describe('transformValuesDeep', function () {
|
|
5
|
+
it('transforms property values of an object', function () {
|
|
6
|
+
const object = {
|
|
7
|
+
foo: 1,
|
|
8
|
+
bar: {
|
|
9
|
+
baz: 2,
|
|
10
|
+
qux: {
|
|
11
|
+
qwe: 3,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const result = transformValuesDeep(object, String);
|
|
16
|
+
expect(result).to.be.eql({
|
|
17
|
+
foo: '1',
|
|
18
|
+
bar: {
|
|
19
|
+
baz: '2',
|
|
20
|
+
qux: {
|
|
21
|
+
qwe: '3',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('transforms elements of an array', function () {
|
|
28
|
+
const object = [1, 2, 3, [4, 5, 6, [7, 8, 9]]];
|
|
29
|
+
const result = transformValuesDeep(object, String);
|
|
30
|
+
expect(result).to.be.eql(['1', '2', '3', ['4', '5', '6', ['7', '8', '9']]]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('transforms non-pure objects', function () {
|
|
34
|
+
const date = new Date();
|
|
35
|
+
const str = String(date);
|
|
36
|
+
const result1 = transformValuesDeep(date, String);
|
|
37
|
+
const result2 = transformValuesDeep([date], String);
|
|
38
|
+
const result3 = transformValuesDeep([[date]], String);
|
|
39
|
+
const result4 = transformValuesDeep({date}, String);
|
|
40
|
+
const result5 = transformValuesDeep({foo: {date}}, String);
|
|
41
|
+
expect(result1).to.be.eql(str);
|
|
42
|
+
expect(result2).to.be.eql([str]);
|
|
43
|
+
expect(result3).to.be.eql([[str]]);
|
|
44
|
+
expect(result4).to.be.eql({date: str});
|
|
45
|
+
expect(result5).to.be.eql({foo: {date: str}});
|
|
46
|
+
});
|
|
47
|
+
});
|
package/test.env
ADDED