ballrush-core 0.5.3 → 0.5.4

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.
@@ -3,3 +3,4 @@ export * from "./group";
3
3
  export * from "./event";
4
4
  export * from "./event-template";
5
5
  export * from "./stat-group";
6
+ export * from "./season";
@@ -19,3 +19,4 @@ __exportStar(require("./group"), exports);
19
19
  __exportStar(require("./event"), exports);
20
20
  __exportStar(require("./event-template"), exports);
21
21
  __exportStar(require("./stat-group"), exports);
22
+ __exportStar(require("./season"), exports);
@@ -0,0 +1,81 @@
1
+ export type SeasonStatus = 'upcoming' | 'in_progress' | 'ended';
2
+ export declare class Season {
3
+ private seasonId;
4
+ private name;
5
+ private year;
6
+ private startDate;
7
+ private endDate;
8
+ private status;
9
+ private isPublic;
10
+ private description?;
11
+ private groupId?;
12
+ private createdBy?;
13
+ private createdAt?;
14
+ private updatedAt?;
15
+ constructor(seasonId: string, name: string, year: number, startDate: Date, endDate: Date, status: SeasonStatus, isPublic: boolean, description?: string | undefined, groupId?: number | undefined, createdBy?: number | undefined, createdAt?: Date | undefined, updatedAt?: Date | undefined);
16
+ static create(p: {
17
+ seasonId: string;
18
+ name: string;
19
+ year: number;
20
+ startDate: Date;
21
+ endDate: Date;
22
+ status?: SeasonStatus;
23
+ isPublic?: boolean;
24
+ description?: string;
25
+ groupId?: number;
26
+ createdBy?: number;
27
+ createdAt?: Date;
28
+ updatedAt?: Date;
29
+ }): Season;
30
+ /**
31
+ * Вычисляет статус сезона на основе дат
32
+ */
33
+ static calculateStatusFromDates(startDate: Date, endDate: Date, now?: Date): SeasonStatus;
34
+ /**
35
+ * Вычисляет текущий статус на основе дат
36
+ */
37
+ calculateStatus(now?: Date): SeasonStatus;
38
+ /**
39
+ * Обновляет статус в entity на основе текущих дат
40
+ */
41
+ updateStatus(now?: Date): void;
42
+ /**
43
+ * Проверяет, нужно ли обновить статус
44
+ */
45
+ needsStatusUpdate(now?: Date): boolean;
46
+ getSeasonId(): string;
47
+ getName(): string;
48
+ getYear(): number;
49
+ getStartDate(): Date;
50
+ getEndDate(): Date;
51
+ getStatus(): SeasonStatus;
52
+ getIsPublic(): boolean;
53
+ getDescription(): string | undefined;
54
+ getGroupId(): number | undefined;
55
+ getCreatedBy(): number | undefined;
56
+ getCreatedAt(): Date;
57
+ getUpdatedAt(): Date;
58
+ setName(name: string): void;
59
+ setYear(year: number): void;
60
+ setStartDate(startDate: Date): void;
61
+ setEndDate(endDate: Date): void;
62
+ setStatus(status: SeasonStatus): void;
63
+ setIsPublic(isPublic: boolean): void;
64
+ setDescription(description?: string): void;
65
+ setGroupId(groupId?: number): void;
66
+ setCreatedBy(createdBy?: number): void;
67
+ toObject(): {
68
+ seasonId: string;
69
+ name: string;
70
+ year: number;
71
+ startDate: Date;
72
+ endDate: Date;
73
+ status: SeasonStatus;
74
+ isPublic: boolean;
75
+ description: string | undefined;
76
+ groupId: number | undefined;
77
+ createdBy: number | undefined;
78
+ createdAt: Date | undefined;
79
+ updatedAt: Date | undefined;
80
+ };
81
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Season = void 0;
4
+ class Season {
5
+ constructor(seasonId, name, year, startDate, endDate, status, isPublic, description, groupId, createdBy, createdAt, updatedAt) {
6
+ this.seasonId = seasonId;
7
+ this.name = name;
8
+ this.year = year;
9
+ this.startDate = startDate;
10
+ this.endDate = endDate;
11
+ this.status = status;
12
+ this.isPublic = isPublic;
13
+ this.description = description;
14
+ this.groupId = groupId;
15
+ this.createdBy = createdBy;
16
+ this.createdAt = createdAt;
17
+ this.updatedAt = updatedAt;
18
+ }
19
+ static create(p) {
20
+ if (!p.seasonId)
21
+ throw new Error("seasonId is required");
22
+ if (!p.name)
23
+ throw new Error("name is required");
24
+ if (!p.year || p.year < 2000)
25
+ throw new Error("year must be >= 2000");
26
+ if (!p.startDate)
27
+ throw new Error("startDate is required");
28
+ if (!p.endDate)
29
+ throw new Error("endDate is required");
30
+ if (p.startDate >= p.endDate)
31
+ throw new Error("startDate must be before endDate");
32
+ // Если статус не указан, вычисляем автоматически
33
+ const status = p.status ?? Season.calculateStatusFromDates(p.startDate, p.endDate);
34
+ return new Season(p.seasonId, p.name, p.year, p.startDate, p.endDate, status, p.isPublic ?? true, // По умолчанию публичный (системный)
35
+ p.description, p.groupId, p.createdBy, p.createdAt ?? new Date(), p.updatedAt ?? new Date());
36
+ }
37
+ /**
38
+ * Вычисляет статус сезона на основе дат
39
+ */
40
+ static calculateStatusFromDates(startDate, endDate, now = new Date()) {
41
+ if (now < startDate)
42
+ return 'upcoming';
43
+ if (now > endDate)
44
+ return 'ended';
45
+ return 'in_progress';
46
+ }
47
+ /**
48
+ * Вычисляет текущий статус на основе дат
49
+ */
50
+ calculateStatus(now = new Date()) {
51
+ return Season.calculateStatusFromDates(this.startDate, this.endDate, now);
52
+ }
53
+ /**
54
+ * Обновляет статус в entity на основе текущих дат
55
+ */
56
+ updateStatus(now = new Date()) {
57
+ this.status = this.calculateStatus(now);
58
+ this.updatedAt = now;
59
+ }
60
+ /**
61
+ * Проверяет, нужно ли обновить статус
62
+ */
63
+ needsStatusUpdate(now = new Date()) {
64
+ return this.status !== this.calculateStatus(now);
65
+ }
66
+ // ---- GETTERS
67
+ getSeasonId() { return this.seasonId; }
68
+ getName() { return this.name; }
69
+ getYear() { return this.year; }
70
+ getStartDate() { return this.startDate; }
71
+ getEndDate() { return this.endDate; }
72
+ getStatus() { return this.status; }
73
+ getIsPublic() { return this.isPublic; }
74
+ getDescription() { return this.description; }
75
+ getGroupId() { return this.groupId; }
76
+ getCreatedBy() { return this.createdBy; }
77
+ getCreatedAt() { return this.createdAt ?? new Date(); }
78
+ getUpdatedAt() { return this.updatedAt ?? new Date(); }
79
+ // ---- SETTERS
80
+ setName(name) {
81
+ if (!name)
82
+ throw new Error("name cannot be empty");
83
+ this.name = name;
84
+ this.updatedAt = new Date();
85
+ }
86
+ setYear(year) {
87
+ if (year < 2000)
88
+ throw new Error("year must be >= 2000");
89
+ this.year = year;
90
+ this.updatedAt = new Date();
91
+ }
92
+ setStartDate(startDate) {
93
+ if (startDate >= this.endDate)
94
+ throw new Error("startDate must be before endDate");
95
+ this.startDate = startDate;
96
+ this.updatedAt = new Date();
97
+ }
98
+ setEndDate(endDate) {
99
+ if (this.startDate >= endDate)
100
+ throw new Error("startDate must be before endDate");
101
+ this.endDate = endDate;
102
+ this.updatedAt = new Date();
103
+ }
104
+ setStatus(status) {
105
+ this.status = status;
106
+ this.updatedAt = new Date();
107
+ }
108
+ setIsPublic(isPublic) {
109
+ this.isPublic = isPublic;
110
+ this.updatedAt = new Date();
111
+ }
112
+ setDescription(description) {
113
+ this.description = description;
114
+ this.updatedAt = new Date();
115
+ }
116
+ setGroupId(groupId) {
117
+ this.groupId = groupId;
118
+ this.updatedAt = new Date();
119
+ }
120
+ setCreatedBy(createdBy) {
121
+ this.createdBy = createdBy;
122
+ this.updatedAt = new Date();
123
+ }
124
+ toObject() {
125
+ return {
126
+ seasonId: this.seasonId,
127
+ name: this.name,
128
+ year: this.year,
129
+ startDate: this.startDate,
130
+ endDate: this.endDate,
131
+ status: this.status,
132
+ isPublic: this.isPublic,
133
+ description: this.description,
134
+ groupId: this.groupId,
135
+ createdBy: this.createdBy,
136
+ createdAt: this.createdAt,
137
+ updatedAt: this.updatedAt,
138
+ };
139
+ }
140
+ }
141
+ exports.Season = Season;
@@ -10,3 +10,4 @@ export * from "./schemas/stat-group-activity-chart.schema";
10
10
  export * from "./schemas/stat-user-profile.schema";
11
11
  export * from "./schemas/stat-user-match-history.schema";
12
12
  export * from "./schemas/stat-event.schema";
13
+ export * from "./schemas/season.schema";
@@ -26,3 +26,4 @@ __exportStar(require("./schemas/stat-group-activity-chart.schema"), exports);
26
26
  __exportStar(require("./schemas/stat-user-profile.schema"), exports);
27
27
  __exportStar(require("./schemas/stat-user-match-history.schema"), exports);
28
28
  __exportStar(require("./schemas/stat-event.schema"), exports);
29
+ __exportStar(require("./schemas/season.schema"), exports);
@@ -0,0 +1,21 @@
1
+ import { Schema } from "mongoose";
2
+ import { SeasonStatus } from "../../domain/season";
3
+ export interface SeasonDoc {
4
+ seasonId: string;
5
+ name: string;
6
+ year: number;
7
+ startDate: Date;
8
+ endDate: Date;
9
+ status: SeasonStatus;
10
+ isPublic: boolean;
11
+ description?: string;
12
+ groupId?: number;
13
+ createdBy?: number;
14
+ createdAt: Date;
15
+ updatedAt: Date;
16
+ }
17
+ export declare function createSeasonSchema(): Schema<SeasonDoc, import("mongoose").Model<SeasonDoc, any, any, any, import("mongoose").Document<unknown, any, SeasonDoc> & SeasonDoc & {
18
+ _id: import("mongoose").Types.ObjectId;
19
+ }, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, SeasonDoc, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<SeasonDoc>> & import("mongoose").FlatRecord<SeasonDoc> & {
20
+ _id: import("mongoose").Types.ObjectId;
21
+ }>;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSeasonSchema = createSeasonSchema;
4
+ const mongoose_1 = require("mongoose");
5
+ function createSeasonSchema() {
6
+ const schema = new mongoose_1.Schema({
7
+ seasonId: {
8
+ type: String,
9
+ required: true,
10
+ unique: true,
11
+ index: true
12
+ },
13
+ name: {
14
+ type: String,
15
+ required: true
16
+ },
17
+ year: {
18
+ type: Number,
19
+ required: true,
20
+ min: 2000,
21
+ index: true
22
+ },
23
+ startDate: {
24
+ type: Date,
25
+ required: true,
26
+ index: true
27
+ },
28
+ endDate: {
29
+ type: Date,
30
+ required: true,
31
+ index: true
32
+ },
33
+ status: {
34
+ type: String,
35
+ enum: ['upcoming', 'in_progress', 'ended'],
36
+ required: true,
37
+ default: 'upcoming',
38
+ index: true
39
+ },
40
+ isPublic: {
41
+ type: Boolean,
42
+ required: true,
43
+ default: true,
44
+ index: true
45
+ },
46
+ description: {
47
+ type: String,
48
+ required: false
49
+ },
50
+ groupId: {
51
+ type: Number,
52
+ required: false,
53
+ index: true
54
+ },
55
+ createdBy: {
56
+ type: Number,
57
+ required: false
58
+ },
59
+ createdAt: {
60
+ type: Date,
61
+ default: Date.now
62
+ },
63
+ updatedAt: {
64
+ type: Date,
65
+ default: Date.now
66
+ },
67
+ }, {
68
+ timestamps: true, // Автоматически обновляет createdAt и updatedAt
69
+ });
70
+ // Compound indexes для оптимизации запросов
71
+ schema.index({ isPublic: 1, status: 1 }); // Для поиска публичных активных сезонов
72
+ schema.index({ groupId: 1, status: 1 }); // Для поиска сезонов группы
73
+ schema.index({ year: 1, status: 1 }); // Для поиска по году и статусу
74
+ return schema;
75
+ }
@@ -10,3 +10,4 @@ export * from "./stat-group-activity-chart.repository";
10
10
  export * from "./stat-user-profile.repository";
11
11
  export * from "./stat-user-match-history.repository";
12
12
  export * from "./stat-event.repository";
13
+ export * from "./seasons.repository";
@@ -26,3 +26,4 @@ __exportStar(require("./stat-group-activity-chart.repository"), exports);
26
26
  __exportStar(require("./stat-user-profile.repository"), exports);
27
27
  __exportStar(require("./stat-user-match-history.repository"), exports);
28
28
  __exportStar(require("./stat-event.repository"), exports);
29
+ __exportStar(require("./seasons.repository"), exports);
@@ -0,0 +1,51 @@
1
+ import { Season, SeasonStatus } from "../domain/season";
2
+ export interface SeasonsRepository {
3
+ /**
4
+ * Получить сезон по ID
5
+ */
6
+ getById(seasonId: string): Promise<Season | null>;
7
+ /**
8
+ * Получить все публичные (системные) сезоны
9
+ */
10
+ getPublicSeasons(): Promise<Season[]>;
11
+ /**
12
+ * Получить все сезоны группы (включая публичные)
13
+ */
14
+ getByGroupId(groupId: number): Promise<Season[]>;
15
+ /**
16
+ * Получить сезоны по статусу
17
+ */
18
+ getByStatus(status: SeasonStatus, isPublic?: boolean): Promise<Season[]>;
19
+ /**
20
+ * Получить сезоны по году
21
+ */
22
+ getByYear(year: number, isPublic?: boolean): Promise<Season[]>;
23
+ /**
24
+ * Получить все сезоны
25
+ */
26
+ getAll(): Promise<Season[]>;
27
+ /**
28
+ * Создать новый сезон
29
+ */
30
+ createFromDomain(entity: Season): Promise<Season>;
31
+ /**
32
+ * Обновить сезон
33
+ */
34
+ updateFromDomain(entity: Season): Promise<Season | null>;
35
+ /**
36
+ * Удалить сезон
37
+ */
38
+ deleteById(seasonId: string): Promise<void>;
39
+ /**
40
+ * Обновить статусы всех сезонов на основе текущих дат
41
+ */
42
+ updateAllStatuses(now?: Date): Promise<number>;
43
+ /**
44
+ * Получить активные сезоны (in_progress)
45
+ */
46
+ getActiveSeasons(groupId?: number): Promise<Season[]>;
47
+ /**
48
+ * Получить будущие сезоны (upcoming)
49
+ */
50
+ getUpcomingSeasons(groupId?: number): Promise<Season[]>;
51
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -10,3 +10,4 @@ export * from "./mongo/stat-group-activity-chart.repository";
10
10
  export * from "./mongo/stat-user-profile.repository";
11
11
  export * from "./mongo/stat-user-match-history.repository";
12
12
  export * from "./mongo/stat-event.repository";
13
+ export * from "./mongo/season.repository";
@@ -26,3 +26,4 @@ __exportStar(require("./mongo/stat-group-activity-chart.repository"), exports);
26
26
  __exportStar(require("./mongo/stat-user-profile.repository"), exports);
27
27
  __exportStar(require("./mongo/stat-user-match-history.repository"), exports);
28
28
  __exportStar(require("./mongo/stat-event.repository"), exports);
29
+ __exportStar(require("./mongo/season.repository"), exports);
@@ -0,0 +1,4 @@
1
+ import { Season } from "../../domain/season";
2
+ import { SeasonDoc } from "../../mongo";
3
+ export declare function toDomain(doc: SeasonDoc): Season;
4
+ export declare function toDoc(entity: Season): SeasonDoc;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toDomain = toDomain;
4
+ exports.toDoc = toDoc;
5
+ const season_1 = require("../../domain/season");
6
+ function toDomain(doc) {
7
+ return season_1.Season.create({
8
+ seasonId: doc.seasonId,
9
+ name: doc.name,
10
+ year: doc.year,
11
+ startDate: new Date(doc.startDate),
12
+ endDate: new Date(doc.endDate),
13
+ status: doc.status,
14
+ isPublic: doc.isPublic,
15
+ description: doc.description,
16
+ groupId: doc.groupId,
17
+ createdBy: doc.createdBy,
18
+ createdAt: new Date(doc.createdAt),
19
+ updatedAt: new Date(doc.updatedAt),
20
+ });
21
+ }
22
+ function toDoc(entity) {
23
+ return {
24
+ seasonId: entity.getSeasonId(),
25
+ name: entity.getName(),
26
+ year: entity.getYear(),
27
+ startDate: entity.getStartDate(),
28
+ endDate: entity.getEndDate(),
29
+ status: entity.getStatus(),
30
+ isPublic: entity.getIsPublic(),
31
+ description: entity.getDescription(),
32
+ groupId: entity.getGroupId(),
33
+ createdBy: entity.getCreatedBy(),
34
+ createdAt: entity.getCreatedAt(),
35
+ updatedAt: entity.getUpdatedAt(),
36
+ };
37
+ }
@@ -0,0 +1,20 @@
1
+ import type { Model } from "mongoose";
2
+ import type { SeasonDoc } from "../../mongo";
3
+ import type { SeasonsRepository } from "../../ports/seasons.repository";
4
+ import { Season, SeasonStatus } from "../../domain/season";
5
+ export declare class MongoSeasonsRepository implements SeasonsRepository {
6
+ private readonly Model;
7
+ constructor(Model: Model<SeasonDoc>);
8
+ getById(seasonId: string): Promise<Season | null>;
9
+ getPublicSeasons(): Promise<Season[]>;
10
+ getByGroupId(groupId: number): Promise<Season[]>;
11
+ getByStatus(status: SeasonStatus, isPublic?: boolean): Promise<Season[]>;
12
+ getByYear(year: number, isPublic?: boolean): Promise<Season[]>;
13
+ getAll(): Promise<Season[]>;
14
+ createFromDomain(entity: Season): Promise<Season>;
15
+ updateFromDomain(entity: Season): Promise<Season | null>;
16
+ deleteById(seasonId: string): Promise<void>;
17
+ updateAllStatuses(now?: Date): Promise<number>;
18
+ getActiveSeasons(groupId?: number): Promise<Season[]>;
19
+ getUpcomingSeasons(groupId?: number): Promise<Season[]>;
20
+ }
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MongoSeasonsRepository = void 0;
4
+ const season_mapper_1 = require("./season.mapper");
5
+ const errors_1 = require("../../errors");
6
+ class MongoSeasonsRepository {
7
+ constructor(Model) {
8
+ this.Model = Model;
9
+ }
10
+ async getById(seasonId) {
11
+ try {
12
+ if (!seasonId) {
13
+ throw new errors_1.ValidationError('Season', 'seasonId', seasonId, 'must be a non-empty string');
14
+ }
15
+ const doc = await this.Model.findOne({ seasonId }).lean();
16
+ return doc ? (0, season_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', 'Season', seasonId, error);
22
+ }
23
+ }
24
+ async getPublicSeasons() {
25
+ try {
26
+ const docs = await this.Model.find({ isPublic: true }).sort({ year: -1, startDate: -1 }).lean();
27
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
28
+ }
29
+ catch (error) {
30
+ throw new errors_1.QueryError('getPublicSeasons', 'Season', 'public', error);
31
+ }
32
+ }
33
+ async getByGroupId(groupId) {
34
+ try {
35
+ if (!groupId || groupId === 0) {
36
+ throw new errors_1.ValidationError('Season', 'groupId', groupId, 'must be a non-zero number');
37
+ }
38
+ // Возвращаем публичные сезоны + сезоны конкретной группы
39
+ const docs = await this.Model.find({
40
+ $or: [
41
+ { isPublic: true },
42
+ { groupId: groupId }
43
+ ]
44
+ }).sort({ year: -1, startDate: -1 }).lean();
45
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
46
+ }
47
+ catch (error) {
48
+ if (error instanceof errors_1.ValidationError)
49
+ throw error;
50
+ throw new errors_1.QueryError('getByGroupId', 'Season', groupId, error);
51
+ }
52
+ }
53
+ async getByStatus(status, isPublic) {
54
+ try {
55
+ const filter = { status };
56
+ if (isPublic !== undefined) {
57
+ filter.isPublic = isPublic;
58
+ }
59
+ const docs = await this.Model.find(filter).sort({ year: -1, startDate: -1 }).lean();
60
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
61
+ }
62
+ catch (error) {
63
+ throw new errors_1.QueryError('getByStatus', 'Season', status, error);
64
+ }
65
+ }
66
+ async getByYear(year, isPublic) {
67
+ try {
68
+ if (!year || year < 2000) {
69
+ throw new errors_1.ValidationError('Season', 'year', year, 'must be >= 2000');
70
+ }
71
+ const filter = { year };
72
+ if (isPublic !== undefined) {
73
+ filter.isPublic = isPublic;
74
+ }
75
+ const docs = await this.Model.find(filter).sort({ startDate: 1 }).lean();
76
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
77
+ }
78
+ catch (error) {
79
+ if (error instanceof errors_1.ValidationError)
80
+ throw error;
81
+ throw new errors_1.QueryError('getByYear', 'Season', year, error);
82
+ }
83
+ }
84
+ async getAll() {
85
+ try {
86
+ const docs = await this.Model.find().sort({ year: -1, startDate: -1 }).lean();
87
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
88
+ }
89
+ catch (error) {
90
+ throw new errors_1.QueryError('getAll', 'Season', 'all', error);
91
+ }
92
+ }
93
+ async createFromDomain(entity) {
94
+ try {
95
+ if (!entity) {
96
+ throw new errors_1.ValidationError('Season', 'entity', entity, 'entity object is required');
97
+ }
98
+ const seasonId = entity.getSeasonId();
99
+ if (!seasonId) {
100
+ throw new errors_1.ValidationError('Season', 'seasonId', seasonId, 'must be a non-empty string');
101
+ }
102
+ const write = (0, season_mapper_1.toDoc)(entity);
103
+ const saved = await new this.Model(write).save();
104
+ return (0, season_mapper_1.toDomain)(saved.toObject());
105
+ }
106
+ catch (error) {
107
+ if (error instanceof errors_1.ValidationError)
108
+ throw error;
109
+ if (error?.code === 11000) {
110
+ throw new errors_1.DuplicateEntityError('Season', entity.getSeasonId(), error);
111
+ }
112
+ throw new errors_1.QueryError('createFromDomain', 'Season', entity.getSeasonId(), error);
113
+ }
114
+ }
115
+ async updateFromDomain(entity) {
116
+ try {
117
+ if (!entity) {
118
+ throw new errors_1.ValidationError('Season', 'entity', entity, 'entity object is required');
119
+ }
120
+ const seasonId = entity.getSeasonId();
121
+ if (!seasonId) {
122
+ throw new errors_1.ValidationError('Season', 'seasonId', seasonId, 'must be a non-empty string');
123
+ }
124
+ const write = (0, season_mapper_1.toDoc)(entity);
125
+ const updated = await this.Model.findOneAndUpdate({ seasonId }, write, { new: true }).lean();
126
+ return updated ? (0, season_mapper_1.toDomain)(updated) : null;
127
+ }
128
+ catch (error) {
129
+ if (error instanceof errors_1.ValidationError)
130
+ throw error;
131
+ throw new errors_1.QueryError('updateFromDomain', 'Season', entity.getSeasonId(), error);
132
+ }
133
+ }
134
+ async deleteById(seasonId) {
135
+ try {
136
+ if (!seasonId) {
137
+ throw new errors_1.ValidationError('Season', 'seasonId', seasonId, 'must be a non-empty string');
138
+ }
139
+ const result = await this.Model.deleteOne({ seasonId });
140
+ if (result.deletedCount === 0) {
141
+ throw new errors_1.EntityNotFoundError('Season', seasonId, 'delete');
142
+ }
143
+ }
144
+ catch (error) {
145
+ if (error instanceof errors_1.ValidationError || error instanceof errors_1.EntityNotFoundError) {
146
+ throw error;
147
+ }
148
+ throw new errors_1.QueryError('deleteById', 'Season', seasonId, error);
149
+ }
150
+ }
151
+ async updateAllStatuses(now = new Date()) {
152
+ try {
153
+ let updatedCount = 0;
154
+ // Получаем все сезоны
155
+ const docs = await this.Model.find().lean();
156
+ // Обновляем каждый сезон, если статус изменился
157
+ for (const doc of docs) {
158
+ const entity = (0, season_mapper_1.toDomain)(doc);
159
+ const oldStatus = entity.getStatus();
160
+ const newStatus = entity.calculateStatus(now);
161
+ if (oldStatus !== newStatus) {
162
+ entity.setStatus(newStatus);
163
+ await this.updateFromDomain(entity);
164
+ updatedCount++;
165
+ }
166
+ }
167
+ return updatedCount;
168
+ }
169
+ catch (error) {
170
+ throw new errors_1.QueryError('updateAllStatuses', 'Season', 'all', error);
171
+ }
172
+ }
173
+ async getActiveSeasons(groupId) {
174
+ try {
175
+ const filter = { status: 'in_progress' };
176
+ if (groupId !== undefined) {
177
+ if (groupId === 0) {
178
+ throw new errors_1.ValidationError('Season', 'groupId', groupId, 'must be a non-zero number');
179
+ }
180
+ filter.$or = [
181
+ { isPublic: true },
182
+ { groupId: groupId }
183
+ ];
184
+ }
185
+ const docs = await this.Model.find(filter).sort({ year: -1, startDate: -1 }).lean();
186
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
187
+ }
188
+ catch (error) {
189
+ if (error instanceof errors_1.ValidationError)
190
+ throw error;
191
+ throw new errors_1.QueryError('getActiveSeasons', 'Season', groupId || 'all', error);
192
+ }
193
+ }
194
+ async getUpcomingSeasons(groupId) {
195
+ try {
196
+ const filter = { status: 'upcoming' };
197
+ if (groupId !== undefined) {
198
+ if (groupId === 0) {
199
+ throw new errors_1.ValidationError('Season', 'groupId', groupId, 'must be a non-zero number');
200
+ }
201
+ filter.$or = [
202
+ { isPublic: true },
203
+ { groupId: groupId }
204
+ ];
205
+ }
206
+ const docs = await this.Model.find(filter).sort({ startDate: 1 }).lean();
207
+ return docs.map(d => (0, season_mapper_1.toDomain)(d));
208
+ }
209
+ catch (error) {
210
+ if (error instanceof errors_1.ValidationError)
211
+ throw error;
212
+ throw new errors_1.QueryError('getUpcomingSeasons', 'Season', groupId || 'all', error);
213
+ }
214
+ }
215
+ }
216
+ exports.MongoSeasonsRepository = MongoSeasonsRepository;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ballrush-core",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",