@hvedinich/utils 0.0.59 → 0.0.61
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/.eslintrc.js +8 -0
- package/.github/workflows/test.yml +28 -0
- package/.github/workflows/update_version_and_publish.yaml +57 -0
- package/package.json +3 -3
- package/src/utils/buildDBModel/__tests/buildDBModel.test.js +129 -0
- package/src/utils/buildDBModel/index.js +88 -0
- package/src/utils/index.js +3 -1
package/.eslintrc.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: run unit tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
pull_request:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
node-version: [18]
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v3
|
|
18
|
+
|
|
19
|
+
- name: Set up Node.js
|
|
20
|
+
uses: actions/setup-node@v3
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm install
|
|
26
|
+
|
|
27
|
+
- name: Run tests
|
|
28
|
+
run: npm test
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Publish utils
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
update-version-publish-and-release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout code
|
|
14
|
+
uses: actions/checkout@v2
|
|
15
|
+
|
|
16
|
+
- name: Setup Node.js
|
|
17
|
+
uses: actions/setup-node@v3
|
|
18
|
+
with:
|
|
19
|
+
node-version: 18
|
|
20
|
+
registry-url: 'https://registry.npmjs.org/'
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
|
|
25
|
+
- name: Update patch version
|
|
26
|
+
run: |
|
|
27
|
+
npm version patch --no-git-tag-version
|
|
28
|
+
git config --local user.email "rooolik@gmail.com"
|
|
29
|
+
git config --local user.name "hvedinich"
|
|
30
|
+
git commit -am "Update version to $(node -p "require('./package.json').version")"
|
|
31
|
+
git push
|
|
32
|
+
|
|
33
|
+
- name: Publish to npm
|
|
34
|
+
uses: JS-DevTools/npm-publish@v3
|
|
35
|
+
with:
|
|
36
|
+
token: ${{ secrets.NPM_TOKEN }}
|
|
37
|
+
|
|
38
|
+
- name: Read Changelog
|
|
39
|
+
id: changelog
|
|
40
|
+
run: echo "::set-output name=body::$(cat CHANGELOG.md)"
|
|
41
|
+
|
|
42
|
+
- name: Get package.json version
|
|
43
|
+
id: package_version
|
|
44
|
+
run: echo "::set-output name=version::$(node -p "require('./package.json').version")"
|
|
45
|
+
shell: bash
|
|
46
|
+
|
|
47
|
+
- name: Set the version in the env
|
|
48
|
+
run: echo "VERSION=${{ steps.package_version.outputs.version }}" >> $GITHUB_ENV
|
|
49
|
+
|
|
50
|
+
- name: Create release
|
|
51
|
+
env:
|
|
52
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
53
|
+
run: |
|
|
54
|
+
gh release create "$VERSION" \
|
|
55
|
+
--repo="$GITHUB_REPOSITORY" \
|
|
56
|
+
--title="${GITHUB_REPOSITORY#*/} ${VERSION#v}" \
|
|
57
|
+
--generate-notes
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hvedinich/utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.61",
|
|
4
4
|
"description": "utils module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "jest"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"eslint-plugin-import": "^2.26.0",
|
|
33
33
|
"eslint-plugin-prettier": "^4.0.0",
|
|
34
34
|
"husky": "^8.0.1",
|
|
35
|
-
"jest": "^29.
|
|
35
|
+
"jest": "^29.7.0",
|
|
36
36
|
"prettier": "^2.5.1"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const { buildDBModel } = require('../index');
|
|
2
|
+
|
|
3
|
+
// Mock Mongoose schema methods
|
|
4
|
+
const mockSchema = {
|
|
5
|
+
findOneAndUpdate: jest.fn(),
|
|
6
|
+
findOne: jest.fn(),
|
|
7
|
+
find: jest.fn(),
|
|
8
|
+
create: jest.fn(),
|
|
9
|
+
deleteOne: jest.fn(),
|
|
10
|
+
countDocuments: jest.fn(),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Create the model using the mocked schema
|
|
14
|
+
const dbModel = buildDBModel(mockSchema);
|
|
15
|
+
|
|
16
|
+
describe('buildDBModel', () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should create a new document', async () => {
|
|
22
|
+
const mockData = { name: 'Test' };
|
|
23
|
+
const createdDoc = { ...mockData, _id: '1' };
|
|
24
|
+
mockSchema.create.mockResolvedValue(createdDoc);
|
|
25
|
+
|
|
26
|
+
const result = await dbModel.create(mockData);
|
|
27
|
+
expect(result).toEqual(createdDoc);
|
|
28
|
+
expect(mockSchema.create).toHaveBeenCalledWith(mockData);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should read a single document', async () => {
|
|
32
|
+
const mockFilter = { _id: '1' };
|
|
33
|
+
const foundDoc = { _id: '1', name: 'Test' };
|
|
34
|
+
mockSchema.findOne.mockReturnValue({
|
|
35
|
+
lean: jest.fn().mockResolvedValue(foundDoc),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const result = await dbModel.read(mockFilter);
|
|
39
|
+
expect(result).toEqual(foundDoc);
|
|
40
|
+
expect(mockSchema.findOne).toHaveBeenCalledWith(mockFilter);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should read multiple documents', async () => {
|
|
44
|
+
const mockFilter = { name: 'Test' };
|
|
45
|
+
const foundDocs = [
|
|
46
|
+
{ _id: '1', name: 'Test' },
|
|
47
|
+
{ _id: '2', name: 'Test2' },
|
|
48
|
+
];
|
|
49
|
+
mockSchema.find.mockReturnValue({
|
|
50
|
+
lean: jest.fn().mockReturnValue({
|
|
51
|
+
exec: jest.fn().mockResolvedValue(foundDocs),
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const result = await dbModel.readAll(mockFilter);
|
|
56
|
+
expect(result).toEqual(foundDocs);
|
|
57
|
+
expect(mockSchema.find).toHaveBeenCalledWith(mockFilter);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should find one and update a document', async () => {
|
|
61
|
+
const mockFilter = { _id: '1' };
|
|
62
|
+
const mockAction = { $set: { name: 'Updated' } };
|
|
63
|
+
const options = { new: true };
|
|
64
|
+
const updatedDoc = { _id: '1', name: 'Updated' };
|
|
65
|
+
mockSchema.findOneAndUpdate.mockReturnValue({
|
|
66
|
+
lean: jest.fn().mockResolvedValue(updatedDoc),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const result = await dbModel.findOneAndUpdate(mockFilter, mockAction, options);
|
|
70
|
+
expect(result).toEqual(updatedDoc);
|
|
71
|
+
expect(mockSchema.findOneAndUpdate).toHaveBeenCalledWith(mockFilter, mockAction, options);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should remove a document by id', async () => {
|
|
75
|
+
const mockId = '1';
|
|
76
|
+
const removeResult = { deletedCount: 1 };
|
|
77
|
+
mockSchema.deleteOne.mockResolvedValue(removeResult);
|
|
78
|
+
|
|
79
|
+
const result = await dbModel.remove(mockId);
|
|
80
|
+
expect(result).toEqual(removeResult);
|
|
81
|
+
expect(mockSchema.deleteOne).toHaveBeenCalledWith({ id: mockId });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should count documents', async () => {
|
|
85
|
+
const mockFilter = { name: 'Test' };
|
|
86
|
+
const countResult = 2;
|
|
87
|
+
mockSchema.countDocuments.mockReturnValue({
|
|
88
|
+
lean: jest.fn().mockReturnValue({
|
|
89
|
+
exec: jest.fn().mockResolvedValue(countResult),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const result = await dbModel.count(mockFilter);
|
|
94
|
+
expect(result).toEqual(countResult);
|
|
95
|
+
expect(mockSchema.countDocuments).toHaveBeenCalledWith(mockFilter);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should list documents with pagination and sorting', async () => {
|
|
99
|
+
const mockOptions = {
|
|
100
|
+
filter: { name: 'Test' },
|
|
101
|
+
pagination: { page: 1, pageSize: 2 },
|
|
102
|
+
sortBy: { field: 'name', direction: 'asc' },
|
|
103
|
+
};
|
|
104
|
+
const foundDocs = [
|
|
105
|
+
{ _id: '1', name: 'Test' },
|
|
106
|
+
{ _id: '2', name: 'Test2' },
|
|
107
|
+
];
|
|
108
|
+
const totalCount = 2;
|
|
109
|
+
|
|
110
|
+
mockSchema.find.mockReturnValue({
|
|
111
|
+
skip: jest.fn().mockReturnThis(),
|
|
112
|
+
limit: jest.fn().mockReturnThis(),
|
|
113
|
+
sort: jest.fn().mockReturnThis(),
|
|
114
|
+
lean: jest.fn().mockReturnThis(),
|
|
115
|
+
exec: jest.fn().mockResolvedValue(foundDocs),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
mockSchema.countDocuments.mockReturnValue({
|
|
119
|
+
lean: jest.fn().mockReturnValue({
|
|
120
|
+
exec: jest.fn().mockResolvedValue(totalCount),
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const result = await dbModel.list(mockOptions);
|
|
125
|
+
expect(result).toEqual([foundDocs, totalCount]);
|
|
126
|
+
expect(mockSchema.find).toHaveBeenCalledWith(mockOptions.filter);
|
|
127
|
+
expect(mockSchema.countDocuments).toHaveBeenCalledWith(mockOptions.filter);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates basic CRUD methods for a Mongoose schema.
|
|
3
|
+
* @param {mongoose.Schema} schema - The Mongoose schema to build the model methods for.
|
|
4
|
+
* @returns {Object} - An object containing CRUD methods for the schema.
|
|
5
|
+
*/
|
|
6
|
+
const buildDBModel = schema => {
|
|
7
|
+
/**
|
|
8
|
+
* Finds one document and updates it.
|
|
9
|
+
* @param {Object} filter - The filter to find the document.
|
|
10
|
+
* @param {Object} action - The update action to perform.
|
|
11
|
+
* @param {Object} options - Options for the update operation.
|
|
12
|
+
* @returns {Promise<Object>} - The updated document.
|
|
13
|
+
*/
|
|
14
|
+
const findOneAndUpdate = (filter, action, options) => schema.findOneAndUpdate(filter, action, options).lean();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reads a single document.
|
|
18
|
+
* @param {Object} input - The filter to find the document.
|
|
19
|
+
* @returns {Promise<Object>} - The found document.
|
|
20
|
+
*/
|
|
21
|
+
const read = input => schema.findOne(input).lean();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reads multiple documents.
|
|
25
|
+
* @param {Object} filter - The filter to find the documents.
|
|
26
|
+
* @returns {Promise<Array>} - An array of found documents.
|
|
27
|
+
*/
|
|
28
|
+
const readAll = filter => schema.find(filter).lean().exec();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new document.
|
|
32
|
+
* @param {Object} data - The data for the new document.
|
|
33
|
+
* @returns {Promise<Object>} - The created document.
|
|
34
|
+
*/
|
|
35
|
+
const create = data => schema.create(data);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Removes a document by id.
|
|
39
|
+
* @param {String} id - The id of the document to remove.
|
|
40
|
+
* @returns {Promise<Object>} - The result of the remove operation.
|
|
41
|
+
*/
|
|
42
|
+
const remove = id => schema.deleteOne({ id });
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Counts the number of documents matching a filter.
|
|
46
|
+
* @param {Object} filter - The filter to count the documents.
|
|
47
|
+
* @returns {Promise<Number>} - The count of documents.
|
|
48
|
+
*/
|
|
49
|
+
const count = filter => schema.countDocuments(filter).lean().exec();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Lists documents with optional pagination and sorting.
|
|
53
|
+
* @param {Object} options - The options for listing documents.
|
|
54
|
+
* @param {Object} options.filter - The filter to find the documents.
|
|
55
|
+
* @param {Object} [options.pagination] - The pagination options.
|
|
56
|
+
* @param {Number} [options.pagination.page] - The page number.
|
|
57
|
+
* @param {Number} [options.pagination.pageSize] - The number of documents per page.
|
|
58
|
+
* @param {Object} [options.sortBy] - The sorting options.
|
|
59
|
+
* @param {String} [options.sortBy.field] - The field to sort by.
|
|
60
|
+
* @param {String} [options.sortBy.direction] - The direction to sort ('asc' or 'desc').
|
|
61
|
+
* @returns {Promise<Array>} - An array containing the found documents and the total count.
|
|
62
|
+
*/
|
|
63
|
+
const list = async ({ filter = {}, pagination, sortBy }) => {
|
|
64
|
+
let query = schema.find(filter);
|
|
65
|
+
const countQuery = schema.countDocuments(filter);
|
|
66
|
+
if (pagination) {
|
|
67
|
+
query = query.skip((pagination.page - 1) * pagination.pageSize).limit(pagination.pageSize);
|
|
68
|
+
}
|
|
69
|
+
if (sortBy && sortBy.field) {
|
|
70
|
+
query = query.sort([[sortBy.field, sortBy.direction || 'asc']]);
|
|
71
|
+
}
|
|
72
|
+
const [totalCount, results] = await Promise.all([countQuery.lean().exec(), query.lean().exec()]);
|
|
73
|
+
return [results, totalCount];
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
create,
|
|
77
|
+
read,
|
|
78
|
+
readAll,
|
|
79
|
+
list,
|
|
80
|
+
findOneAndUpdate,
|
|
81
|
+
remove,
|
|
82
|
+
count,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
buildDBModel,
|
|
88
|
+
};
|
package/src/utils/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const common = require('./common');
|
|
|
6
6
|
const permission = require('./permission');
|
|
7
7
|
const config = require('./config');
|
|
8
8
|
const healthCheck = require('./healthCheck');
|
|
9
|
+
const db = require('./buildDBModel');
|
|
9
10
|
|
|
10
11
|
module.exports = {
|
|
11
12
|
context,
|
|
@@ -15,5 +16,6 @@ module.exports = {
|
|
|
15
16
|
permission,
|
|
16
17
|
config,
|
|
17
18
|
common,
|
|
18
|
-
healthCheck
|
|
19
|
+
healthCheck,
|
|
20
|
+
db,
|
|
19
21
|
};
|