ballrush-core 0.2.3 → 0.2.5
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/dist/domain/user.js +5 -2
- package/dist/errors/domain.errors.d.ts +20 -0
- package/dist/errors/domain.errors.js +35 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +18 -0
- package/dist/errors/repository.errors.d.ts +45 -0
- package/dist/errors/repository.errors.js +76 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/repositories/mongo/event-template.repository.js +99 -15
- package/dist/repositories/mongo/event.repository.js +133 -24
- package/dist/repositories/mongo/group.repository.js +80 -11
- package/dist/repositories/mongo/user.repository.js +49 -6
- package/package.json +10 -3
package/dist/domain/user.js
CHANGED
|
@@ -9,8 +9,11 @@ class User {
|
|
|
9
9
|
this.language = language;
|
|
10
10
|
}
|
|
11
11
|
static create(params) {
|
|
12
|
-
if (!params.
|
|
13
|
-
throw new Error(
|
|
12
|
+
if (!params.userId) {
|
|
13
|
+
throw new Error(`User creation failed: missing userId (firstName="${params.firstName ?? 'N/A'}")`);
|
|
14
|
+
}
|
|
15
|
+
if (!params.firstName) {
|
|
16
|
+
throw new Error(`User creation failed: missing firstName (userId=${params.userId ?? 'N/A'})`);
|
|
14
17
|
}
|
|
15
18
|
return new User(params.userId, params.firstName, params.username, params.language ?? "ru");
|
|
16
19
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for domain operations
|
|
3
|
+
*/
|
|
4
|
+
export declare class DomainError extends Error {
|
|
5
|
+
readonly entityType: string;
|
|
6
|
+
readonly operation: string;
|
|
7
|
+
constructor(message: string, entityType: string, operation: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when domain validation fails
|
|
11
|
+
*/
|
|
12
|
+
export declare class DomainValidationError extends DomainError {
|
|
13
|
+
constructor(entityType: string, field: string, value: any, reason: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when a business rule is violated
|
|
17
|
+
*/
|
|
18
|
+
export declare class BusinessRuleViolationError extends DomainError {
|
|
19
|
+
constructor(entityType: string, rule: string, context?: string);
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BusinessRuleViolationError = exports.DomainValidationError = exports.DomainError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for domain operations
|
|
6
|
+
*/
|
|
7
|
+
class DomainError extends Error {
|
|
8
|
+
constructor(message, entityType, operation) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.entityType = entityType;
|
|
11
|
+
this.operation = operation;
|
|
12
|
+
this.name = 'DomainError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.DomainError = DomainError;
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when domain validation fails
|
|
18
|
+
*/
|
|
19
|
+
class DomainValidationError extends DomainError {
|
|
20
|
+
constructor(entityType, field, value, reason) {
|
|
21
|
+
super(`Domain validation failed for ${entityType}.${field}: ${reason} (value: ${value})`, entityType, 'validate');
|
|
22
|
+
this.name = 'DomainValidationError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.DomainValidationError = DomainValidationError;
|
|
26
|
+
/**
|
|
27
|
+
* Error thrown when a business rule is violated
|
|
28
|
+
*/
|
|
29
|
+
class BusinessRuleViolationError extends DomainError {
|
|
30
|
+
constructor(entityType, rule, context) {
|
|
31
|
+
super(`Business rule violation in ${entityType}: ${rule}${context ? ` (${context})` : ''}`, entityType, 'business_rule');
|
|
32
|
+
this.name = 'BusinessRuleViolationError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.BusinessRuleViolationError = BusinessRuleViolationError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./repository.errors"), exports);
|
|
18
|
+
__exportStar(require("./domain.errors"), exports);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for repository operations
|
|
3
|
+
*/
|
|
4
|
+
export declare class RepositoryError extends Error {
|
|
5
|
+
readonly operation: string;
|
|
6
|
+
readonly entityType: string;
|
|
7
|
+
readonly originalError?: Error | undefined;
|
|
8
|
+
constructor(message: string, operation: string, entityType: string, originalError?: Error | undefined);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when a database connection fails
|
|
12
|
+
*/
|
|
13
|
+
export declare class DatabaseConnectionError extends RepositoryError {
|
|
14
|
+
constructor(originalError?: Error);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when a query fails
|
|
18
|
+
*/
|
|
19
|
+
export declare class QueryError extends RepositoryError {
|
|
20
|
+
constructor(operation: string, entityType: string, identifier: string | number, originalError?: Error);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown when an entity is not found
|
|
24
|
+
*/
|
|
25
|
+
export declare class EntityNotFoundError extends RepositoryError {
|
|
26
|
+
constructor(entityType: string, identifier: string | number, operation?: string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when a duplicate entity is created
|
|
30
|
+
*/
|
|
31
|
+
export declare class DuplicateEntityError extends RepositoryError {
|
|
32
|
+
constructor(entityType: string, identifier: string | number, originalError?: Error);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Error thrown when validation fails
|
|
36
|
+
*/
|
|
37
|
+
export declare class ValidationError extends RepositoryError {
|
|
38
|
+
constructor(entityType: string, field: string, value: any, reason: string);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Error thrown when a transaction fails
|
|
42
|
+
*/
|
|
43
|
+
export declare class TransactionError extends RepositoryError {
|
|
44
|
+
constructor(operation: string, originalError?: Error);
|
|
45
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransactionError = exports.ValidationError = exports.DuplicateEntityError = exports.EntityNotFoundError = exports.QueryError = exports.DatabaseConnectionError = exports.RepositoryError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for repository operations
|
|
6
|
+
*/
|
|
7
|
+
class RepositoryError extends Error {
|
|
8
|
+
constructor(message, operation, entityType, originalError) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.operation = operation;
|
|
11
|
+
this.entityType = entityType;
|
|
12
|
+
this.originalError = originalError;
|
|
13
|
+
this.name = 'RepositoryError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.RepositoryError = RepositoryError;
|
|
17
|
+
/**
|
|
18
|
+
* Error thrown when a database connection fails
|
|
19
|
+
*/
|
|
20
|
+
class DatabaseConnectionError extends RepositoryError {
|
|
21
|
+
constructor(originalError) {
|
|
22
|
+
super('Failed to connect to database', 'connect', 'database', originalError);
|
|
23
|
+
this.name = 'DatabaseConnectionError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.DatabaseConnectionError = DatabaseConnectionError;
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when a query fails
|
|
29
|
+
*/
|
|
30
|
+
class QueryError extends RepositoryError {
|
|
31
|
+
constructor(operation, entityType, identifier, originalError) {
|
|
32
|
+
super(`Query failed for ${entityType} with identifier ${identifier}`, operation, entityType, originalError);
|
|
33
|
+
this.name = 'QueryError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.QueryError = QueryError;
|
|
37
|
+
/**
|
|
38
|
+
* Error thrown when an entity is not found
|
|
39
|
+
*/
|
|
40
|
+
class EntityNotFoundError extends RepositoryError {
|
|
41
|
+
constructor(entityType, identifier, operation = 'find') {
|
|
42
|
+
super(`${entityType} with identifier ${identifier} not found`, operation, entityType);
|
|
43
|
+
this.name = 'EntityNotFoundError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.EntityNotFoundError = EntityNotFoundError;
|
|
47
|
+
/**
|
|
48
|
+
* Error thrown when a duplicate entity is created
|
|
49
|
+
*/
|
|
50
|
+
class DuplicateEntityError extends RepositoryError {
|
|
51
|
+
constructor(entityType, identifier, originalError) {
|
|
52
|
+
super(`${entityType} with identifier ${identifier} already exists`, 'create', entityType, originalError);
|
|
53
|
+
this.name = 'DuplicateEntityError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.DuplicateEntityError = DuplicateEntityError;
|
|
57
|
+
/**
|
|
58
|
+
* Error thrown when validation fails
|
|
59
|
+
*/
|
|
60
|
+
class ValidationError extends RepositoryError {
|
|
61
|
+
constructor(entityType, field, value, reason) {
|
|
62
|
+
super(`Validation failed for ${entityType}.${field}: ${reason} (value: ${value})`, 'validate', entityType);
|
|
63
|
+
this.name = 'ValidationError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.ValidationError = ValidationError;
|
|
67
|
+
/**
|
|
68
|
+
* Error thrown when a transaction fails
|
|
69
|
+
*/
|
|
70
|
+
class TransactionError extends RepositoryError {
|
|
71
|
+
constructor(operation, originalError) {
|
|
72
|
+
super(`Transaction failed during ${operation}`, operation, 'transaction', originalError);
|
|
73
|
+
this.name = 'TransactionError';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.TransactionError = TransactionError;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,38 +2,122 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoEventTemplatesRepository = void 0;
|
|
4
4
|
const event_template_mapper_1 = require("./event-template.mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
5
6
|
class MongoEventTemplatesRepository {
|
|
6
7
|
constructor(Model) {
|
|
7
8
|
this.Model = Model;
|
|
8
9
|
}
|
|
9
10
|
async getById(templateId) {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
try {
|
|
12
|
+
if (!templateId || templateId === 0) {
|
|
13
|
+
throw new errors_1.ValidationError('EventTemplate', 'templateId', templateId, 'must be a non-zero number');
|
|
14
|
+
}
|
|
15
|
+
const doc = await this.Model.findOne({ templateId }).lean();
|
|
16
|
+
return doc ? (0, event_template_mapper_1.toDomain)(doc) : null;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error instanceof errors_1.ValidationError)
|
|
20
|
+
throw error;
|
|
21
|
+
throw new errors_1.QueryError('getById', 'EventTemplate', templateId, error);
|
|
22
|
+
}
|
|
12
23
|
}
|
|
13
24
|
async getByGroupId(groupId) {
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
try {
|
|
26
|
+
if (!groupId || groupId === 0) {
|
|
27
|
+
throw new errors_1.ValidationError('EventTemplate', 'groupId', groupId, 'must be a non-zero number');
|
|
28
|
+
}
|
|
29
|
+
const docs = await this.Model.find({ groupId }).lean();
|
|
30
|
+
return docs.map(d => (0, event_template_mapper_1.toDomain)(d));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof errors_1.ValidationError)
|
|
34
|
+
throw error;
|
|
35
|
+
throw new errors_1.QueryError('getByGroupId', 'EventTemplate', groupId, error);
|
|
36
|
+
}
|
|
16
37
|
}
|
|
17
38
|
async getAll() {
|
|
18
|
-
|
|
19
|
-
|
|
39
|
+
try {
|
|
40
|
+
const docs = await this.Model.find().lean();
|
|
41
|
+
return docs.map(d => (0, event_template_mapper_1.toDomain)(d));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new errors_1.QueryError('getAll', 'EventTemplate', 'all', error);
|
|
45
|
+
}
|
|
20
46
|
}
|
|
21
47
|
async createFromDomain(entity) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
48
|
+
try {
|
|
49
|
+
if (!entity) {
|
|
50
|
+
throw new errors_1.ValidationError('EventTemplate', 'entity', entity, 'entity object is required');
|
|
51
|
+
}
|
|
52
|
+
const templateId = entity.getTemplateId();
|
|
53
|
+
if (!templateId || templateId === 0) {
|
|
54
|
+
throw new errors_1.ValidationError('EventTemplate', 'templateId', templateId, 'must be a non-zero number');
|
|
55
|
+
}
|
|
56
|
+
const write = (0, event_template_mapper_1.toDoc)(entity);
|
|
57
|
+
const saved = await new this.Model(write).save();
|
|
58
|
+
return (0, event_template_mapper_1.toDomain)(saved.toObject());
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (error instanceof errors_1.ValidationError)
|
|
62
|
+
throw error;
|
|
63
|
+
if (error?.code === 11000) {
|
|
64
|
+
throw new errors_1.DuplicateEntityError('EventTemplate', entity.getTemplateId(), error);
|
|
65
|
+
}
|
|
66
|
+
throw new errors_1.QueryError('createFromDomain', 'EventTemplate', entity.getTemplateId(), error);
|
|
67
|
+
}
|
|
25
68
|
}
|
|
26
69
|
async updateFromDomain(entity) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
70
|
+
try {
|
|
71
|
+
if (!entity) {
|
|
72
|
+
throw new errors_1.ValidationError('EventTemplate', 'entity', entity, 'entity object is required');
|
|
73
|
+
}
|
|
74
|
+
const templateId = entity.getTemplateId();
|
|
75
|
+
if (!templateId || templateId === 0) {
|
|
76
|
+
throw new errors_1.ValidationError('EventTemplate', 'templateId', templateId, 'must be a non-zero number');
|
|
77
|
+
}
|
|
78
|
+
const write = (0, event_template_mapper_1.toDoc)(entity);
|
|
79
|
+
const updated = await this.Model.findOneAndUpdate({ templateId }, write, { new: true }).lean();
|
|
80
|
+
return updated ? (0, event_template_mapper_1.toDomain)(updated) : null;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error instanceof errors_1.ValidationError)
|
|
84
|
+
throw error;
|
|
85
|
+
throw new errors_1.QueryError('updateFromDomain', 'EventTemplate', entity.getTemplateId(), error);
|
|
86
|
+
}
|
|
30
87
|
}
|
|
31
88
|
async deleteById(templateId) {
|
|
32
|
-
|
|
89
|
+
try {
|
|
90
|
+
if (!templateId || templateId === 0) {
|
|
91
|
+
throw new errors_1.ValidationError('EventTemplate', 'templateId', templateId, 'must be a non-zero number');
|
|
92
|
+
}
|
|
93
|
+
const result = await this.Model.deleteOne({ templateId });
|
|
94
|
+
if (result.deletedCount === 0) {
|
|
95
|
+
throw new errors_1.EntityNotFoundError('EventTemplate', templateId, 'delete');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (error instanceof errors_1.ValidationError || error instanceof errors_1.EntityNotFoundError) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
throw new errors_1.QueryError('deleteById', 'EventTemplate', templateId, error);
|
|
103
|
+
}
|
|
33
104
|
}
|
|
34
105
|
async setDefaultParticipants(templateId, participants) {
|
|
35
|
-
|
|
36
|
-
|
|
106
|
+
try {
|
|
107
|
+
if (!templateId || templateId === 0) {
|
|
108
|
+
throw new errors_1.ValidationError('EventTemplate', 'templateId', templateId, 'must be a non-zero number');
|
|
109
|
+
}
|
|
110
|
+
if (!Array.isArray(participants)) {
|
|
111
|
+
throw new errors_1.ValidationError('EventTemplate', 'participants', participants, 'must be an array');
|
|
112
|
+
}
|
|
113
|
+
const doc = await this.Model.findOneAndUpdate({ templateId }, { $set: { defaultParticipants: participants } }, { new: true }).lean();
|
|
114
|
+
return doc ? (0, event_template_mapper_1.toDomain)(doc) : null;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof errors_1.ValidationError)
|
|
118
|
+
throw error;
|
|
119
|
+
throw new errors_1.QueryError('setDefaultParticipants', 'EventTemplate', templateId, error);
|
|
120
|
+
}
|
|
37
121
|
}
|
|
38
122
|
}
|
|
39
123
|
exports.MongoEventTemplatesRepository = MongoEventTemplatesRepository;
|
|
@@ -2,53 +2,162 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoEventsRepository = void 0;
|
|
4
4
|
const event_mapper_1 = require("./event.mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
5
6
|
class MongoEventsRepository {
|
|
6
7
|
constructor(EventModel) {
|
|
7
8
|
this.EventModel = EventModel;
|
|
8
9
|
}
|
|
9
10
|
async create(event) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
try {
|
|
12
|
+
// Validate input
|
|
13
|
+
if (!event) {
|
|
14
|
+
throw new errors_1.ValidationError('Event', 'event', event, 'event object is required');
|
|
15
|
+
}
|
|
16
|
+
const eventId = event.getEventId();
|
|
17
|
+
if (!eventId || eventId === 0) {
|
|
18
|
+
throw new errors_1.ValidationError('Event', 'eventId', eventId, 'must be a non-zero number');
|
|
19
|
+
}
|
|
20
|
+
const write = (0, event_mapper_1.toDoc)(event);
|
|
21
|
+
const saved = await new this.EventModel(write).save();
|
|
22
|
+
return (0, event_mapper_1.toDomain)(saved.toObject());
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof errors_1.ValidationError) {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
// Check for duplicate key error
|
|
29
|
+
if (error?.code === 11000) {
|
|
30
|
+
throw new errors_1.DuplicateEntityError('Event', event.getEventId(), error);
|
|
31
|
+
}
|
|
32
|
+
throw new errors_1.QueryError('create', 'Event', event.getEventId(), error);
|
|
33
|
+
}
|
|
13
34
|
}
|
|
14
35
|
async findById(eventId) {
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
try {
|
|
37
|
+
// Validate input
|
|
38
|
+
if (!eventId || eventId === 0) {
|
|
39
|
+
throw new errors_1.ValidationError('Event', 'eventId', eventId, 'must be a non-zero number');
|
|
40
|
+
}
|
|
41
|
+
const doc = await this.EventModel.findOne({ eventId }).lean();
|
|
42
|
+
return doc ? (0, event_mapper_1.toDomain)(doc) : null;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof errors_1.ValidationError) {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
throw new errors_1.QueryError('findById', 'Event', eventId, error);
|
|
49
|
+
}
|
|
17
50
|
}
|
|
18
51
|
async findByGroupAndStatuses(groupId, statuses) {
|
|
19
|
-
|
|
20
|
-
|
|
52
|
+
try {
|
|
53
|
+
// Validate input
|
|
54
|
+
if (!groupId || groupId === 0) {
|
|
55
|
+
throw new errors_1.ValidationError('Event', 'groupId', groupId, 'must be a non-zero number');
|
|
56
|
+
}
|
|
57
|
+
if (!statuses || !Array.isArray(statuses) || statuses.length === 0) {
|
|
58
|
+
throw new errors_1.ValidationError('Event', 'statuses', statuses, 'must be a non-empty array');
|
|
59
|
+
}
|
|
60
|
+
const doc = await this.EventModel.findOne({ groupId, status: { $in: statuses } }).lean();
|
|
61
|
+
return doc ? (0, event_mapper_1.toDomain)(doc) : null;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof errors_1.ValidationError) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
throw new errors_1.QueryError('findByGroupAndStatuses', 'Event', groupId, error);
|
|
68
|
+
}
|
|
21
69
|
}
|
|
22
70
|
async findByTemplateAndGroup(templateId, groupId) {
|
|
23
|
-
|
|
24
|
-
|
|
71
|
+
try {
|
|
72
|
+
if (!templateId || templateId === 0) {
|
|
73
|
+
throw new errors_1.ValidationError('Event', 'templateId', templateId, 'must be a non-zero number');
|
|
74
|
+
}
|
|
75
|
+
if (!groupId || groupId === 0) {
|
|
76
|
+
throw new errors_1.ValidationError('Event', 'groupId', groupId, 'must be a non-zero number');
|
|
77
|
+
}
|
|
78
|
+
const doc = await this.EventModel.findOne({ templateId, groupId, status: "active" }).lean();
|
|
79
|
+
return doc ? (0, event_mapper_1.toDomain)(doc) : null;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof errors_1.ValidationError)
|
|
83
|
+
throw error;
|
|
84
|
+
throw new errors_1.QueryError('findByTemplateAndGroup', 'Event', `${templateId}-${groupId}`, error);
|
|
85
|
+
}
|
|
25
86
|
}
|
|
26
87
|
async update(eventId, updates) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
88
|
+
try {
|
|
89
|
+
if (!eventId || eventId === 0) {
|
|
90
|
+
throw new errors_1.ValidationError('Event', 'eventId', eventId, 'must be a non-zero number');
|
|
91
|
+
}
|
|
92
|
+
if (!updates) {
|
|
93
|
+
throw new errors_1.ValidationError('Event', 'updates', updates, 'updates object is required');
|
|
94
|
+
}
|
|
95
|
+
const write = (0, event_mapper_1.toDoc)(updates);
|
|
96
|
+
const doc = await this.EventModel.findOneAndUpdate({ eventId }, { $set: write }, { new: true }).lean();
|
|
97
|
+
return doc ? (0, event_mapper_1.toDomain)(doc) : null;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error instanceof errors_1.ValidationError)
|
|
101
|
+
throw error;
|
|
102
|
+
throw new errors_1.QueryError('update', 'Event', eventId, error);
|
|
103
|
+
}
|
|
30
104
|
}
|
|
31
105
|
async findLastByGroup(groupId) {
|
|
32
|
-
|
|
33
|
-
|
|
106
|
+
try {
|
|
107
|
+
if (!groupId || groupId === 0) {
|
|
108
|
+
throw new errors_1.ValidationError('Event', 'groupId', groupId, 'must be a non-zero number');
|
|
109
|
+
}
|
|
110
|
+
const doc = await this.EventModel.findOne({ groupId }).sort({ date: -1 }).lean();
|
|
111
|
+
return doc ? (0, event_mapper_1.toDomain)(doc) : null;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (error instanceof errors_1.ValidationError)
|
|
115
|
+
throw error;
|
|
116
|
+
throw new errors_1.QueryError('findLastByGroup', 'Event', groupId, error);
|
|
117
|
+
}
|
|
34
118
|
}
|
|
35
119
|
async findAllByGroup(groupId) {
|
|
36
|
-
|
|
37
|
-
|
|
120
|
+
try {
|
|
121
|
+
if (!groupId || groupId === 0) {
|
|
122
|
+
throw new errors_1.ValidationError('Event', 'groupId', groupId, 'must be a non-zero number');
|
|
123
|
+
}
|
|
124
|
+
const docs = await this.EventModel.find({ groupId }).lean();
|
|
125
|
+
return docs.map(d => (0, event_mapper_1.toDomain)(d));
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error instanceof errors_1.ValidationError)
|
|
129
|
+
throw error;
|
|
130
|
+
throw new errors_1.QueryError('findAllByGroup', 'Event', groupId, error);
|
|
131
|
+
}
|
|
38
132
|
}
|
|
39
133
|
async countEvents() {
|
|
40
|
-
|
|
134
|
+
try {
|
|
135
|
+
return await this.EventModel.countDocuments();
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
throw new errors_1.QueryError('countEvents', 'Event', 'all', error);
|
|
139
|
+
}
|
|
41
140
|
}
|
|
42
141
|
async countMatches() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
142
|
+
try {
|
|
143
|
+
const result = await this.EventModel.aggregate([
|
|
144
|
+
{ $unwind: "$matches" },
|
|
145
|
+
{ $count: "matches" }
|
|
146
|
+
]);
|
|
147
|
+
return result.length > 0 ? result[0].matches : 0;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw new errors_1.QueryError('countMatches', 'Event', 'all', error);
|
|
151
|
+
}
|
|
48
152
|
}
|
|
49
153
|
async getAll() {
|
|
50
|
-
|
|
51
|
-
|
|
154
|
+
try {
|
|
155
|
+
const docs = await this.EventModel.find().lean();
|
|
156
|
+
return docs.map(d => (0, event_mapper_1.toDomain)(d));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
throw new errors_1.QueryError('getAll', 'Event', 'all', error);
|
|
160
|
+
}
|
|
52
161
|
}
|
|
53
162
|
}
|
|
54
163
|
exports.MongoEventsRepository = MongoEventsRepository;
|
|
@@ -2,30 +2,99 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoGroupsRepository = void 0;
|
|
4
4
|
const group_mapper_1 = require("./group.mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
5
6
|
class MongoGroupsRepository {
|
|
6
7
|
constructor(GroupModel) {
|
|
7
8
|
this.GroupModel = GroupModel;
|
|
8
9
|
}
|
|
9
10
|
async create(group) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
try {
|
|
12
|
+
// Validate input
|
|
13
|
+
if (!group) {
|
|
14
|
+
throw new errors_1.ValidationError('Group', 'group', group, 'group object is required');
|
|
15
|
+
}
|
|
16
|
+
const groupId = group.getGroupId();
|
|
17
|
+
if (!groupId || groupId === 0) {
|
|
18
|
+
throw new errors_1.ValidationError('Group', 'groupId', groupId, 'must be a non-zero number');
|
|
19
|
+
}
|
|
20
|
+
const write = (0, group_mapper_1.toDoc)(group);
|
|
21
|
+
const saved = await new this.GroupModel(write).save();
|
|
22
|
+
return (0, group_mapper_1.toDomain)(saved.toObject());
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof errors_1.ValidationError) {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
// Check for duplicate key error
|
|
29
|
+
if (error?.code === 11000) {
|
|
30
|
+
throw new errors_1.DuplicateEntityError('Group', group.getGroupId(), error);
|
|
31
|
+
}
|
|
32
|
+
throw new errors_1.QueryError('create', 'Group', group.getGroupId(), error);
|
|
33
|
+
}
|
|
13
34
|
}
|
|
14
35
|
async findById(groupId) {
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
try {
|
|
37
|
+
// Validate input
|
|
38
|
+
if (!groupId || groupId === 0) {
|
|
39
|
+
throw new errors_1.ValidationError('Group', 'groupId', groupId, 'must be a non-zero number');
|
|
40
|
+
}
|
|
41
|
+
const doc = await this.GroupModel.findOne({ groupId }).lean();
|
|
42
|
+
return doc ? (0, group_mapper_1.toDomain)(doc) : null;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof errors_1.ValidationError) {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
throw new errors_1.QueryError('findById', 'Group', groupId, error);
|
|
49
|
+
}
|
|
17
50
|
}
|
|
18
51
|
async update(groupId, updates) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
52
|
+
try {
|
|
53
|
+
// Validate input
|
|
54
|
+
if (!groupId || groupId === 0) {
|
|
55
|
+
throw new errors_1.ValidationError('Group', 'groupId', groupId, 'must be a non-zero number');
|
|
56
|
+
}
|
|
57
|
+
if (!updates) {
|
|
58
|
+
throw new errors_1.ValidationError('Group', 'updates', updates, 'updates object is required');
|
|
59
|
+
}
|
|
60
|
+
const write = (0, group_mapper_1.toDoc)(updates);
|
|
61
|
+
const doc = await this.GroupModel.findOneAndUpdate({ groupId }, { $set: write }, { new: true }).lean();
|
|
62
|
+
return doc ? (0, group_mapper_1.toDomain)(doc) : null;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof errors_1.ValidationError) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
throw new errors_1.QueryError('update', 'Group', groupId, error);
|
|
69
|
+
}
|
|
22
70
|
}
|
|
23
71
|
async findAll() {
|
|
24
|
-
|
|
25
|
-
|
|
72
|
+
try {
|
|
73
|
+
const docs = await this.GroupModel.find().lean();
|
|
74
|
+
return docs.map((doc) => (0, group_mapper_1.toDomain)(doc));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw new errors_1.QueryError('findAll', 'Group', 'all', error);
|
|
78
|
+
}
|
|
26
79
|
}
|
|
27
80
|
async delete(groupId) {
|
|
28
|
-
|
|
81
|
+
try {
|
|
82
|
+
// Validate input
|
|
83
|
+
if (!groupId || groupId === 0) {
|
|
84
|
+
throw new errors_1.ValidationError('Group', 'groupId', groupId, 'must be a non-zero number');
|
|
85
|
+
}
|
|
86
|
+
const result = await this.GroupModel.deleteOne({ groupId });
|
|
87
|
+
// Check if document was actually deleted
|
|
88
|
+
if (result.deletedCount === 0) {
|
|
89
|
+
throw new errors_1.EntityNotFoundError('Group', groupId, 'delete');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (error instanceof errors_1.ValidationError || error instanceof errors_1.EntityNotFoundError) {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
throw new errors_1.QueryError('delete', 'Group', groupId, error);
|
|
97
|
+
}
|
|
29
98
|
}
|
|
30
99
|
}
|
|
31
100
|
exports.MongoGroupsRepository = MongoGroupsRepository;
|
|
@@ -2,23 +2,66 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MongoUsersRepository = void 0;
|
|
4
4
|
const user_mapper_1 = require("./user.mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
5
6
|
class MongoUsersRepository {
|
|
6
7
|
constructor(UserModel) {
|
|
7
8
|
this.UserModel = UserModel;
|
|
8
9
|
}
|
|
9
10
|
async findByUserId(userId) {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
try {
|
|
12
|
+
// Validate input
|
|
13
|
+
if (!userId || userId === 0) {
|
|
14
|
+
throw new errors_1.ValidationError('User', 'userId', userId, 'must be a non-zero number');
|
|
15
|
+
}
|
|
16
|
+
const doc = await this.UserModel.findOne({ userId }).lean();
|
|
17
|
+
return doc ? (0, user_mapper_1.toDomain)(doc) : null;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof errors_1.ValidationError) {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
throw new errors_1.QueryError('findByUserId', 'User', userId, error);
|
|
24
|
+
}
|
|
12
25
|
}
|
|
13
26
|
async upsert(user) {
|
|
14
|
-
|
|
27
|
+
try {
|
|
28
|
+
// Validate input
|
|
29
|
+
if (!user) {
|
|
30
|
+
throw new errors_1.ValidationError('User', 'user', user, 'user object is required');
|
|
31
|
+
}
|
|
32
|
+
const userId = user.getUserId();
|
|
33
|
+
if (!userId || userId === 0) {
|
|
34
|
+
throw new errors_1.ValidationError('User', 'userId', userId, 'must be a non-zero number');
|
|
35
|
+
}
|
|
36
|
+
await this.UserModel.updateOne({ userId }, { $set: (0, user_mapper_1.toDoc)(user) }, { upsert: true });
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof errors_1.ValidationError) {
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
// Check for duplicate key error
|
|
43
|
+
if (error?.code === 11000) {
|
|
44
|
+
throw new errors_1.DuplicateEntityError('User', user.getUserId(), error);
|
|
45
|
+
}
|
|
46
|
+
throw new errors_1.QueryError('upsert', 'User', user.getUserId(), error);
|
|
47
|
+
}
|
|
15
48
|
}
|
|
16
49
|
async count() {
|
|
17
|
-
|
|
50
|
+
try {
|
|
51
|
+
return await this.UserModel.countDocuments();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new errors_1.QueryError('count', 'User', 'all', error);
|
|
55
|
+
}
|
|
18
56
|
}
|
|
19
57
|
async findAll() {
|
|
20
|
-
|
|
21
|
-
|
|
58
|
+
try {
|
|
59
|
+
const docs = await this.UserModel.find().lean();
|
|
60
|
+
return docs.map(d => (0, user_mapper_1.toDomain)(d));
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new errors_1.QueryError('findAll', 'User', 'all', error);
|
|
64
|
+
}
|
|
22
65
|
}
|
|
23
66
|
}
|
|
24
67
|
exports.MongoUsersRepository = MongoUsersRepository;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ballrush-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc -p tsconfig.json",
|
|
15
15
|
"clean": "rimraf dist",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"test:watch": "jest --watch",
|
|
18
|
+
"test:cov": "jest --coverage",
|
|
16
19
|
"pack:check": "npm pack --dry-run",
|
|
17
20
|
"prepublishOnly": "npm run clean && npm run build && npm run pack:check",
|
|
18
21
|
"release:patch": "./release.sh patch",
|
|
@@ -24,9 +27,13 @@
|
|
|
24
27
|
"mongoose": "^7.0.0 || ^8.0.0"
|
|
25
28
|
},
|
|
26
29
|
"devDependencies": {
|
|
27
|
-
"
|
|
30
|
+
"@types/jest": "^30.0.0",
|
|
31
|
+
"jest": "^30.1.3",
|
|
32
|
+
"mongoose": "^7.8.7",
|
|
28
33
|
"rimraf": "^5.0.0",
|
|
29
|
-
"
|
|
34
|
+
"ts-jest": "^29.4.4",
|
|
35
|
+
"ts-node": "^10.9.2",
|
|
36
|
+
"typescript": "^5.9.2"
|
|
30
37
|
},
|
|
31
38
|
"publishConfig": {
|
|
32
39
|
"access": "public"
|