ballrush-core 0.4.2 → 0.4.3
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/group.d.ts +4 -0
- package/dist/domain/group.js +7 -2
- package/dist/domain/index.d.ts +1 -0
- package/dist/domain/index.js +1 -0
- package/dist/domain/stat-group.d.ts +26 -0
- package/dist/domain/stat-group.js +35 -0
- package/dist/mongo/index.d.ts +1 -0
- package/dist/mongo/index.js +1 -0
- package/dist/mongo/schemas/group.schema.d.ts +3 -0
- package/dist/mongo/schemas/group.schema.js +3 -0
- package/dist/mongo/schemas/stat-group.schema.d.ts +15 -0
- package/dist/mongo/schemas/stat-group.schema.js +19 -0
- package/dist/ports/groups.repository.d.ts +1 -0
- package/dist/ports/index.d.ts +1 -0
- package/dist/ports/index.js +1 -0
- package/dist/ports/stat-group.repository.d.ts +41 -0
- package/dist/ports/stat-group.repository.js +2 -0
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +1 -0
- package/dist/repositories/mongo/group.mapper.js +2 -0
- package/dist/repositories/mongo/stat-group.mapper.d.ts +4 -0
- package/dist/repositories/mongo/stat-group.mapper.js +27 -0
- package/dist/repositories/mongo/stat-group.repository.d.ts +13 -0
- package/dist/repositories/mongo/stat-group.repository.js +165 -0
- package/package.json +1 -1
package/dist/domain/group.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class Group {
|
|
|
6
6
|
private timezone;
|
|
7
7
|
private isMessageLast;
|
|
8
8
|
private language;
|
|
9
|
+
private isPublic;
|
|
9
10
|
private constructor();
|
|
10
11
|
static create(params: {
|
|
11
12
|
groupId: number;
|
|
@@ -14,6 +15,7 @@ export declare class Group {
|
|
|
14
15
|
timezone?: string;
|
|
15
16
|
isMessageLast?: boolean;
|
|
16
17
|
language?: LanguageType;
|
|
18
|
+
isPublic?: boolean;
|
|
17
19
|
}): Group;
|
|
18
20
|
getGroupId(): number;
|
|
19
21
|
getGroupName(): string;
|
|
@@ -21,11 +23,13 @@ export declare class Group {
|
|
|
21
23
|
getIsMessageLast(): boolean;
|
|
22
24
|
getLanguage(): LanguageType;
|
|
23
25
|
getParticipants(): ParticipantGroup[];
|
|
26
|
+
getIsPublic(): boolean;
|
|
24
27
|
getAdmins(): ParticipantGroup[];
|
|
25
28
|
getAdminIds(): number[];
|
|
26
29
|
setTimezone(tz: string): void;
|
|
27
30
|
setIsMessageLast(v: boolean): void;
|
|
28
31
|
setLanguage(language: LanguageType): void;
|
|
32
|
+
setIsPublic(value: boolean): void;
|
|
29
33
|
addAdmin(userId: number): void;
|
|
30
34
|
removeAdmin(userId: number): void;
|
|
31
35
|
addNewParticipant(userId: number, isAdmin?: boolean, initialRating?: number): boolean;
|
package/dist/domain/group.js
CHANGED
|
@@ -4,18 +4,19 @@ exports.Group = void 0;
|
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
class Group {
|
|
7
|
-
constructor(groupId, groupName, participants, timezone = "UTC+0", isMessageLast = false, language = "en") {
|
|
7
|
+
constructor(groupId, groupName, participants, timezone = "UTC+0", isMessageLast = false, language = "en", isPublic = false) {
|
|
8
8
|
this.groupId = groupId;
|
|
9
9
|
this.groupName = groupName;
|
|
10
10
|
this.participants = participants;
|
|
11
11
|
this.timezone = timezone;
|
|
12
12
|
this.isMessageLast = isMessageLast;
|
|
13
13
|
this.language = language;
|
|
14
|
+
this.isPublic = isPublic;
|
|
14
15
|
}
|
|
15
16
|
static create(params) {
|
|
16
17
|
if (!params.groupName)
|
|
17
18
|
throw new Error("Group name is required");
|
|
18
|
-
return new Group(params.groupId, params.groupName, (params.participants ?? []).map(p => ({ ...p, ratingHistory: [...p.ratingHistory] })), params.timezone ?? "UTC+0", params.isMessageLast ?? false, params.language ?? "en");
|
|
19
|
+
return new Group(params.groupId, params.groupName, (params.participants ?? []).map(p => ({ ...p, ratingHistory: [...p.ratingHistory] })), params.timezone ?? "UTC+0", params.isMessageLast ?? false, params.language ?? "en", params.isPublic ?? false);
|
|
19
20
|
}
|
|
20
21
|
getGroupId() { return this.groupId; }
|
|
21
22
|
getGroupName() { return this.groupName; }
|
|
@@ -23,6 +24,7 @@ class Group {
|
|
|
23
24
|
getIsMessageLast() { return this.isMessageLast; }
|
|
24
25
|
getLanguage() { return this.language; }
|
|
25
26
|
getParticipants() { return this.participants; }
|
|
27
|
+
getIsPublic() { return this.isPublic; }
|
|
26
28
|
getAdmins() {
|
|
27
29
|
return this.participants.filter(p => p.isAdmin);
|
|
28
30
|
}
|
|
@@ -38,6 +40,9 @@ class Group {
|
|
|
38
40
|
setLanguage(language) {
|
|
39
41
|
this.language = language;
|
|
40
42
|
}
|
|
43
|
+
setIsPublic(value) {
|
|
44
|
+
this.isPublic = value;
|
|
45
|
+
}
|
|
41
46
|
addAdmin(userId) {
|
|
42
47
|
const p = this.participants.find(x => x.userId === userId);
|
|
43
48
|
if (p) {
|
package/dist/domain/index.d.ts
CHANGED
package/dist/domain/index.js
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class StatGroup {
|
|
2
|
+
private readonly groupId;
|
|
3
|
+
private readonly groupName;
|
|
4
|
+
private readonly seasonsCount;
|
|
5
|
+
private readonly eventsCount;
|
|
6
|
+
private readonly matchesCount;
|
|
7
|
+
private readonly participantsCount;
|
|
8
|
+
private readonly updatedAt;
|
|
9
|
+
private constructor();
|
|
10
|
+
static create(params: {
|
|
11
|
+
groupId: number;
|
|
12
|
+
groupName: string;
|
|
13
|
+
seasonsCount: number;
|
|
14
|
+
eventsCount: number;
|
|
15
|
+
matchesCount: number;
|
|
16
|
+
participantsCount: number;
|
|
17
|
+
updatedAt?: Date;
|
|
18
|
+
}): StatGroup;
|
|
19
|
+
getGroupId(): number;
|
|
20
|
+
getGroupName(): string;
|
|
21
|
+
getSeasonsCount(): number;
|
|
22
|
+
getEventsCount(): number;
|
|
23
|
+
getMatchesCount(): number;
|
|
24
|
+
getParticipantsCount(): number;
|
|
25
|
+
getUpdatedAt(): Date;
|
|
26
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatGroup = void 0;
|
|
4
|
+
class StatGroup {
|
|
5
|
+
constructor(groupId, groupName, seasonsCount, eventsCount, matchesCount, participantsCount, updatedAt) {
|
|
6
|
+
this.groupId = groupId;
|
|
7
|
+
this.groupName = groupName;
|
|
8
|
+
this.seasonsCount = seasonsCount;
|
|
9
|
+
this.eventsCount = eventsCount;
|
|
10
|
+
this.matchesCount = matchesCount;
|
|
11
|
+
this.participantsCount = participantsCount;
|
|
12
|
+
this.updatedAt = updatedAt;
|
|
13
|
+
}
|
|
14
|
+
static create(params) {
|
|
15
|
+
if (!params.groupName)
|
|
16
|
+
throw new Error("Group name is required");
|
|
17
|
+
if (params.seasonsCount < 0)
|
|
18
|
+
throw new Error("Seasons count cannot be negative");
|
|
19
|
+
if (params.eventsCount < 0)
|
|
20
|
+
throw new Error("Events count cannot be negative");
|
|
21
|
+
if (params.matchesCount < 0)
|
|
22
|
+
throw new Error("Matches count cannot be negative");
|
|
23
|
+
if (params.participantsCount < 0)
|
|
24
|
+
throw new Error("Participants count cannot be negative");
|
|
25
|
+
return new StatGroup(params.groupId, params.groupName, params.seasonsCount, params.eventsCount, params.matchesCount, params.participantsCount, params.updatedAt ?? new Date());
|
|
26
|
+
}
|
|
27
|
+
getGroupId() { return this.groupId; }
|
|
28
|
+
getGroupName() { return this.groupName; }
|
|
29
|
+
getSeasonsCount() { return this.seasonsCount; }
|
|
30
|
+
getEventsCount() { return this.eventsCount; }
|
|
31
|
+
getMatchesCount() { return this.matchesCount; }
|
|
32
|
+
getParticipantsCount() { return this.participantsCount; }
|
|
33
|
+
getUpdatedAt() { return this.updatedAt; }
|
|
34
|
+
}
|
|
35
|
+
exports.StatGroup = StatGroup;
|
package/dist/mongo/index.d.ts
CHANGED
package/dist/mongo/index.js
CHANGED
|
@@ -18,3 +18,4 @@ __exportStar(require("./schemas/user.schema"), exports);
|
|
|
18
18
|
__exportStar(require("./schemas/event-template.schema"), exports);
|
|
19
19
|
__exportStar(require("./schemas/event.schema"), exports);
|
|
20
20
|
__exportStar(require("./schemas/group.schema"), exports);
|
|
21
|
+
__exportStar(require("./schemas/stat-group.schema"), exports);
|
|
@@ -7,6 +7,9 @@ export interface GroupDoc {
|
|
|
7
7
|
timezone: string;
|
|
8
8
|
isMessageLast: boolean;
|
|
9
9
|
language: LanguageType;
|
|
10
|
+
isPublic?: boolean;
|
|
11
|
+
createdAt?: Date;
|
|
12
|
+
updatedAt?: Date;
|
|
10
13
|
}
|
|
11
14
|
export declare function createRatingPointSchema(): Schema<RatingPoint, import("mongoose").Model<RatingPoint, any, any, any, import("mongoose").Document<unknown, any, RatingPoint> & RatingPoint & {
|
|
12
15
|
_id: import("mongoose").Types.ObjectId;
|
|
@@ -30,6 +30,9 @@ function createGroupSchema() {
|
|
|
30
30
|
timezone: { type: String, default: "UTC+0" },
|
|
31
31
|
isMessageLast: { type: Boolean, default: false },
|
|
32
32
|
language: { type: String, enum: ['en', 'ru', 'ua'], default: 'en' },
|
|
33
|
+
isPublic: { type: Boolean, default: false, index: true },
|
|
34
|
+
}, {
|
|
35
|
+
timestamps: true, // Adds createdAt and updatedAt automatically
|
|
33
36
|
});
|
|
34
37
|
return GroupSchema;
|
|
35
38
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
export interface StatGroupDoc {
|
|
3
|
+
groupId: number;
|
|
4
|
+
groupName: string;
|
|
5
|
+
seasonsCount: number;
|
|
6
|
+
eventsCount: number;
|
|
7
|
+
matchesCount: number;
|
|
8
|
+
participantsCount: number;
|
|
9
|
+
updatedAt: Date;
|
|
10
|
+
}
|
|
11
|
+
export declare function createStatGroupSchema(): Schema<StatGroupDoc, import("mongoose").Model<StatGroupDoc, any, any, any, import("mongoose").Document<unknown, any, StatGroupDoc> & StatGroupDoc & {
|
|
12
|
+
_id: import("mongoose").Types.ObjectId;
|
|
13
|
+
}, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, StatGroupDoc, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<StatGroupDoc>> & import("mongoose").FlatRecord<StatGroupDoc> & {
|
|
14
|
+
_id: import("mongoose").Types.ObjectId;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStatGroupSchema = createStatGroupSchema;
|
|
4
|
+
const mongoose_1 = require("mongoose");
|
|
5
|
+
function createStatGroupSchema() {
|
|
6
|
+
const StatGroupSchema = new mongoose_1.Schema({
|
|
7
|
+
groupId: { type: Number, required: true, unique: true, index: true },
|
|
8
|
+
groupName: { type: String, required: true },
|
|
9
|
+
seasonsCount: { type: Number, required: true, min: 0 },
|
|
10
|
+
eventsCount: { type: Number, required: true, min: 0 },
|
|
11
|
+
matchesCount: { type: Number, required: true, min: 0 },
|
|
12
|
+
participantsCount: { type: Number, required: true, min: 0 },
|
|
13
|
+
updatedAt: { type: Date, default: Date.now },
|
|
14
|
+
}, {
|
|
15
|
+
collection: 'stat_group',
|
|
16
|
+
versionKey: false, // убирает поле __v
|
|
17
|
+
});
|
|
18
|
+
return StatGroupSchema;
|
|
19
|
+
}
|
package/dist/ports/index.d.ts
CHANGED
package/dist/ports/index.js
CHANGED
|
@@ -18,3 +18,4 @@ __exportStar(require("./users.repository"), exports);
|
|
|
18
18
|
__exportStar(require("./groups.repository"), exports);
|
|
19
19
|
__exportStar(require("./events.repository"), exports);
|
|
20
20
|
__exportStar(require("./event-templates.repository"), exports);
|
|
21
|
+
__exportStar(require("./stat-group.repository"), exports);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { StatGroup } from "../domain/stat-group";
|
|
2
|
+
export interface FindPublicGroupsOptions {
|
|
3
|
+
page: number;
|
|
4
|
+
limit: number;
|
|
5
|
+
search?: string;
|
|
6
|
+
sort: 'lastActivity' | 'name' | 'members' | 'games';
|
|
7
|
+
}
|
|
8
|
+
export interface PublicGroupsWithStatsResult {
|
|
9
|
+
groups: Array<{
|
|
10
|
+
groupId: number;
|
|
11
|
+
groupName: string;
|
|
12
|
+
updatedAt: Date;
|
|
13
|
+
statistics: {
|
|
14
|
+
seasonsCount: number;
|
|
15
|
+
eventsCount: number;
|
|
16
|
+
matchesCount: number;
|
|
17
|
+
participantsCount: number;
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
totalCount: number;
|
|
21
|
+
}
|
|
22
|
+
export interface StatGroupRepository {
|
|
23
|
+
/**
|
|
24
|
+
* Find statistics for a specific group
|
|
25
|
+
* @param groupId The group ID
|
|
26
|
+
* @returns Group statistics or null if not found
|
|
27
|
+
*/
|
|
28
|
+
findByGroupId(groupId: number): Promise<StatGroup | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Find public groups with their statistics using aggregation
|
|
31
|
+
* @param options Query options for filtering, pagination, and sorting
|
|
32
|
+
* @returns Paginated list of public groups with statistics
|
|
33
|
+
*/
|
|
34
|
+
findPublicGroupsWithStats(options: FindPublicGroupsOptions): Promise<PublicGroupsWithStatsResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Create or update group statistics
|
|
37
|
+
* @param stats The statistics to save
|
|
38
|
+
* @returns The saved statistics
|
|
39
|
+
*/
|
|
40
|
+
upsert(stats: StatGroup): Promise<StatGroup>;
|
|
41
|
+
}
|
|
@@ -18,3 +18,4 @@ __exportStar(require("./mongo/user.repository"), exports);
|
|
|
18
18
|
__exportStar(require("./mongo/group.repository"), exports);
|
|
19
19
|
__exportStar(require("./mongo/event.repository"), exports);
|
|
20
20
|
__exportStar(require("./mongo/event-template.repository"), exports);
|
|
21
|
+
__exportStar(require("./mongo/stat-group.repository"), exports);
|
|
@@ -11,6 +11,7 @@ function toDomain(doc) {
|
|
|
11
11
|
timezone: doc.timezone,
|
|
12
12
|
isMessageLast: doc.isMessageLast,
|
|
13
13
|
language: doc.language,
|
|
14
|
+
isPublic: doc.isPublic ?? false,
|
|
14
15
|
});
|
|
15
16
|
}
|
|
16
17
|
function toDoc(group) {
|
|
@@ -21,5 +22,6 @@ function toDoc(group) {
|
|
|
21
22
|
timezone: group.getTimezone(),
|
|
22
23
|
isMessageLast: group.getIsMessageLast(),
|
|
23
24
|
language: group.getLanguage(),
|
|
25
|
+
isPublic: group.getIsPublic(),
|
|
24
26
|
};
|
|
25
27
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toStatGroupDomain = toStatGroupDomain;
|
|
4
|
+
exports.toStatGroupDoc = toStatGroupDoc;
|
|
5
|
+
const stat_group_1 = require("../../domain/stat-group");
|
|
6
|
+
function toStatGroupDomain(doc) {
|
|
7
|
+
return stat_group_1.StatGroup.create({
|
|
8
|
+
groupId: doc.groupId,
|
|
9
|
+
groupName: doc.groupName,
|
|
10
|
+
seasonsCount: doc.seasonsCount,
|
|
11
|
+
eventsCount: doc.eventsCount,
|
|
12
|
+
matchesCount: doc.matchesCount,
|
|
13
|
+
participantsCount: doc.participantsCount,
|
|
14
|
+
updatedAt: doc.updatedAt,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function toStatGroupDoc(statGroup) {
|
|
18
|
+
return {
|
|
19
|
+
groupId: statGroup.getGroupId(),
|
|
20
|
+
groupName: statGroup.getGroupName(),
|
|
21
|
+
seasonsCount: statGroup.getSeasonsCount(),
|
|
22
|
+
eventsCount: statGroup.getEventsCount(),
|
|
23
|
+
matchesCount: statGroup.getMatchesCount(),
|
|
24
|
+
participantsCount: statGroup.getParticipantsCount(),
|
|
25
|
+
updatedAt: statGroup.getUpdatedAt(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Model } from "mongoose";
|
|
2
|
+
import type { StatGroupRepository, FindPublicGroupsOptions, PublicGroupsWithStatsResult } from "../../ports/stat-group.repository";
|
|
3
|
+
import type { StatGroupDoc } from "../../mongo";
|
|
4
|
+
import type { GroupDoc } from "../../mongo";
|
|
5
|
+
import { StatGroup } from "../../domain/stat-group";
|
|
6
|
+
export declare class MongoStatGroupRepository implements StatGroupRepository {
|
|
7
|
+
private readonly StatGroupModel;
|
|
8
|
+
private readonly GroupModel;
|
|
9
|
+
constructor(StatGroupModel: Model<StatGroupDoc>, GroupModel: Model<GroupDoc>);
|
|
10
|
+
findByGroupId(groupId: number): Promise<StatGroup | null>;
|
|
11
|
+
findPublicGroupsWithStats(options: FindPublicGroupsOptions): Promise<PublicGroupsWithStatsResult>;
|
|
12
|
+
upsert(stats: StatGroup): Promise<StatGroup>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoStatGroupRepository = void 0;
|
|
4
|
+
const stat_group_mapper_1 = require("./stat-group.mapper");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
class MongoStatGroupRepository {
|
|
7
|
+
constructor(StatGroupModel, GroupModel) {
|
|
8
|
+
this.StatGroupModel = StatGroupModel;
|
|
9
|
+
this.GroupModel = GroupModel;
|
|
10
|
+
}
|
|
11
|
+
async findByGroupId(groupId) {
|
|
12
|
+
try {
|
|
13
|
+
// Validate input
|
|
14
|
+
if (!groupId || groupId === 0) {
|
|
15
|
+
throw new errors_1.ValidationError('StatGroup', 'groupId', groupId, 'must be a non-zero number');
|
|
16
|
+
}
|
|
17
|
+
const doc = await this.StatGroupModel.findOne({ groupId }).lean();
|
|
18
|
+
return doc ? (0, stat_group_mapper_1.toStatGroupDomain)(doc) : null;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof errors_1.ValidationError) {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
throw new errors_1.QueryError('findByGroupId', 'StatGroup', groupId, error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async findPublicGroupsWithStats(options) {
|
|
28
|
+
try {
|
|
29
|
+
const { page, limit, search, sort } = options;
|
|
30
|
+
const skip = (page - 1) * limit;
|
|
31
|
+
// Build match stage for public groups
|
|
32
|
+
const matchStage = { isPublic: true };
|
|
33
|
+
if (search) {
|
|
34
|
+
matchStage.groupName = { $regex: search, $options: 'i' };
|
|
35
|
+
}
|
|
36
|
+
// Build sort stage
|
|
37
|
+
let sortStage = {};
|
|
38
|
+
switch (sort) {
|
|
39
|
+
case 'lastActivity':
|
|
40
|
+
sortStage = { 'statistics.updatedAt': -1 };
|
|
41
|
+
break;
|
|
42
|
+
case 'name':
|
|
43
|
+
sortStage = { groupName: 1 };
|
|
44
|
+
break;
|
|
45
|
+
case 'members':
|
|
46
|
+
sortStage = { 'statistics.participantsCount': -1 };
|
|
47
|
+
break;
|
|
48
|
+
case 'games':
|
|
49
|
+
sortStage = { 'statistics.matchesCount': -1 };
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
// Aggregation pipeline to join groups with statistics
|
|
53
|
+
const pipeline = [
|
|
54
|
+
// Match public groups
|
|
55
|
+
{ $match: matchStage },
|
|
56
|
+
// Lookup statistics
|
|
57
|
+
{
|
|
58
|
+
$lookup: {
|
|
59
|
+
from: 'stat_group',
|
|
60
|
+
localField: 'groupId',
|
|
61
|
+
foreignField: 'groupId',
|
|
62
|
+
as: 'statistics'
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
// Unwind statistics (handle case where no stats exist)
|
|
66
|
+
{
|
|
67
|
+
$unwind: {
|
|
68
|
+
path: '$statistics',
|
|
69
|
+
preserveNullAndEmptyArrays: true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
// Add default statistics if none exist
|
|
73
|
+
{
|
|
74
|
+
$addFields: {
|
|
75
|
+
statistics: {
|
|
76
|
+
$cond: {
|
|
77
|
+
if: { $eq: ['$statistics', null] },
|
|
78
|
+
then: {
|
|
79
|
+
seasonsCount: 0,
|
|
80
|
+
eventsCount: 0,
|
|
81
|
+
matchesCount: 0,
|
|
82
|
+
participantsCount: { $size: '$participants' },
|
|
83
|
+
updatedAt: '$updatedAt'
|
|
84
|
+
},
|
|
85
|
+
else: {
|
|
86
|
+
seasonsCount: '$statistics.seasonsCount',
|
|
87
|
+
eventsCount: '$statistics.eventsCount',
|
|
88
|
+
matchesCount: '$statistics.matchesCount',
|
|
89
|
+
participantsCount: '$statistics.participantsCount',
|
|
90
|
+
updatedAt: '$statistics.updatedAt'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
// Sort
|
|
97
|
+
{ $sort: sortStage },
|
|
98
|
+
// Pagination
|
|
99
|
+
{ $skip: skip },
|
|
100
|
+
{ $limit: limit },
|
|
101
|
+
// Project final result
|
|
102
|
+
{
|
|
103
|
+
$project: {
|
|
104
|
+
groupId: 1,
|
|
105
|
+
groupName: 1,
|
|
106
|
+
updatedAt: 1,
|
|
107
|
+
statistics: 1
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
];
|
|
111
|
+
// Execute aggregation
|
|
112
|
+
const groups = await this.GroupModel.aggregate(pipeline).exec();
|
|
113
|
+
// Get total count for pagination
|
|
114
|
+
const totalCountPipeline = [
|
|
115
|
+
{ $match: matchStage },
|
|
116
|
+
{ $count: 'total' }
|
|
117
|
+
];
|
|
118
|
+
const totalResult = await this.GroupModel.aggregate(totalCountPipeline).exec();
|
|
119
|
+
const totalCount = totalResult[0]?.total || 0;
|
|
120
|
+
return {
|
|
121
|
+
groups: groups.map(g => ({
|
|
122
|
+
groupId: g.groupId,
|
|
123
|
+
groupName: g.groupName,
|
|
124
|
+
updatedAt: g.updatedAt,
|
|
125
|
+
statistics: g.statistics,
|
|
126
|
+
})),
|
|
127
|
+
totalCount,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw new errors_1.QueryError('findPublicGroupsWithStats', 'StatGroup', 'public', error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async upsert(stats) {
|
|
135
|
+
try {
|
|
136
|
+
// Validate input
|
|
137
|
+
if (!stats) {
|
|
138
|
+
throw new errors_1.ValidationError('StatGroup', 'stats', stats, 'stats object is required');
|
|
139
|
+
}
|
|
140
|
+
const groupId = stats.getGroupId();
|
|
141
|
+
if (!groupId || groupId === 0) {
|
|
142
|
+
throw new errors_1.ValidationError('StatGroup', 'groupId', groupId, 'must be a non-zero number');
|
|
143
|
+
}
|
|
144
|
+
const doc = (0, stat_group_mapper_1.toStatGroupDoc)(stats);
|
|
145
|
+
const result = await this.StatGroupModel.findOneAndUpdate({ groupId }, {
|
|
146
|
+
$set: {
|
|
147
|
+
...doc,
|
|
148
|
+
updatedAt: new Date(),
|
|
149
|
+
}
|
|
150
|
+
}, {
|
|
151
|
+
upsert: true,
|
|
152
|
+
new: true,
|
|
153
|
+
setDefaultsOnInsert: true,
|
|
154
|
+
}).lean();
|
|
155
|
+
return (0, stat_group_mapper_1.toStatGroupDomain)(result);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof errors_1.ValidationError) {
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
throw new errors_1.QueryError('upsert', 'StatGroup', stats.getGroupId(), error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.MongoStatGroupRepository = MongoStatGroupRepository;
|