@aneuhold/be-ts-db-lib 1.0.1
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/README.md +7 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +2 -0
- package/lib/repositories/BaseRepository.d.ts +31 -0
- package/lib/repositories/BaseRepository.d.ts.map +1 -0
- package/lib/repositories/BaseRepository.js +79 -0
- package/lib/repositories/common/UserRepository.d.ts +27 -0
- package/lib/repositories/common/UserRepository.d.ts.map +1 -0
- package/lib/repositories/common/UserRepository.js +46 -0
- package/lib/tests/repositories/BaseRepository.spec.d.ts +2 -0
- package/lib/tests/repositories/BaseRepository.spec.d.ts.map +1 -0
- package/lib/tests/repositories/BaseRepository.spec.js +20 -0
- package/lib/tests/repositories/UserRepository.spec.d.ts +2 -0
- package/lib/tests/repositories/UserRepository.spec.d.ts.map +1 -0
- package/lib/tests/repositories/UserRepository.spec.js +88 -0
- package/lib/tests/testsUtil.d.ts +9 -0
- package/lib/tests/testsUtil.d.ts.map +1 -0
- package/lib/tests/testsUtil.js +32 -0
- package/lib/util/DocumentDb.d.ts +11 -0
- package/lib/util/DocumentDb.d.ts.map +1 -0
- package/lib/util/DocumentDb.js +38 -0
- package/lib/validators/BaseValidator.d.ts +19 -0
- package/lib/validators/BaseValidator.d.ts.map +1 -0
- package/lib/validators/BaseValidator.js +11 -0
- package/lib/validators/common/UserValidator.d.ts +11 -0
- package/lib/validators/common/UserValidator.d.ts.map +1 -0
- package/lib/validators/common/UserValidator.js +46 -0
- package/package.json +61 -0
package/README.md
ADDED
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC;AAGV,YAAY,EAAE,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BaseDocument } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
import { Collection, DeleteResult, UpdateResult } from 'mongodb';
|
|
3
|
+
import { ObjectId } from 'bson';
|
|
4
|
+
import IValidator from '../validators/BaseValidator';
|
|
5
|
+
/**
|
|
6
|
+
* A base repository that implements a lot of the normal CRUD operations.
|
|
7
|
+
*/
|
|
8
|
+
export default abstract class BaseRepository<TBasetype extends BaseDocument> {
|
|
9
|
+
private validator;
|
|
10
|
+
protected collectionName: string;
|
|
11
|
+
private collection?;
|
|
12
|
+
constructor(collectionName: string, validator: IValidator<TBasetype>);
|
|
13
|
+
protected getCollection(): Promise<Collection<import("bson").Document>>;
|
|
14
|
+
insertNew(newDoc: TBasetype): Promise<TBasetype | null>;
|
|
15
|
+
get(filter: Partial<TBasetype>): Promise<TBasetype | null>;
|
|
16
|
+
getAll(): Promise<TBasetype[]>;
|
|
17
|
+
getList(docIds: ObjectId[]): Promise<TBasetype[]>;
|
|
18
|
+
delete(docId: ObjectId): Promise<DeleteResult>;
|
|
19
|
+
deleteList(docIds: ObjectId[]): Promise<DeleteResult>;
|
|
20
|
+
/**
|
|
21
|
+
* This should not be used except for testing purposes
|
|
22
|
+
*/
|
|
23
|
+
deleteAll(): Promise<DeleteResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Updates the provided doc in the DB.
|
|
26
|
+
*
|
|
27
|
+
* This base method strips the `_id` before updating.
|
|
28
|
+
*/
|
|
29
|
+
update(updatedDoc: Partial<TBasetype>): Promise<UpdateResult>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=BaseRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseRepository.d.ts","sourceRoot":"","sources":["../../src/repositories/BaseRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,UAAU,MAAM,6BAA6B,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,cAAc,CAAC,SAAS,SAAS,YAAY;IAOvE,OAAO,CAAC,SAAS;IANnB,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC;IAEjC,OAAO,CAAC,UAAU,CAAC,CAAa;gBAG9B,cAAc,EAAE,MAAM,EACd,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC;cAK1B,aAAa;IAOvB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAUvD,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAM1D,MAAM,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAO9B,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAMjD,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC;IAK9C,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAK3D;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAKxC;;;;OAIG;IACG,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;CAYpE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const DocumentDb_1 = __importDefault(require("../util/DocumentDb"));
|
|
7
|
+
/**
|
|
8
|
+
* A base repository that implements a lot of the normal CRUD operations.
|
|
9
|
+
*/
|
|
10
|
+
class BaseRepository {
|
|
11
|
+
validator;
|
|
12
|
+
collectionName;
|
|
13
|
+
collection;
|
|
14
|
+
constructor(collectionName, validator) {
|
|
15
|
+
this.validator = validator;
|
|
16
|
+
this.collectionName = collectionName;
|
|
17
|
+
}
|
|
18
|
+
async getCollection() {
|
|
19
|
+
if (!this.collection) {
|
|
20
|
+
this.collection = await DocumentDb_1.default.getCollection(this.collectionName);
|
|
21
|
+
}
|
|
22
|
+
return this.collection;
|
|
23
|
+
}
|
|
24
|
+
async insertNew(newDoc) {
|
|
25
|
+
const collection = await this.getCollection();
|
|
26
|
+
await this.validator.validateNewObject(newDoc);
|
|
27
|
+
const insertResult = await collection.insertOne(newDoc);
|
|
28
|
+
if (!insertResult.acknowledged) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return newDoc;
|
|
32
|
+
}
|
|
33
|
+
async get(filter) {
|
|
34
|
+
const collection = await this.getCollection();
|
|
35
|
+
const result = await collection.findOne(filter);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
async getAll() {
|
|
39
|
+
const collection = await this.getCollection();
|
|
40
|
+
const result = await collection.find().toArray();
|
|
41
|
+
// Set to unknown first because of some weird type things.
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
async getList(docIds) {
|
|
45
|
+
const collection = await this.getCollection();
|
|
46
|
+
const result = await collection.find({ _id: { $in: docIds } }).toArray();
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
async delete(docId) {
|
|
50
|
+
const collection = await this.getCollection();
|
|
51
|
+
return collection.deleteOne({ _id: docId });
|
|
52
|
+
}
|
|
53
|
+
async deleteList(docIds) {
|
|
54
|
+
const collection = await this.getCollection();
|
|
55
|
+
return collection.deleteMany({ _id: { $in: docIds } });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* This should not be used except for testing purposes
|
|
59
|
+
*/
|
|
60
|
+
async deleteAll() {
|
|
61
|
+
const collection = await this.getCollection();
|
|
62
|
+
return collection.deleteMany({});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Updates the provided doc in the DB.
|
|
66
|
+
*
|
|
67
|
+
* This base method strips the `_id` before updating.
|
|
68
|
+
*/
|
|
69
|
+
async update(updatedDoc) {
|
|
70
|
+
const collection = await this.getCollection();
|
|
71
|
+
await this.validator.validateUpdateObject(updatedDoc);
|
|
72
|
+
const docId = updatedDoc._id;
|
|
73
|
+
// Create a copy so that there aren't side-effects
|
|
74
|
+
const docCopy = { ...updatedDoc };
|
|
75
|
+
delete docCopy._id;
|
|
76
|
+
return collection.updateOne({ _id: docId }, { $set: docCopy });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.default = BaseRepository;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { User } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
import BaseRepository from '../BaseRepository';
|
|
3
|
+
/**
|
|
4
|
+
* The repository that contains {@link User} documents.
|
|
5
|
+
*/
|
|
6
|
+
export default class UserRepository extends BaseRepository<User> {
|
|
7
|
+
private static COLLECTION_NAME;
|
|
8
|
+
private static singletonInstance;
|
|
9
|
+
private constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Gets the singleton instance of the {@link UserRepository}.
|
|
12
|
+
*/
|
|
13
|
+
static getRepo(): UserRepository;
|
|
14
|
+
/**
|
|
15
|
+
* Inserts a new user.
|
|
16
|
+
*
|
|
17
|
+
* This will add the default team that consists of just the user if it
|
|
18
|
+
* doesn't already exist. If it does exist, it will add that team to the
|
|
19
|
+
* user's {@link User.currentTeamsIncludingUser} array.
|
|
20
|
+
*
|
|
21
|
+
* @override
|
|
22
|
+
*
|
|
23
|
+
* @returns The user with the additional team, or null if the insert failed.
|
|
24
|
+
*/
|
|
25
|
+
insertNew(newUser: User): Promise<User | null>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=UserRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserRepository.d.ts","sourceRoot":"","sources":["../../../src/repositories/common/UserRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,cAAc,MAAM,mBAAmB,CAAC;AAG/C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,IAAI,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,eAAe,CAAW;IAEzC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAiB;IAEjD,OAAO;IAIP;;OAEG;WACW,OAAO;IAOrB;;;;;;;;;;OAUG;IACG,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;CAQrD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const BaseRepository_1 = __importDefault(require("../BaseRepository"));
|
|
7
|
+
const UserValidator_1 = __importDefault(require("../../validators/common/UserValidator"));
|
|
8
|
+
/**
|
|
9
|
+
* The repository that contains {@link User} documents.
|
|
10
|
+
*/
|
|
11
|
+
class UserRepository extends BaseRepository_1.default {
|
|
12
|
+
static COLLECTION_NAME = 'users';
|
|
13
|
+
static singletonInstance;
|
|
14
|
+
constructor() {
|
|
15
|
+
super(UserRepository.COLLECTION_NAME, new UserValidator_1.default());
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Gets the singleton instance of the {@link UserRepository}.
|
|
19
|
+
*/
|
|
20
|
+
static getRepo() {
|
|
21
|
+
if (!UserRepository.singletonInstance) {
|
|
22
|
+
UserRepository.singletonInstance = new UserRepository();
|
|
23
|
+
}
|
|
24
|
+
return UserRepository.singletonInstance;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Inserts a new user.
|
|
28
|
+
*
|
|
29
|
+
* This will add the default team that consists of just the user if it
|
|
30
|
+
* doesn't already exist. If it does exist, it will add that team to the
|
|
31
|
+
* user's {@link User.currentTeamsIncludingUser} array.
|
|
32
|
+
*
|
|
33
|
+
* @override
|
|
34
|
+
*
|
|
35
|
+
* @returns The user with the additional team, or null if the insert failed.
|
|
36
|
+
*/
|
|
37
|
+
async insertNew(newUser) {
|
|
38
|
+
// Insert the new user first
|
|
39
|
+
const insertResult = await super.insertNew(newUser);
|
|
40
|
+
if (!insertResult) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return newUser;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = UserRepository;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseRepository.spec.d.ts","sourceRoot":"","sources":["../../../src/tests/repositories/BaseRepository.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
+
const core_ts_db_lib_1 = require("@aneuhold/core-ts-db-lib");
|
|
8
|
+
const UserRepository_1 = __importDefault(require("../../repositories/common/UserRepository"));
|
|
9
|
+
const testsUtil_1 = require("../testsUtil");
|
|
10
|
+
const DocumentDb_1 = __importDefault(require("../../util/DocumentDb"));
|
|
11
|
+
it('can create a new document and delete it', async () => {
|
|
12
|
+
const userRepository = UserRepository_1.default.getRepo();
|
|
13
|
+
const newUser = new core_ts_db_lib_1.User(crypto_1.default.randomUUID());
|
|
14
|
+
const createResult = await userRepository.insertNew(newUser);
|
|
15
|
+
expect(createResult).toBeTruthy();
|
|
16
|
+
await (0, testsUtil_1.cleanupDoc)(userRepository, newUser);
|
|
17
|
+
});
|
|
18
|
+
afterAll(async () => {
|
|
19
|
+
return DocumentDb_1.default.closeDbConnection();
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserRepository.spec.d.ts","sourceRoot":"","sources":["../../../src/tests/repositories/UserRepository.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
+
const core_ts_db_lib_1 = require("@aneuhold/core-ts-db-lib");
|
|
8
|
+
const testsUtil_1 = require("../testsUtil");
|
|
9
|
+
const UserRepository_1 = __importDefault(require("../../repositories/common/UserRepository"));
|
|
10
|
+
const DocumentDb_1 = __importDefault(require("../../util/DocumentDb"));
|
|
11
|
+
const userRepo = UserRepository_1.default.getRepo();
|
|
12
|
+
describe('Create operations', () => {
|
|
13
|
+
it('throws if the username is a duplicate username', async () => {
|
|
14
|
+
const duplicateUserName = `${crypto_1.default.randomUUID()}`;
|
|
15
|
+
const newUser1 = new core_ts_db_lib_1.User(duplicateUserName);
|
|
16
|
+
const newUser2 = new core_ts_db_lib_1.User(duplicateUserName);
|
|
17
|
+
const insertResult = await userRepo.insertNew(newUser1);
|
|
18
|
+
expect(insertResult).toBeTruthy();
|
|
19
|
+
await (0, testsUtil_1.expectToThrow)(async () => {
|
|
20
|
+
await userRepo.insertNew(newUser2);
|
|
21
|
+
});
|
|
22
|
+
await (0, testsUtil_1.cleanupDoc)(userRepo, newUser1);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('Update operations', () => {
|
|
26
|
+
it('succeeds in updating the username if the username doesnt already exist', async () => {
|
|
27
|
+
const userName1 = crypto_1.default.randomUUID();
|
|
28
|
+
const userName2 = crypto_1.default.randomUUID();
|
|
29
|
+
const newUser = new core_ts_db_lib_1.User(userName1);
|
|
30
|
+
// Insert the user
|
|
31
|
+
const insertResult = await userRepo.insertNew(newUser);
|
|
32
|
+
expect(insertResult).toBeTruthy();
|
|
33
|
+
// Try to update the user
|
|
34
|
+
newUser.userName = userName2;
|
|
35
|
+
const updateResult = await userRepo.update(newUser);
|
|
36
|
+
expect(updateResult.acknowledged).toBeTruthy();
|
|
37
|
+
await (0, testsUtil_1.cleanupDoc)(userRepo, newUser);
|
|
38
|
+
});
|
|
39
|
+
it('throws if no id is defined', async () => {
|
|
40
|
+
const newUser = new core_ts_db_lib_1.User(crypto_1.default.randomUUID());
|
|
41
|
+
delete newUser._id;
|
|
42
|
+
await (0, testsUtil_1.expectToThrow)(async () => {
|
|
43
|
+
await userRepo.update(newUser);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('throws if the username is updated and already exists', async () => {
|
|
47
|
+
const userName1 = crypto_1.default.randomUUID();
|
|
48
|
+
const userName2 = crypto_1.default.randomUUID();
|
|
49
|
+
const newUser = new core_ts_db_lib_1.User(userName1);
|
|
50
|
+
const userWithOtherUserName = new core_ts_db_lib_1.User(userName2);
|
|
51
|
+
// Insert the users
|
|
52
|
+
const insertResult1 = await userRepo.insertNew(newUser);
|
|
53
|
+
expect(insertResult1).toBeTruthy();
|
|
54
|
+
const insertResult2 = await userRepo.insertNew(userWithOtherUserName);
|
|
55
|
+
expect(insertResult2).toBeTruthy();
|
|
56
|
+
// Try to update the first user
|
|
57
|
+
newUser.userName = userName2;
|
|
58
|
+
await (0, testsUtil_1.expectToThrow)(async () => {
|
|
59
|
+
await userRepo.update(newUser);
|
|
60
|
+
});
|
|
61
|
+
await Promise.all([
|
|
62
|
+
(0, testsUtil_1.cleanupDoc)(userRepo, newUser),
|
|
63
|
+
(0, testsUtil_1.cleanupDoc)(userRepo, userWithOtherUserName)
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
it('throws if the user doesnt exist', async () => {
|
|
67
|
+
const newUser = new core_ts_db_lib_1.User(crypto_1.default.randomUUID());
|
|
68
|
+
// Try to update the user
|
|
69
|
+
await (0, testsUtil_1.expectToThrow)(async () => {
|
|
70
|
+
await userRepo.update(newUser);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Deletes all users!
|
|
76
|
+
*
|
|
77
|
+
* Make sure that the local DB you are working on doesn't have important
|
|
78
|
+
* state before turning skip off on this one.
|
|
79
|
+
*
|
|
80
|
+
* To just do a cleanup, put `only` after `it`. So `it.only('can delete all users'`
|
|
81
|
+
*/
|
|
82
|
+
it.skip('can delete all users', async () => {
|
|
83
|
+
const result = await userRepo.deleteAll();
|
|
84
|
+
expect(result.acknowledged).toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
afterAll(async () => {
|
|
87
|
+
return DocumentDb_1.default.closeDbConnection();
|
|
88
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseDocument } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
import BaseRepository from '../repositories/BaseRepository';
|
|
3
|
+
export declare function expectToThrow(func: () => Promise<void>): Promise<void>;
|
|
4
|
+
/**
|
|
5
|
+
* Removes the provided doc from the DB
|
|
6
|
+
*/
|
|
7
|
+
export declare function cleanupDoc<TDocType extends BaseDocument>(repo: BaseRepository<TDocType>, doc: TDocType): Promise<void>;
|
|
8
|
+
export declare function cleanupDocs<TDocType extends BaseDocument>(repo: BaseRepository<TDocType>, docs: TDocType[]): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=testsUtil.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testsUtil.d.ts","sourceRoot":"","sources":["../../src/tests/testsUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,cAAc,MAAM,gCAAgC,CAAC;AAE5D,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,iBAQ5D;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,SAAS,YAAY,EAC5D,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC9B,GAAG,EAAE,QAAQ,iBAMd;AAED,wBAAsB,WAAW,CAAC,QAAQ,SAAS,YAAY,EAC7D,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC9B,IAAI,EAAE,QAAQ,EAAE,iBAOjB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanupDocs = exports.cleanupDoc = exports.expectToThrow = void 0;
|
|
4
|
+
async function expectToThrow(func) {
|
|
5
|
+
let threwError = false;
|
|
6
|
+
try {
|
|
7
|
+
await func();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
threwError = true;
|
|
11
|
+
}
|
|
12
|
+
expect(threwError).toBeTruthy();
|
|
13
|
+
}
|
|
14
|
+
exports.expectToThrow = expectToThrow;
|
|
15
|
+
/**
|
|
16
|
+
* Removes the provided doc from the DB
|
|
17
|
+
*/
|
|
18
|
+
async function cleanupDoc(repo, doc) {
|
|
19
|
+
const deleteResult = await repo.delete(doc._id);
|
|
20
|
+
expect(deleteResult.acknowledged).toBeTruthy();
|
|
21
|
+
const findResult = await repo.get({ _id: doc._id });
|
|
22
|
+
expect(findResult).toBeNull();
|
|
23
|
+
}
|
|
24
|
+
exports.cleanupDoc = cleanupDoc;
|
|
25
|
+
async function cleanupDocs(repo, docs) {
|
|
26
|
+
const idsToDelete = docs.map((doc) => doc._id);
|
|
27
|
+
const deleteResult = await repo.deleteList(idsToDelete);
|
|
28
|
+
expect(deleteResult.acknowledged).toBeTruthy();
|
|
29
|
+
const findResult = await repo.getList(idsToDelete);
|
|
30
|
+
expect(findResult.length).toBe(0);
|
|
31
|
+
}
|
|
32
|
+
exports.cleanupDocs = cleanupDocs;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Collection } from 'mongodb';
|
|
2
|
+
import { Document } from 'bson';
|
|
3
|
+
export default class DocumentDb {
|
|
4
|
+
private static DB_NAME;
|
|
5
|
+
private static mongoClient;
|
|
6
|
+
private static db;
|
|
7
|
+
private static getClient;
|
|
8
|
+
static getCollection<TDocType extends Document>(collectionName: string): Promise<Collection<TDocType>>;
|
|
9
|
+
static closeDbConnection(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=DocumentDb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocumentDb.d.ts","sourceRoot":"","sources":["../../src/util/DocumentDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAmB,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,OAAO,CAAC,MAAM,CAAC,OAAO,CAAa;IAEnC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAc;IAExC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAK;mBAED,SAAS;WAiBjB,aAAa,CAAC,QAAQ,SAAS,QAAQ,EAClD,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;WAQnB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const be_ts_lib_1 = require("@aneuhold/be-ts-lib");
|
|
4
|
+
const mongodb_1 = require("mongodb");
|
|
5
|
+
class DocumentDb {
|
|
6
|
+
static DB_NAME = 'default';
|
|
7
|
+
static mongoClient;
|
|
8
|
+
static db;
|
|
9
|
+
static async getClient() {
|
|
10
|
+
if (!be_ts_lib_1.ConfigService.isInitialized) {
|
|
11
|
+
// Hard-coded local for now until there are move envs.
|
|
12
|
+
await be_ts_lib_1.ConfigService.useConfig('local');
|
|
13
|
+
}
|
|
14
|
+
const { config } = be_ts_lib_1.ConfigService;
|
|
15
|
+
if (!this.mongoClient) {
|
|
16
|
+
const mongoDbConnectionString = `mongodb+srv://${config.mongoRootUsername}:${config.mongoRootPassword}@${config.mongoUrl}/?retryWrites=true&w=majority`;
|
|
17
|
+
this.mongoClient = new mongodb_1.MongoClient(mongoDbConnectionString);
|
|
18
|
+
}
|
|
19
|
+
// Connecting every time is evidently the correct way to do it. This is
|
|
20
|
+
// because it will not do anything and just return if it is already
|
|
21
|
+
// connected.
|
|
22
|
+
await this.mongoClient.connect();
|
|
23
|
+
return this.mongoClient;
|
|
24
|
+
}
|
|
25
|
+
static async getCollection(collectionName) {
|
|
26
|
+
const client = await this.getClient();
|
|
27
|
+
if (!this.db) {
|
|
28
|
+
DocumentDb.db = client.db(DocumentDb.DB_NAME);
|
|
29
|
+
}
|
|
30
|
+
return DocumentDb.db.collection(collectionName);
|
|
31
|
+
}
|
|
32
|
+
static async closeDbConnection() {
|
|
33
|
+
if (DocumentDb.mongoClient) {
|
|
34
|
+
await DocumentDb.mongoClient.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.default = DocumentDb;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseDocument } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
export default abstract class IValidator<TBaseType extends BaseDocument> {
|
|
3
|
+
/**
|
|
4
|
+
* Validates that an object that is supposed to be inserted in to the database
|
|
5
|
+
* is correct.
|
|
6
|
+
*/
|
|
7
|
+
abstract validateNewObject(object: TBaseType): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Validates an object that is suppposed to be updated in the database.
|
|
10
|
+
*
|
|
11
|
+
* At this point, the fields that do not change should already be stripped.
|
|
12
|
+
*/
|
|
13
|
+
abstract validateUpdateObject(partialObject: Partial<TBaseType>): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Checks that all elements that exist in array1, exist in array2.
|
|
16
|
+
*/
|
|
17
|
+
protected checkAllElementsExistInArr(array1: Array<unknown>, array2: Array<unknown>): boolean;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=BaseValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseValidator.d.ts","sourceRoot":"","sources":["../../src/validators/BaseValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,UAAU,CAAC,SAAS,SAAS,YAAY;IACrE;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAE5D;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,aAAa,EAAE,OAAO,CAAC,SAAS,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,0BAA0B,CAClC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EACtB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;CAIzB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class IValidator {
|
|
4
|
+
/**
|
|
5
|
+
* Checks that all elements that exist in array1, exist in array2.
|
|
6
|
+
*/
|
|
7
|
+
checkAllElementsExistInArr(array1, array2) {
|
|
8
|
+
return array1.every((value) => array2.includes(value));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.default = IValidator;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { User } from '@aneuhold/core-ts-db-lib';
|
|
2
|
+
import IValidator from '../BaseValidator';
|
|
3
|
+
export default class UserValidator extends IValidator<User> {
|
|
4
|
+
validateNewObject(newUser: User): Promise<void>;
|
|
5
|
+
validateUpdateObject(userToUpdate: Partial<User>): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if the username exists already and throws an error if it does.
|
|
8
|
+
*/
|
|
9
|
+
private checkIfUserNameExists;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=UserValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserValidator.d.ts","sourceRoot":"","sources":["../../../src/validators/common/UserValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAEhD,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAG1C,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,UAAU,CAAC,IAAI,CAAC;IACnD,iBAAiB,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/C,oBAAoB,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BtE;;OAEG;YACW,qBAAqB;CAWpC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_ts_db_lib_1 = require("@aneuhold/core-ts-db-lib");
|
|
7
|
+
const core_ts_lib_1 = require("@aneuhold/core-ts-lib");
|
|
8
|
+
const BaseValidator_1 = __importDefault(require("../BaseValidator"));
|
|
9
|
+
const UserRepository_1 = __importDefault(require("../../repositories/common/UserRepository"));
|
|
10
|
+
class UserValidator extends BaseValidator_1.default {
|
|
11
|
+
async validateNewObject(newUser) {
|
|
12
|
+
// Check if the username already exists
|
|
13
|
+
const userRepo = UserRepository_1.default.getRepo();
|
|
14
|
+
await this.checkIfUserNameExists(userRepo, newUser.userName);
|
|
15
|
+
}
|
|
16
|
+
async validateUpdateObject(userToUpdate) {
|
|
17
|
+
// Check if an id is defined
|
|
18
|
+
if (!userToUpdate._id) {
|
|
19
|
+
core_ts_lib_1.ErrorUtils.throwError(`No _id defined for ${core_ts_db_lib_1.User.name} to update.`, userToUpdate);
|
|
20
|
+
}
|
|
21
|
+
// Check to see if the user exists
|
|
22
|
+
const userRepo = UserRepository_1.default.getRepo();
|
|
23
|
+
const userInDb = await userRepo.get({ _id: userToUpdate._id });
|
|
24
|
+
if (!userInDb) {
|
|
25
|
+
core_ts_lib_1.ErrorUtils.throwError(`${core_ts_db_lib_1.User.name} with ID: ${userToUpdate._id} does not exist in the database.`, userToUpdate);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Check if the username is being updated and, if it is, if it already
|
|
29
|
+
// exists
|
|
30
|
+
if (userToUpdate.userName && userInDb.userName !== userToUpdate.userName) {
|
|
31
|
+
await this.checkIfUserNameExists(userRepo, userToUpdate.userName);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the username exists already and throws an error if it does.
|
|
36
|
+
*/
|
|
37
|
+
async checkIfUserNameExists(userRepo, userName) {
|
|
38
|
+
const userNameSearchResult = await userRepo.get({
|
|
39
|
+
userName
|
|
40
|
+
});
|
|
41
|
+
if (userNameSearchResult) {
|
|
42
|
+
core_ts_lib_1.ErrorUtils.throwError('Username already exists', { userName });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = UserValidator;
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aneuhold/be-ts-db-lib",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A backend database library meant to actually interact with various databases in personal projects",
|
|
5
|
+
"author": "Anton G Neuhold Jr <agneuhold@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/aneuhold/be-ts-db-lib.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/aneuhold/be-ts-db-lib/issues"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/aneuhold/be-ts-db-lib#readme",
|
|
17
|
+
"files": [
|
|
18
|
+
"lib/**/*"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"Scripting",
|
|
22
|
+
"Node.js"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"pushpub": "npm run build && npm version patch && git push && npm publish --access public",
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"watch": "tsc -w",
|
|
28
|
+
"link:local": "cd lib && yarn link",
|
|
29
|
+
"link:coredb": "yarn link @aneuhold/core-ts-db-lib",
|
|
30
|
+
"link:bets": "yarn link @aneuhold/be-ts-lib",
|
|
31
|
+
"unlink:local": "cd lib && yarn unlink",
|
|
32
|
+
"unlink:coredb": "yarn unlink @aneuhold/core-ts-db-lib && yarn install --force",
|
|
33
|
+
"unlink:bets": "yarn unlink @aneuhold/be-ts-lib && yarn install --force",
|
|
34
|
+
"upgrade:all": "yarn upgrade --latest",
|
|
35
|
+
"test": "jest"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@aneuhold/be-ts-lib": "^1.0.2",
|
|
39
|
+
"@aneuhold/core-ts-db-lib": "^1.0.1",
|
|
40
|
+
"@aneuhold/core-ts-lib": "^1.1.6",
|
|
41
|
+
"bson": "^6.2.0",
|
|
42
|
+
"mongodb": "^6.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/jest": "^29.5.8",
|
|
46
|
+
"@types/node": "^20.10.4",
|
|
47
|
+
"@types/node-fetch": "^2.6.9",
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
|
49
|
+
"@typescript-eslint/parser": "^6.14.0",
|
|
50
|
+
"eslint": "^8.35.0",
|
|
51
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
52
|
+
"eslint-config-prettier": "^9.1.0",
|
|
53
|
+
"eslint-plugin-import": "^2.22.1",
|
|
54
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
55
|
+
"jest": "^29.7.0",
|
|
56
|
+
"prettier": "^3.1.1",
|
|
57
|
+
"ts-jest": "^29.1.1",
|
|
58
|
+
"ts-node": "^10.2.1",
|
|
59
|
+
"typescript": "^5.3.3"
|
|
60
|
+
}
|
|
61
|
+
}
|