volleyballsimtypes 0.0.459 → 0.0.463
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/cjs/src/api/index.d.ts +2 -0
- package/dist/cjs/src/data/init-models.js +13 -0
- package/dist/cjs/src/data/models/index.d.ts +2 -0
- package/dist/cjs/src/data/models/index.js +2 -0
- package/dist/cjs/src/data/models/match-preset.d.ts +28 -0
- package/dist/cjs/src/data/models/match-preset.js +65 -0
- package/dist/cjs/src/data/models/match.d.ts +2 -1
- package/dist/cjs/src/data/models/user-device-token.d.ts +23 -0
- package/dist/cjs/src/data/models/user-device-token.js +65 -0
- package/dist/cjs/src/data/transformers/division.js +1 -1
- package/dist/cjs/src/data/transformers/match-preset-override.test.d.ts +1 -0
- package/dist/cjs/src/data/transformers/match-preset-override.test.js +275 -0
- package/dist/cjs/src/data/transformers/match.d.ts +2 -1
- package/dist/cjs/src/data/transformers/match.js +15 -3
- package/dist/cjs/src/data/transformers/qualifier.js +1 -1
- package/dist/cjs/src/data/transformers/season.js +1 -1
- package/dist/cjs/src/data/transformers/tactics.d.ts +3 -2
- package/dist/cjs/src/data/transformers/tactics.js +36 -0
- package/dist/cjs/src/data/transformers/tactics.test.js +61 -0
- package/dist/cjs/src/data/transformers/team.d.ts +7 -1
- package/dist/cjs/src/data/transformers/team.js +22 -4
- package/dist/cjs/src/data/transformers/tournament.js +1 -1
- package/dist/cjs/src/service/team/schemas/tactics.z.test.js +115 -0
- package/dist/esm/src/api/index.d.ts +2 -0
- package/dist/esm/src/data/init-models.js +14 -1
- package/dist/esm/src/data/models/index.d.ts +2 -0
- package/dist/esm/src/data/models/index.js +2 -0
- package/dist/esm/src/data/models/match-preset.d.ts +28 -0
- package/dist/esm/src/data/models/match-preset.js +61 -0
- package/dist/esm/src/data/models/match.d.ts +2 -1
- package/dist/esm/src/data/models/user-device-token.d.ts +23 -0
- package/dist/esm/src/data/models/user-device-token.js +61 -0
- package/dist/esm/src/data/transformers/division.js +1 -1
- package/dist/esm/src/data/transformers/match-preset-override.test.d.ts +1 -0
- package/dist/esm/src/data/transformers/match-preset-override.test.js +273 -0
- package/dist/esm/src/data/transformers/match.d.ts +2 -1
- package/dist/esm/src/data/transformers/match.js +15 -3
- package/dist/esm/src/data/transformers/qualifier.js +1 -1
- package/dist/esm/src/data/transformers/season.js +1 -1
- package/dist/esm/src/data/transformers/tactics.d.ts +3 -2
- package/dist/esm/src/data/transformers/tactics.js +36 -1
- package/dist/esm/src/data/transformers/tactics.test.js +63 -2
- package/dist/esm/src/data/transformers/team.d.ts +7 -1
- package/dist/esm/src/data/transformers/team.js +20 -5
- package/dist/esm/src/data/transformers/tournament.js +1 -1
- package/dist/esm/src/service/team/schemas/tactics.z.test.js +115 -0
- package/package.json +1 -1
|
@@ -49,6 +49,7 @@ export type Match = Omit<DataProps<_Match>, 'sets' | 'homeTeam' | 'awayTeam' | '
|
|
|
49
49
|
awayForm?: MatchForm[];
|
|
50
50
|
isFriendly?: boolean;
|
|
51
51
|
detailUnavailable?: boolean;
|
|
52
|
+
selectedPresetId?: string;
|
|
52
53
|
};
|
|
53
54
|
export type RallyEvent = DataProps<_RallyEvent> & {
|
|
54
55
|
teamId?: string;
|
|
@@ -128,6 +129,7 @@ export interface ApiLineupPreset {
|
|
|
128
129
|
orderIndex: number;
|
|
129
130
|
config: Tactics;
|
|
130
131
|
}
|
|
132
|
+
export type ApiLineupPresetSummary = Omit<ApiLineupPreset, 'config'>;
|
|
131
133
|
export type Team = Omit<DataProps<_Team>, 'roster' | '_rating' | 'rating' | 'tactics'> & {
|
|
132
134
|
roster: Player[];
|
|
133
135
|
rating: {
|
|
@@ -8,6 +8,7 @@ function initModels(sequelize) {
|
|
|
8
8
|
const CurrencyTransaction = models_1.CurrencyTransactionModel.initModel(sequelize);
|
|
9
9
|
const Tactics = models_1.TacticsModel.initModel(sequelize);
|
|
10
10
|
const LineupPreset = models_1.LineupPresetModel.initModel(sequelize);
|
|
11
|
+
const MatchPreset = models_1.MatchPresetModel.initModel(sequelize);
|
|
11
12
|
const AuthUser = models_1.AuthUserModel.initModel(sequelize);
|
|
12
13
|
const UserCurrency = models_1.UserCurrencyModel.initModel(sequelize);
|
|
13
14
|
const UserPlayerProgress = models_1.UserPlayerProgressModel.initModel(sequelize);
|
|
@@ -16,6 +17,7 @@ function initModels(sequelize) {
|
|
|
16
17
|
const UserPullGrant = models_1.UserPullGrantModel.initModel(sequelize);
|
|
17
18
|
const Wishlist = models_1.WishlistModel.initModel(sequelize);
|
|
18
19
|
const UserSettings = models_1.UserSettingsModel.initModel(sequelize);
|
|
20
|
+
const UserDeviceToken = models_1.UserDeviceTokenModel.initModel(sequelize);
|
|
19
21
|
const Notification = models_1.NotificationModel.initModel(sequelize);
|
|
20
22
|
const AuthIdentity = models_1.AuthIdentityModel.initModel(sequelize);
|
|
21
23
|
const AuthSession = models_1.AuthSessionModel.initModel(sequelize);
|
|
@@ -63,7 +65,9 @@ function initModels(sequelize) {
|
|
|
63
65
|
AuthUser.hasOne(GachaPity, { as: 'GachaPity', foreignKey: 'user_id' });
|
|
64
66
|
AuthUser.hasOne(Wishlist, { as: 'Wishlist', foreignKey: 'user_id' });
|
|
65
67
|
AuthUser.hasOne(UserSettings, { as: 'UserSettings', foreignKey: 'user_id' });
|
|
68
|
+
AuthUser.hasMany(UserDeviceToken, { as: 'UserDeviceTokens', foreignKey: 'user_id' });
|
|
66
69
|
AuthUser.hasMany(Notification, { as: 'Notifications', foreignKey: 'user_id' });
|
|
70
|
+
UserDeviceToken.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
67
71
|
Notification.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
68
72
|
AuthUser.hasMany(GachaPullHistory, { as: 'GachaPullHistory', foreignKey: 'user_id' });
|
|
69
73
|
AuthUser.hasMany(UserPullGrant, { as: 'UserPullGrants', foreignKey: 'user_id' });
|
|
@@ -212,6 +216,13 @@ function initModels(sequelize) {
|
|
|
212
216
|
// simulator's team loads are unchanged (it reads the active config from the mirrored Tactics row).
|
|
213
217
|
Team.hasMany(LineupPreset, { as: 'lineupPresets', foreignKey: 'team_id' });
|
|
214
218
|
LineupPreset.belongsTo(Team, { as: 'team', foreignKey: 'team_id' });
|
|
219
|
+
// Per-match preset choices. Deliberately NOT part of any default scope: only the simulator's match query
|
|
220
|
+
// loads MatchPresets, so every other transformToMatch caller stays on the active-tactics path.
|
|
221
|
+
Match.hasMany(MatchPreset, { as: 'MatchPresets', foreignKey: 'match_id' });
|
|
222
|
+
MatchPreset.belongsTo(Match, { as: 'match', foreignKey: 'match_id' });
|
|
223
|
+
MatchPreset.belongsTo(Team, { as: 'team', foreignKey: 'team_id' });
|
|
224
|
+
MatchPreset.belongsTo(LineupPreset, { as: 'preset', foreignKey: 'preset_id' });
|
|
225
|
+
LineupPreset.hasMany(MatchPreset, { as: 'MatchPresets', foreignKey: 'preset_id' });
|
|
215
226
|
Team.belongsTo(Country, { as: 'country', foreignKey: 'country_id' });
|
|
216
227
|
Team.belongsToMany(Competition, {
|
|
217
228
|
as: 'Competitions',
|
|
@@ -286,6 +297,7 @@ function initModels(sequelize) {
|
|
|
286
297
|
TeamReplacement,
|
|
287
298
|
Tactics,
|
|
288
299
|
LineupPreset,
|
|
300
|
+
MatchPreset,
|
|
289
301
|
UserTeam,
|
|
290
302
|
UserCurrency,
|
|
291
303
|
UserPlayerProgress,
|
|
@@ -294,6 +306,7 @@ function initModels(sequelize) {
|
|
|
294
306
|
UserPullGrant,
|
|
295
307
|
Wishlist,
|
|
296
308
|
UserSettings,
|
|
309
|
+
UserDeviceToken,
|
|
297
310
|
Notification,
|
|
298
311
|
Coach,
|
|
299
312
|
Scout,
|
|
@@ -36,6 +36,7 @@ export * from './team';
|
|
|
36
36
|
export * from './team-replacement';
|
|
37
37
|
export * from './tactics';
|
|
38
38
|
export * from './lineup-preset';
|
|
39
|
+
export * from './match-preset';
|
|
39
40
|
export * from './user-currency';
|
|
40
41
|
export * from './user-player-progress';
|
|
41
42
|
export * from './gacha-pity';
|
|
@@ -44,6 +45,7 @@ export * from './wishlist';
|
|
|
44
45
|
export * from './currency-transaction';
|
|
45
46
|
export * from './user-pull-grant';
|
|
46
47
|
export * from './user-settings';
|
|
48
|
+
export * from './user-device-token';
|
|
47
49
|
export * from './notification';
|
|
48
50
|
export * from './vper';
|
|
49
51
|
export * from './views';
|
|
@@ -52,6 +52,7 @@ __exportStar(require("./team"), exports);
|
|
|
52
52
|
__exportStar(require("./team-replacement"), exports);
|
|
53
53
|
__exportStar(require("./tactics"), exports);
|
|
54
54
|
__exportStar(require("./lineup-preset"), exports);
|
|
55
|
+
__exportStar(require("./match-preset"), exports);
|
|
55
56
|
__exportStar(require("./user-currency"), exports);
|
|
56
57
|
__exportStar(require("./user-player-progress"), exports);
|
|
57
58
|
__exportStar(require("./gacha-pity"), exports);
|
|
@@ -60,6 +61,7 @@ __exportStar(require("./wishlist"), exports);
|
|
|
60
61
|
__exportStar(require("./currency-transaction"), exports);
|
|
61
62
|
__exportStar(require("./user-pull-grant"), exports);
|
|
62
63
|
__exportStar(require("./user-settings"), exports);
|
|
64
|
+
__exportStar(require("./user-device-token"), exports);
|
|
63
65
|
__exportStar(require("./notification"), exports);
|
|
64
66
|
__exportStar(require("./vper"), exports);
|
|
65
67
|
__exportStar(require("./views"), exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Sequelize from 'sequelize';
|
|
2
|
+
import { Model } from 'sequelize';
|
|
3
|
+
import { LineupPresetId, LineupPresetModel, MatchId, MatchModel, TeamId, TeamModel } from '.';
|
|
4
|
+
export interface MatchPresetAttributes {
|
|
5
|
+
match_id: string;
|
|
6
|
+
team_id: string;
|
|
7
|
+
preset_id: string;
|
|
8
|
+
}
|
|
9
|
+
export type MatchPresetPk = 'match_id' | 'team_id';
|
|
10
|
+
export type MatchPresetCreationAttributes = MatchPresetAttributes;
|
|
11
|
+
export declare class MatchPresetModel extends Model<MatchPresetAttributes, MatchPresetCreationAttributes> implements MatchPresetAttributes {
|
|
12
|
+
match_id: string;
|
|
13
|
+
team_id: string;
|
|
14
|
+
preset_id: string;
|
|
15
|
+
match: MatchModel;
|
|
16
|
+
getMatch: Sequelize.BelongsToGetAssociationMixin<MatchModel>;
|
|
17
|
+
setMatch: Sequelize.BelongsToSetAssociationMixin<MatchModel, MatchId>;
|
|
18
|
+
createMatch: Sequelize.BelongsToCreateAssociationMixin<MatchModel>;
|
|
19
|
+
team: TeamModel;
|
|
20
|
+
getTeam: Sequelize.BelongsToGetAssociationMixin<TeamModel>;
|
|
21
|
+
setTeam: Sequelize.BelongsToSetAssociationMixin<TeamModel, TeamId>;
|
|
22
|
+
createTeam: Sequelize.BelongsToCreateAssociationMixin<TeamModel>;
|
|
23
|
+
preset: LineupPresetModel;
|
|
24
|
+
getPreset: Sequelize.BelongsToGetAssociationMixin<LineupPresetModel>;
|
|
25
|
+
setPreset: Sequelize.BelongsToSetAssociationMixin<LineupPresetModel, LineupPresetId>;
|
|
26
|
+
createPreset: Sequelize.BelongsToCreateAssociationMixin<LineupPresetModel>;
|
|
27
|
+
static initModel(sequelize: Sequelize.Sequelize): typeof MatchPresetModel;
|
|
28
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MatchPresetModel = void 0;
|
|
4
|
+
const sequelize_1 = require("sequelize");
|
|
5
|
+
class MatchPresetModel extends sequelize_1.Model {
|
|
6
|
+
static initModel(sequelize) {
|
|
7
|
+
return MatchPresetModel.init({
|
|
8
|
+
match_id: {
|
|
9
|
+
type: sequelize_1.DataTypes.UUID,
|
|
10
|
+
allowNull: false,
|
|
11
|
+
primaryKey: true,
|
|
12
|
+
references: {
|
|
13
|
+
model: 'Match',
|
|
14
|
+
key: 'match_id'
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
team_id: {
|
|
18
|
+
type: sequelize_1.DataTypes.UUID,
|
|
19
|
+
allowNull: false,
|
|
20
|
+
primaryKey: true,
|
|
21
|
+
references: {
|
|
22
|
+
model: 'Team',
|
|
23
|
+
key: 'team_id'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
preset_id: {
|
|
27
|
+
type: sequelize_1.DataTypes.UUID,
|
|
28
|
+
allowNull: false,
|
|
29
|
+
references: {
|
|
30
|
+
model: 'LineupPreset',
|
|
31
|
+
key: 'preset_id'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}, {
|
|
35
|
+
sequelize,
|
|
36
|
+
tableName: 'MatchPreset',
|
|
37
|
+
schema: 'public',
|
|
38
|
+
timestamps: false,
|
|
39
|
+
indexes: [
|
|
40
|
+
{
|
|
41
|
+
name: 'MatchPreset_pk',
|
|
42
|
+
unique: true,
|
|
43
|
+
fields: [
|
|
44
|
+
{ name: 'match_id' },
|
|
45
|
+
{ name: 'team_id' }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'MatchPreset_team_id_idx',
|
|
50
|
+
fields: [
|
|
51
|
+
{ name: 'team_id' }
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
// Keeps the LineupPreset ON DELETE CASCADE cheap.
|
|
56
|
+
name: 'MatchPreset_preset_id_idx',
|
|
57
|
+
fields: [
|
|
58
|
+
{ name: 'preset_id' }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.MatchPresetModel = MatchPresetModel;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Sequelize from 'sequelize';
|
|
2
2
|
import { Model } from 'sequelize';
|
|
3
3
|
import { Status } from '../common';
|
|
4
|
-
import { CompetitionMatchId, CompetitionMatchModel, MatchRatingId, MatchRatingModel, MatchResultId, MatchResultModel, MatchSetAttributes, MatchSetId, MatchSetModel, VPERAttributes, VPERId, VPERModel, TeamId, TeamModel } from '.';
|
|
4
|
+
import { CompetitionMatchId, CompetitionMatchModel, MatchRatingId, MatchRatingModel, MatchResultId, MatchResultModel, MatchPresetModel, MatchSetAttributes, MatchSetId, MatchSetModel, VPERAttributes, VPERId, VPERModel, TeamId, TeamModel } from '.';
|
|
5
5
|
import { MatchRallyAggregates } from '../../service';
|
|
6
6
|
export interface MatchAttributes {
|
|
7
7
|
match_id: string;
|
|
@@ -59,6 +59,7 @@ export declare class MatchModel extends Model<MatchAttributes, MatchCreationAttr
|
|
|
59
59
|
hasVPER: Sequelize.HasManyHasAssociationMixin<VPERModel, VPERId>;
|
|
60
60
|
hasVPERs: Sequelize.HasManyHasAssociationsMixin<VPERModel, VPERId>;
|
|
61
61
|
countVPERs: Sequelize.HasManyCountAssociationsMixin;
|
|
62
|
+
MatchPresets?: MatchPresetModel[];
|
|
62
63
|
MatchSets: MatchSetModel[];
|
|
63
64
|
getMatchSets: Sequelize.HasManyGetAssociationsMixin<MatchSetModel>;
|
|
64
65
|
setMatchSets: Sequelize.HasManySetAssociationsMixin<MatchSetModel, MatchSetId>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as Sequelize from 'sequelize';
|
|
2
|
+
import { Model, Optional } from 'sequelize';
|
|
3
|
+
export interface UserDeviceTokenAttributes {
|
|
4
|
+
user_device_token_id: string;
|
|
5
|
+
user_id: string;
|
|
6
|
+
device_token: string;
|
|
7
|
+
platform: string;
|
|
8
|
+
created_at?: Date;
|
|
9
|
+
updated_at?: Date;
|
|
10
|
+
}
|
|
11
|
+
export type UserDeviceTokenPk = 'user_device_token_id';
|
|
12
|
+
export type UserDeviceTokenId = UserDeviceTokenModel[UserDeviceTokenPk];
|
|
13
|
+
export type UserDeviceTokenOptionalAttributes = 'user_device_token_id' | 'platform' | 'created_at' | 'updated_at';
|
|
14
|
+
export type UserDeviceTokenCreationAttributes = Optional<UserDeviceTokenAttributes, UserDeviceTokenOptionalAttributes>;
|
|
15
|
+
export declare class UserDeviceTokenModel extends Model<UserDeviceTokenAttributes, UserDeviceTokenCreationAttributes> implements UserDeviceTokenAttributes {
|
|
16
|
+
user_device_token_id: string;
|
|
17
|
+
user_id: string;
|
|
18
|
+
device_token: string;
|
|
19
|
+
platform: string;
|
|
20
|
+
created_at?: Date;
|
|
21
|
+
updated_at?: Date;
|
|
22
|
+
static initModel(sequelize: Sequelize.Sequelize): typeof UserDeviceTokenModel;
|
|
23
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UserDeviceTokenModel = void 0;
|
|
4
|
+
const sequelize_1 = require("sequelize");
|
|
5
|
+
class UserDeviceTokenModel extends sequelize_1.Model {
|
|
6
|
+
static initModel(sequelize) {
|
|
7
|
+
return UserDeviceTokenModel.init({
|
|
8
|
+
user_device_token_id: {
|
|
9
|
+
type: sequelize_1.DataTypes.UUID,
|
|
10
|
+
allowNull: false,
|
|
11
|
+
primaryKey: true,
|
|
12
|
+
defaultValue: sequelize_1.DataTypes.UUIDV4
|
|
13
|
+
},
|
|
14
|
+
user_id: {
|
|
15
|
+
type: sequelize_1.DataTypes.UUID,
|
|
16
|
+
allowNull: false,
|
|
17
|
+
references: {
|
|
18
|
+
model: 'AuthUser',
|
|
19
|
+
key: 'user_id'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
device_token: {
|
|
23
|
+
type: sequelize_1.DataTypes.TEXT,
|
|
24
|
+
allowNull: false
|
|
25
|
+
},
|
|
26
|
+
platform: {
|
|
27
|
+
type: sequelize_1.DataTypes.TEXT,
|
|
28
|
+
allowNull: false,
|
|
29
|
+
defaultValue: 'android'
|
|
30
|
+
},
|
|
31
|
+
created_at: {
|
|
32
|
+
type: sequelize_1.DataTypes.DATE,
|
|
33
|
+
allowNull: false,
|
|
34
|
+
defaultValue: sequelize_1.DataTypes.NOW
|
|
35
|
+
},
|
|
36
|
+
updated_at: {
|
|
37
|
+
type: sequelize_1.DataTypes.DATE,
|
|
38
|
+
allowNull: false,
|
|
39
|
+
defaultValue: sequelize_1.DataTypes.NOW
|
|
40
|
+
}
|
|
41
|
+
}, {
|
|
42
|
+
sequelize,
|
|
43
|
+
tableName: 'UserDeviceToken',
|
|
44
|
+
schema: 'public',
|
|
45
|
+
timestamps: false,
|
|
46
|
+
indexes: [
|
|
47
|
+
{
|
|
48
|
+
name: 'UserDeviceToken_pk',
|
|
49
|
+
unique: true,
|
|
50
|
+
fields: [{ name: 'user_device_token_id' }]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'UserDeviceToken_user_id_device_token_uq',
|
|
54
|
+
unique: true,
|
|
55
|
+
fields: [{ name: 'user_id' }, { name: 'device_token' }]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'UserDeviceToken_user_id_idx',
|
|
59
|
+
fields: [{ name: 'user_id' }]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.UserDeviceTokenModel = UserDeviceTokenModel;
|
|
@@ -27,6 +27,6 @@ function transformToObject(model) {
|
|
|
27
27
|
subdivision: model.subdivision,
|
|
28
28
|
leagueId: model.league_id,
|
|
29
29
|
seasons: (model.DivisionSeasons ?? []).map((ds) => (0, season_1.transformToSeason)(ds.competition)),
|
|
30
|
-
teams: model.Teams != null ? model.Teams.map(team_1.transformToTeam) : undefined
|
|
30
|
+
teams: model.Teams != null ? model.Teams.map(team => (0, team_1.transformToTeam)(team)) : undefined
|
|
31
31
|
});
|
|
32
32
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const tactics_1 = require("./tactics");
|
|
6
|
+
const team_1 = require("./team");
|
|
7
|
+
const match_1 = require("./match");
|
|
8
|
+
const service_1 = require("../../service");
|
|
9
|
+
// ─── shared mocks (model-shaped plain objects, cast through unknown) ──────────
|
|
10
|
+
const countryFixture = {
|
|
11
|
+
country_id: (0, uuid_1.v4)(),
|
|
12
|
+
name: 'Test Country',
|
|
13
|
+
alpha_2: 'TC',
|
|
14
|
+
alpha_3: 'TCN',
|
|
15
|
+
country_code: '999',
|
|
16
|
+
iso_3166_2: 'TC-TEST',
|
|
17
|
+
region: '',
|
|
18
|
+
region_code: '',
|
|
19
|
+
sub_region: '',
|
|
20
|
+
sub_region_code: '',
|
|
21
|
+
intermediate_region: '',
|
|
22
|
+
intermediate_region_code: ''
|
|
23
|
+
};
|
|
24
|
+
function makePlayerModel(id) {
|
|
25
|
+
const stat = 50;
|
|
26
|
+
return {
|
|
27
|
+
player_id: id,
|
|
28
|
+
first_name: 'Test',
|
|
29
|
+
last_name: `P-${id.slice(0, 4)}`,
|
|
30
|
+
rarity: service_1.RarityEnum.COMMON,
|
|
31
|
+
roles: [service_1.RoleEnum.OUTSIDE_HITTER],
|
|
32
|
+
traits: [],
|
|
33
|
+
birth_age: 18,
|
|
34
|
+
birth_iteration: 1,
|
|
35
|
+
last_declined_iteration: null,
|
|
36
|
+
decline_profile: service_1.DeclineProfileEnum.STANDARD,
|
|
37
|
+
BoxScores: [],
|
|
38
|
+
BoxScoreTotals: null,
|
|
39
|
+
country: countryFixture,
|
|
40
|
+
PerformanceStat: {
|
|
41
|
+
setting: stat,
|
|
42
|
+
serve: stat,
|
|
43
|
+
spike: stat,
|
|
44
|
+
quick: stat,
|
|
45
|
+
power: stat,
|
|
46
|
+
awareness: stat,
|
|
47
|
+
attack: stat,
|
|
48
|
+
back_attack: stat,
|
|
49
|
+
reception: stat,
|
|
50
|
+
overhand: stat,
|
|
51
|
+
bump: stat,
|
|
52
|
+
block: stat,
|
|
53
|
+
read: stat,
|
|
54
|
+
commit: stat,
|
|
55
|
+
focus: stat,
|
|
56
|
+
defense: stat,
|
|
57
|
+
stamina: stat,
|
|
58
|
+
reflex: stat
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Six starters; index order is the row lineup's zone 1..6 order.
|
|
63
|
+
const ids = Array.from({ length: 6 }, () => (0, uuid_1.v4)());
|
|
64
|
+
const teamId = (0, uuid_1.v4)();
|
|
65
|
+
function rowLineup(order) {
|
|
66
|
+
return {
|
|
67
|
+
[service_1.CourtPosition.RIGHT_BACK]: order[0],
|
|
68
|
+
[service_1.CourtPosition.RIGHT_FRONT]: order[1],
|
|
69
|
+
[service_1.CourtPosition.MIDDLE_FRONT]: order[2],
|
|
70
|
+
[service_1.CourtPosition.LEFT_FRONT]: order[3],
|
|
71
|
+
[service_1.CourtPosition.LEFT_BACK]: order[4],
|
|
72
|
+
[service_1.CourtPosition.MIDDLE_BACK]: order[5],
|
|
73
|
+
bench: []
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function makeTacticsRow(order) {
|
|
77
|
+
return {
|
|
78
|
+
team_id: teamId,
|
|
79
|
+
lineup: rowLineup(order),
|
|
80
|
+
libero_replacements: [],
|
|
81
|
+
receive_rotation_offset: false,
|
|
82
|
+
designated_subs: [],
|
|
83
|
+
substitution_band: 'TIRED',
|
|
84
|
+
rotation_system: '6-0',
|
|
85
|
+
designated_setters: [],
|
|
86
|
+
offensive_preferences: []
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function makeTeamModel(activeOrder) {
|
|
90
|
+
return {
|
|
91
|
+
team_id: teamId,
|
|
92
|
+
name: 'Test Team',
|
|
93
|
+
short_name: 'TST',
|
|
94
|
+
rating: 0,
|
|
95
|
+
division_id: (0, uuid_1.v4)(),
|
|
96
|
+
active: true,
|
|
97
|
+
country: countryFixture,
|
|
98
|
+
tactics: makeTacticsRow(activeOrder),
|
|
99
|
+
PlayerTeams: ids.map(id => ({ player: makePlayerModel(id) }))
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// The API-DTO config for a preset whose starters are the REVERSE of the active order, so an applied
|
|
103
|
+
// override is visible through the hydrated lineup.
|
|
104
|
+
function makeConfig(order) {
|
|
105
|
+
return {
|
|
106
|
+
lineup: {
|
|
107
|
+
[service_1.CourtPosition.RIGHT_BACK]: order[0],
|
|
108
|
+
[service_1.CourtPosition.RIGHT_FRONT]: order[1],
|
|
109
|
+
[service_1.CourtPosition.MIDDLE_FRONT]: order[2],
|
|
110
|
+
[service_1.CourtPosition.LEFT_FRONT]: order[3],
|
|
111
|
+
[service_1.CourtPosition.LEFT_BACK]: order[4],
|
|
112
|
+
[service_1.CourtPosition.MIDDLE_BACK]: order[5],
|
|
113
|
+
bench: []
|
|
114
|
+
},
|
|
115
|
+
liberoReplacements: [],
|
|
116
|
+
receiveRotationOffset: false,
|
|
117
|
+
designatedSubs: [],
|
|
118
|
+
substitutionBand: 'TIRED',
|
|
119
|
+
rotationSystem: '6-0',
|
|
120
|
+
designatedSetters: [],
|
|
121
|
+
offensivePreferences: []
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const activeOrder = ids;
|
|
125
|
+
const presetOrder = [...ids].reverse();
|
|
126
|
+
function starterAt(tactics, zone) {
|
|
127
|
+
return tactics.lineup[zone]?.id;
|
|
128
|
+
}
|
|
129
|
+
// ─── apiTacticsConfigToTacticsAttributes ──────────────────────────────────────
|
|
130
|
+
(0, globals_1.describe)('apiTacticsConfigToTacticsAttributes()', () => {
|
|
131
|
+
(0, globals_1.it)('round-trips a fully-loaded Tactics row through tacticsColumnsToApiDto', () => {
|
|
132
|
+
const full = {
|
|
133
|
+
team_id: teamId,
|
|
134
|
+
lineup: { ...rowLineup(activeOrder), [service_1.CourtPosition.LIBERO_ZONE]: undefined },
|
|
135
|
+
libero_replacements: [ids[5]],
|
|
136
|
+
receive_rotation_offset: true,
|
|
137
|
+
designated_subs: [{ starterId: ids[0], benchId: undefined, mode: 'FATIGUE', fatigueBand: 'WORN', sets: [{ mode: 'NEVER' }] }],
|
|
138
|
+
substitution_band: 'TIRED',
|
|
139
|
+
second_libero: undefined,
|
|
140
|
+
libero_sub: undefined,
|
|
141
|
+
libero_replacement_sets: [[ids[0]], [ids[1]]],
|
|
142
|
+
rotation_system: '5-1',
|
|
143
|
+
designated_setters: [ids[0]],
|
|
144
|
+
offensive_preferences: [{ rotation: 1, order: [ids[1], ids[2]] }],
|
|
145
|
+
system_sets: [{ rotationSystem: '5-1', designatedSetters: [ids[0]] }],
|
|
146
|
+
offensive_preference_sets: [[{ rotation: 2, order: [ids[3]] }]]
|
|
147
|
+
};
|
|
148
|
+
const dto = (0, tactics_1.tacticsColumnsToApiDto)(full);
|
|
149
|
+
const back = (0, tactics_1.apiTacticsConfigToTacticsAttributes)(dto, teamId);
|
|
150
|
+
(0, globals_1.expect)(back.lineup).toEqual(full.lineup);
|
|
151
|
+
(0, globals_1.expect)(back.libero_replacements).toEqual(full.libero_replacements);
|
|
152
|
+
(0, globals_1.expect)(back.receive_rotation_offset).toBe(true);
|
|
153
|
+
(0, globals_1.expect)(back.designated_subs).toEqual(full.designated_subs);
|
|
154
|
+
(0, globals_1.expect)(back.libero_replacement_sets).toEqual(full.libero_replacement_sets);
|
|
155
|
+
(0, globals_1.expect)(back.rotation_system).toBe('5-1');
|
|
156
|
+
(0, globals_1.expect)(back.designated_setters).toEqual(full.designated_setters);
|
|
157
|
+
(0, globals_1.expect)(back.offensive_preferences).toEqual(full.offensive_preferences);
|
|
158
|
+
(0, globals_1.expect)(back.system_sets).toEqual(full.system_sets);
|
|
159
|
+
(0, globals_1.expect)(back.offensive_preference_sets).toEqual(full.offensive_preference_sets);
|
|
160
|
+
});
|
|
161
|
+
(0, globals_1.it)('hydrates through transformToTactics identically to the row path', () => {
|
|
162
|
+
const roster = ids.map(id => (0, team_1.transformToTeam)(makeTeamModel(activeOrder)).roster.find(p => p.id === id));
|
|
163
|
+
(0, globals_1.expect)(roster.every(p => p != null)).toBe(true);
|
|
164
|
+
const teamModel = makeTeamModel(activeOrder);
|
|
165
|
+
const players = (0, team_1.transformToTeam)(teamModel).roster;
|
|
166
|
+
const fromRow = (0, tactics_1.transformToTactics)(makeTacticsRow(activeOrder), players);
|
|
167
|
+
const fromConfig = (0, tactics_1.transformToTactics)((0, tactics_1.apiTacticsConfigToTacticsAttributes)(makeConfig(activeOrder), teamId), players);
|
|
168
|
+
for (const zone of [1, 2, 3, 4, 5, 6]) {
|
|
169
|
+
(0, globals_1.expect)(starterAt(fromConfig, zone)).toBe(starterAt(fromRow, zone));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
(0, globals_1.it)('throws PLAYER_NOT_FOUND when the config references an off-roster player', () => {
|
|
173
|
+
const players = (0, team_1.transformToTeam)(makeTeamModel(activeOrder)).roster;
|
|
174
|
+
const drifted = makeConfig([(0, uuid_1.v4)(), ...ids.slice(1)]);
|
|
175
|
+
(0, globals_1.expect)(() => (0, tactics_1.transformToTactics)((0, tactics_1.apiTacticsConfigToTacticsAttributes)(drifted, teamId), players)).toThrow('PLAYER_NOT_FOUND');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
// ─── transformToTeam override / fallback ──────────────────────────────────────
|
|
179
|
+
(0, globals_1.describe)('transformToTeam() tacticsOverride', () => {
|
|
180
|
+
(0, globals_1.it)('uses the override config when it hydrates', () => {
|
|
181
|
+
const team = (0, team_1.transformToTeam)(makeTeamModel(activeOrder), undefined, {
|
|
182
|
+
presetId: 'preset-1',
|
|
183
|
+
config: makeConfig(presetOrder)
|
|
184
|
+
});
|
|
185
|
+
(0, globals_1.expect)(starterAt(team.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(presetOrder[0]);
|
|
186
|
+
});
|
|
187
|
+
(0, globals_1.it)('falls back to the active tactics and notifies onFallback when the override fails', () => {
|
|
188
|
+
const onFallback = globals_1.jest.fn();
|
|
189
|
+
const drifted = makeConfig([(0, uuid_1.v4)(), ...ids.slice(1)]);
|
|
190
|
+
const team = (0, team_1.transformToTeam)(makeTeamModel(activeOrder), undefined, {
|
|
191
|
+
presetId: 'preset-1',
|
|
192
|
+
config: drifted,
|
|
193
|
+
onFallback
|
|
194
|
+
});
|
|
195
|
+
(0, globals_1.expect)(onFallback).toHaveBeenCalledTimes(1);
|
|
196
|
+
(0, globals_1.expect)(onFallback.mock.calls[0][0]).toBe('preset-1');
|
|
197
|
+
(0, globals_1.expect)(starterAt(team.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(activeOrder[0]);
|
|
198
|
+
});
|
|
199
|
+
(0, globals_1.it)('keeps the active tactics when no override is given', () => {
|
|
200
|
+
const team = (0, team_1.transformToTeam)(makeTeamModel(activeOrder));
|
|
201
|
+
(0, globals_1.expect)(starterAt(team.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(activeOrder[0]);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
// ─── transformToMatch per-team override ───────────────────────────────────────
|
|
205
|
+
(0, globals_1.describe)('transformToMatch() MatchPresets', () => {
|
|
206
|
+
const awayIds = Array.from({ length: 6 }, () => (0, uuid_1.v4)());
|
|
207
|
+
const awayTeamId = (0, uuid_1.v4)();
|
|
208
|
+
function makeAwayModel() {
|
|
209
|
+
return {
|
|
210
|
+
team_id: awayTeamId,
|
|
211
|
+
name: 'Away Team',
|
|
212
|
+
short_name: 'AWY',
|
|
213
|
+
rating: 0,
|
|
214
|
+
division_id: (0, uuid_1.v4)(),
|
|
215
|
+
active: true,
|
|
216
|
+
country: countryFixture,
|
|
217
|
+
tactics: {
|
|
218
|
+
team_id: awayTeamId,
|
|
219
|
+
lineup: {
|
|
220
|
+
[service_1.CourtPosition.RIGHT_BACK]: awayIds[0],
|
|
221
|
+
[service_1.CourtPosition.RIGHT_FRONT]: awayIds[1],
|
|
222
|
+
[service_1.CourtPosition.MIDDLE_FRONT]: awayIds[2],
|
|
223
|
+
[service_1.CourtPosition.LEFT_FRONT]: awayIds[3],
|
|
224
|
+
[service_1.CourtPosition.LEFT_BACK]: awayIds[4],
|
|
225
|
+
[service_1.CourtPosition.MIDDLE_BACK]: awayIds[5],
|
|
226
|
+
bench: []
|
|
227
|
+
},
|
|
228
|
+
libero_replacements: [],
|
|
229
|
+
receive_rotation_offset: false,
|
|
230
|
+
designated_subs: [],
|
|
231
|
+
substitution_band: 'TIRED',
|
|
232
|
+
rotation_system: '6-0',
|
|
233
|
+
designated_setters: [],
|
|
234
|
+
offensive_preferences: []
|
|
235
|
+
},
|
|
236
|
+
PlayerTeams: awayIds.map(id => ({ player: makePlayerModel(id) }))
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function makeMatchModel(withPreset) {
|
|
240
|
+
return {
|
|
241
|
+
match_id: (0, uuid_1.v4)(),
|
|
242
|
+
home_team: teamId,
|
|
243
|
+
away_team: awayTeamId,
|
|
244
|
+
scheduled_date: new Date(),
|
|
245
|
+
status: 'PENDING',
|
|
246
|
+
HomeTeam: makeTeamModel(activeOrder),
|
|
247
|
+
AwayTeam: makeAwayModel(),
|
|
248
|
+
MatchSets: [],
|
|
249
|
+
VPERs: [],
|
|
250
|
+
MatchPresets: withPreset
|
|
251
|
+
? [{ match_id: 'm', team_id: teamId, preset_id: 'preset-1', preset: { config: makeConfig(presetOrder) } }]
|
|
252
|
+
: undefined
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
(0, globals_1.it)('applies the home override and leaves the away team on active tactics', () => {
|
|
256
|
+
const match = (0, match_1.transformToMatch)(makeMatchModel(true));
|
|
257
|
+
(0, globals_1.expect)(starterAt(match.homeTeam.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(presetOrder[0]);
|
|
258
|
+
(0, globals_1.expect)(starterAt(match.awayTeam.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(awayIds[0]);
|
|
259
|
+
});
|
|
260
|
+
(0, globals_1.it)('behaves exactly as before when the association is absent', () => {
|
|
261
|
+
const match = (0, match_1.transformToMatch)(makeMatchModel(false));
|
|
262
|
+
(0, globals_1.expect)(starterAt(match.homeTeam.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(activeOrder[0]);
|
|
263
|
+
(0, globals_1.expect)(starterAt(match.awayTeam.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(awayIds[0]);
|
|
264
|
+
});
|
|
265
|
+
(0, globals_1.it)('routes the fallback callback with the failing team id', () => {
|
|
266
|
+
const onPresetFallback = globals_1.jest.fn();
|
|
267
|
+
const model = makeMatchModel(true);
|
|
268
|
+
model.MatchPresets[0].preset.config = makeConfig([(0, uuid_1.v4)(), ...ids.slice(1)]);
|
|
269
|
+
const match = (0, match_1.transformToMatch)(model, undefined, onPresetFallback);
|
|
270
|
+
(0, globals_1.expect)(onPresetFallback).toHaveBeenCalledTimes(1);
|
|
271
|
+
(0, globals_1.expect)(onPresetFallback.mock.calls[0][0]).toBe(teamId);
|
|
272
|
+
(0, globals_1.expect)(onPresetFallback.mock.calls[0][1]).toBe('preset-1');
|
|
273
|
+
(0, globals_1.expect)(starterAt(match.homeTeam.tactics, service_1.CourtPosition.RIGHT_BACK)).toBe(activeOrder[0]);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MatchAttributes, MatchModel } from '../models';
|
|
2
2
|
import { Match } from '../../service';
|
|
3
|
+
export type PresetFallbackHandler = (teamId: string, presetId: string, err: unknown) => void;
|
|
3
4
|
declare function transformToAttributes(match: Match): MatchAttributes;
|
|
4
|
-
declare function transformToObject(model: MatchModel, currentIteration?: number): Match;
|
|
5
|
+
declare function transformToObject(model: MatchModel, currentIteration?: number, onPresetFallback?: PresetFallbackHandler): Match;
|
|
5
6
|
export { transformToObject as transformToMatch, transformToAttributes as transformFromMatch };
|
|
@@ -15,7 +15,19 @@ function transformToAttributes(match) {
|
|
|
15
15
|
status: match.status
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
-
function transformToObject(model, currentIteration) {
|
|
18
|
+
function transformToObject(model, currentIteration, onPresetFallback) {
|
|
19
|
+
// The (match, team)-chosen preset override for one side, when the loader included MatchPresets with the
|
|
20
|
+
// preset loaded (only the simulator's match query does). Association absent = active tactics, as always.
|
|
21
|
+
const overrideFor = (teamId) => {
|
|
22
|
+
const row = (model.MatchPresets ?? []).find(mp => mp.team_id === teamId);
|
|
23
|
+
if (row?.preset == null)
|
|
24
|
+
return undefined;
|
|
25
|
+
return {
|
|
26
|
+
presetId: row.preset_id,
|
|
27
|
+
config: row.preset.config,
|
|
28
|
+
onFallback: (presetId, err) => onPresetFallback?.(teamId, presetId, err)
|
|
29
|
+
};
|
|
30
|
+
};
|
|
19
31
|
const sets = (model.MatchSets ?? []).map(match_set_1.transformToMatchSet)
|
|
20
32
|
.sort((s1, s2) => s1.order - s2.order);
|
|
21
33
|
let homeScore = 0;
|
|
@@ -47,8 +59,8 @@ function transformToObject(model, currentIteration) {
|
|
|
47
59
|
const VPERs = (model.VPERs ?? []).map(vper_1.transformToVPER);
|
|
48
60
|
return service_1.Match.create({
|
|
49
61
|
id: model.match_id,
|
|
50
|
-
homeTeam: (0, team_1.transformToTeam)(model.HomeTeam, currentIteration),
|
|
51
|
-
awayTeam: (0, team_1.transformToTeam)(model.AwayTeam, currentIteration),
|
|
62
|
+
homeTeam: (0, team_1.transformToTeam)(model.HomeTeam, currentIteration, overrideFor(model.home_team)),
|
|
63
|
+
awayTeam: (0, team_1.transformToTeam)(model.AwayTeam, currentIteration, overrideFor(model.away_team)),
|
|
52
64
|
scheduledDate: new Date(model.scheduled_date),
|
|
53
65
|
sets,
|
|
54
66
|
status: model.status,
|
|
@@ -44,7 +44,7 @@ function transformToObject(model) {
|
|
|
44
44
|
id: model.competition_id,
|
|
45
45
|
iteration: (0, _1.transformToIteration)(model.Iteration),
|
|
46
46
|
matches: (model.CompetitionMatches ?? []).map(_1.transformToQualifierMatch),
|
|
47
|
-
teams: (0, _1.sortTeamsByCompetitionIndex)(model.Teams ?? []).map(_1.transformToTeam),
|
|
47
|
+
teams: (0, _1.sortTeamsByCompetitionIndex)(model.Teams ?? []).map(team => (0, _1.transformToTeam)(team)),
|
|
48
48
|
status: model.status,
|
|
49
49
|
region: (0, _1.transformToRegion)(regionQualifier),
|
|
50
50
|
champion
|
|
@@ -33,7 +33,7 @@ function transformToAttributes(season) {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
function transformToObject(model) {
|
|
36
|
-
const teams = (0, _1.sortTeamsByCompetitionIndex)(model.Teams ?? []).map(_1.transformToTeam);
|
|
36
|
+
const teams = (0, _1.sortTeamsByCompetitionIndex)(model.Teams ?? []).map(team => (0, _1.transformToTeam)(team));
|
|
37
37
|
// One standing per roster team: the persisted CompetitionStandings aggregate where it exists, a zero-stat
|
|
38
38
|
// row otherwise. CompetitionStandings only gains a row once a team plays (the DB trigger fires on match
|
|
39
39
|
// COMPLETE), so mapping it directly dropped un-played teams from the table for the first part of a season.
|