volleyballsimtypes 0.0.364 → 0.0.366

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.
Files changed (39) hide show
  1. package/dist/cjs/src/data/models/player.d.ts +6 -2
  2. package/dist/cjs/src/data/models/player.js +10 -1
  3. package/dist/cjs/src/data/models/retired-player.d.ts +0 -2
  4. package/dist/cjs/src/data/models/retired-player.js +8 -10
  5. package/dist/cjs/src/data/transformers/match.d.ts +1 -1
  6. package/dist/cjs/src/data/transformers/match.js +4 -4
  7. package/dist/cjs/src/data/transformers/player.d.ts +1 -1
  8. package/dist/cjs/src/data/transformers/player.js +9 -3
  9. package/dist/cjs/src/data/transformers/player.test.d.ts +1 -0
  10. package/dist/cjs/src/data/transformers/player.test.js +131 -0
  11. package/dist/cjs/src/data/transformers/team.d.ts +1 -1
  12. package/dist/cjs/src/data/transformers/team.js +2 -2
  13. package/dist/cjs/src/service/player/player-generator.d.ts +1 -1
  14. package/dist/cjs/src/service/player/player-generator.js +3 -3
  15. package/dist/cjs/src/service/player/player.d.ts +2 -0
  16. package/dist/cjs/src/service/player/player.js +3 -1
  17. package/dist/cjs/src/service/player/schemas/player.z.d.ts +2 -0
  18. package/dist/cjs/src/service/player/schemas/player.z.js +2 -0
  19. package/dist/cjs/src/service/test-helpers.js +2 -0
  20. package/dist/esm/src/data/models/player.d.ts +6 -2
  21. package/dist/esm/src/data/models/player.js +10 -1
  22. package/dist/esm/src/data/models/retired-player.d.ts +0 -2
  23. package/dist/esm/src/data/models/retired-player.js +8 -10
  24. package/dist/esm/src/data/transformers/match.d.ts +1 -1
  25. package/dist/esm/src/data/transformers/match.js +4 -4
  26. package/dist/esm/src/data/transformers/player.d.ts +1 -1
  27. package/dist/esm/src/data/transformers/player.js +9 -3
  28. package/dist/esm/src/data/transformers/player.test.d.ts +1 -0
  29. package/dist/esm/src/data/transformers/player.test.js +129 -0
  30. package/dist/esm/src/data/transformers/team.d.ts +1 -1
  31. package/dist/esm/src/data/transformers/team.js +2 -2
  32. package/dist/esm/src/service/player/player-generator.d.ts +1 -1
  33. package/dist/esm/src/service/player/player-generator.js +3 -3
  34. package/dist/esm/src/service/player/player.d.ts +2 -0
  35. package/dist/esm/src/service/player/player.js +3 -1
  36. package/dist/esm/src/service/player/schemas/player.z.d.ts +2 -0
  37. package/dist/esm/src/service/player/schemas/player.z.js +2 -0
  38. package/dist/esm/src/service/test-helpers.js +2 -0
  39. package/package.json +2 -4
@@ -10,7 +10,9 @@ export interface PlayerAttributes {
10
10
  first_name: string;
11
11
  last_name: string;
12
12
  country_id: string;
13
- age: number;
13
+ birth_age: number;
14
+ birth_iteration: number;
15
+ last_declined_iteration: number | null;
14
16
  decline_profile: DeclineProfile;
15
17
  PerformanceStat?: PerformanceStatsAttributes;
16
18
  BoxScores?: BoxScoreAttributes[];
@@ -26,7 +28,9 @@ export declare class PlayerModel extends Model<PlayerAttributes, PlayerCreationA
26
28
  first_name: string;
27
29
  last_name: string;
28
30
  country_id: string;
29
- age: number;
31
+ birth_age: number;
32
+ birth_iteration: number;
33
+ last_declined_iteration: number | null;
30
34
  decline_profile: DeclineProfile;
31
35
  country: CountryModel;
32
36
  getCountry: Sequelize.BelongsToGetAssociationMixin<CountryModel>;
@@ -40,11 +40,20 @@ class PlayerModel extends sequelize_1.Model {
40
40
  key: 'country_id'
41
41
  }
42
42
  },
43
- age: {
43
+ birth_age: {
44
44
  type: sequelize_1.DataTypes.INTEGER,
45
45
  allowNull: false,
46
46
  defaultValue: 17
47
47
  },
48
+ birth_iteration: {
49
+ type: sequelize_1.DataTypes.INTEGER,
50
+ allowNull: false,
51
+ defaultValue: 1
52
+ },
53
+ last_declined_iteration: {
54
+ type: sequelize_1.DataTypes.INTEGER,
55
+ allowNull: true
56
+ },
48
57
  decline_profile: {
49
58
  type: sequelize_1.DataTypes.ENUM(...Object.values(service_1.DeclineProfileEnum)),
50
59
  allowNull: false,
@@ -3,7 +3,6 @@ import { Model } from 'sequelize';
3
3
  import { PlayerId, PlayerModel, TeamId, TeamModel } from '.';
4
4
  export interface RetiredPlayerAttributes {
5
5
  player_id: string;
6
- user_id: string;
7
6
  team_id: string;
8
7
  retired_iteration: number;
9
8
  }
@@ -12,7 +11,6 @@ export type RetiredPlayerId = RetiredPlayerModel[RetiredPlayerPk];
12
11
  export type RetiredPlayerCreationAttributes = RetiredPlayerAttributes;
13
12
  export declare class RetiredPlayerModel extends Model<RetiredPlayerAttributes, RetiredPlayerCreationAttributes> implements RetiredPlayerAttributes {
14
13
  player_id: string;
15
- user_id: string;
16
14
  team_id: string;
17
15
  retired_iteration: number;
18
16
  player: PlayerModel;
@@ -14,14 +14,6 @@ class RetiredPlayerModel extends sequelize_1.Model {
14
14
  key: 'player_id'
15
15
  }
16
16
  },
17
- user_id: {
18
- type: sequelize_1.DataTypes.UUID,
19
- allowNull: false,
20
- references: {
21
- model: 'AuthUser',
22
- key: 'user_id'
23
- }
24
- },
25
17
  team_id: {
26
18
  type: sequelize_1.DataTypes.UUID,
27
19
  allowNull: false,
@@ -39,11 +31,17 @@ class RetiredPlayerModel extends sequelize_1.Model {
39
31
  tableName: 'RetiredPlayer',
40
32
  schema: 'public',
41
33
  timestamps: false,
42
- indexes: [{
34
+ indexes: [
35
+ {
43
36
  name: 'RetiredPlayer_pk',
44
37
  unique: true,
45
38
  fields: [{ name: 'player_id' }]
46
- }]
39
+ },
40
+ {
41
+ name: 'RetiredPlayer_team_id_idx',
42
+ fields: [{ name: 'team_id' }]
43
+ }
44
+ ]
47
45
  });
48
46
  }
49
47
  }
@@ -1,5 +1,5 @@
1
1
  import { MatchAttributes, MatchModel } from '../models';
2
2
  import { Match } from '../../service';
3
3
  declare function transformToAttributes(match: Match): MatchAttributes;
4
- declare function transformToObject(model: MatchModel): Match;
4
+ declare function transformToObject(model: MatchModel, currentIteration?: number): Match;
5
5
  export { transformToObject as transformToMatch, transformToAttributes as transformFromMatch };
@@ -15,7 +15,7 @@ function transformToAttributes(match) {
15
15
  status: match.status
16
16
  };
17
17
  }
18
- function transformToObject(model) {
18
+ function transformToObject(model, currentIteration) {
19
19
  const sets = (model.MatchSets ?? []).map(match_set_1.transformToMatchSet)
20
20
  .sort((s1, s2) => s1.order - s2.order);
21
21
  let homeScore = 0;
@@ -47,14 +47,14 @@ function transformToObject(model) {
47
47
  const VPERs = (model.VPERs ?? []).map(vper_1.transformToVPER);
48
48
  return service_1.Match.create({
49
49
  id: model.match_id,
50
- homeTeam: (0, team_1.transformToTeam)(model.HomeTeam),
51
- awayTeam: (0, team_1.transformToTeam)(model.AwayTeam),
50
+ homeTeam: (0, team_1.transformToTeam)(model.HomeTeam, currentIteration),
51
+ awayTeam: (0, team_1.transformToTeam)(model.AwayTeam, currentIteration),
52
52
  scheduledDate: new Date(model.scheduled_date),
53
53
  sets,
54
54
  status: model.status,
55
55
  VPERs,
56
56
  homeScore,
57
57
  awayScore,
58
- winner: model.MatchResult?.Winner != null ? (0, team_1.transformToTeam)(model.MatchResult.Winner) : undefined
58
+ winner: model.MatchResult?.Winner != null ? (0, team_1.transformToTeam)(model.MatchResult.Winner, currentIteration) : undefined
59
59
  });
60
60
  }
@@ -1,5 +1,5 @@
1
1
  import { PlayerAttributes, PlayerModel } from '../models';
2
2
  import { Player } from '../../service';
3
3
  declare function transformToAttributes(player: Player): PlayerAttributes;
4
- declare function transformToObject(model: PlayerModel): Player;
4
+ declare function transformToObject(model: PlayerModel, currentIteration?: number): Player;
5
5
  export { transformToObject as transformToPlayer, transformToAttributes as transformFromPlayer };
@@ -21,7 +21,9 @@ function transformToAttributes(player) {
21
21
  traits: player.traits,
22
22
  PerformanceStat: (0, _1.transformFromPerformanceStats)(player.stats, player.id),
23
23
  rarity: player.rarity,
24
- age: player.age,
24
+ birth_age: player.birthAge,
25
+ birth_iteration: player.birthIteration,
26
+ last_declined_iteration: null,
25
27
  decline_profile: player.declineProfile
26
28
  };
27
29
  }
@@ -68,8 +70,10 @@ function transformToBoxScoreTotals(model) {
68
70
  }
69
71
  };
70
72
  }
71
- function transformToObject(model) {
73
+ function transformToObject(model, currentIteration) {
72
74
  const boxScoreTotals = model.BoxScoreTotals != null ? transformToBoxScoreTotals(model.BoxScoreTotals) : undefined;
75
+ // When currentIteration is not provided, fall back to birth_iteration so age = birthAge.
76
+ const iter = currentIteration ?? model.birth_iteration;
73
77
  return service_1.Player.create({
74
78
  id: model.player_id,
75
79
  name: {
@@ -81,7 +85,9 @@ function transformToObject(model) {
81
85
  traits: model.traits,
82
86
  stats: (0, _1.transformToPerformanceStats)(model.PerformanceStat),
83
87
  rarity: model.rarity,
84
- age: model.age,
88
+ age: model.birth_age + (iter - model.birth_iteration),
89
+ birthAge: model.birth_age,
90
+ birthIteration: model.birth_iteration,
85
91
  declineProfile: model.decline_profile,
86
92
  boxScores: (model.BoxScores ?? []).map(_1.transformToBoxScore),
87
93
  boxScoreTotals
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,131 @@
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 player_1 = require("./player");
6
+ const service_1 = require("../../service");
7
+ // ─── shared mock ──────────────────────────────────────────────────────────────
8
+ /** Minimal PlayerModel-shaped object for transformer tests.
9
+ * Uses 'as unknown as PlayerModel' because Sequelize model instances carry
10
+ * internal state we don't need; plain objects are sufficient for unit testing. */
11
+ function makeModel(birthAge, birthIteration) {
12
+ const stat = 50;
13
+ return {
14
+ player_id: (0, uuid_1.v4)(),
15
+ first_name: 'Test',
16
+ last_name: 'Player',
17
+ rarity: service_1.RarityEnum.COMMON,
18
+ roles: [service_1.RoleEnum.OUTSIDE_HITTER],
19
+ traits: [],
20
+ birth_age: birthAge,
21
+ birth_iteration: birthIteration,
22
+ last_declined_iteration: null,
23
+ decline_profile: service_1.DeclineProfileEnum.STANDARD,
24
+ BoxScores: [],
25
+ BoxScoreTotals: null,
26
+ country: {
27
+ country_id: (0, uuid_1.v4)(),
28
+ name: 'Test Country',
29
+ alpha_2: 'TC',
30
+ alpha_3: 'TCN',
31
+ country_code: '999',
32
+ iso_3166_2: 'TC-TEST',
33
+ region: '',
34
+ region_code: '',
35
+ sub_region: '',
36
+ sub_region_code: '',
37
+ intermediate_region: '',
38
+ intermediate_region_code: ''
39
+ },
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
+ // ─── transformToPlayer ────────────────────────────────────────────────────────
63
+ (0, globals_1.describe)('transformToPlayer()', () => {
64
+ (0, globals_1.describe)('age computation', () => {
65
+ (0, globals_1.it)('computes age as birthAge + (currentIteration - birthIteration)', () => {
66
+ const model = makeModel(17, 1);
67
+ const player = (0, player_1.transformToPlayer)(model, 10);
68
+ (0, globals_1.expect)(player.age).toBe(17 + (10 - 1)); // 26
69
+ });
70
+ (0, globals_1.it)('age equals birthAge when currentIteration equals birthIteration', () => {
71
+ const model = makeModel(18, 5);
72
+ const player = (0, player_1.transformToPlayer)(model, 5);
73
+ (0, globals_1.expect)(player.age).toBe(18);
74
+ });
75
+ (0, globals_1.it)('falls back to birthAge when currentIteration is omitted', () => {
76
+ const model = makeModel(19, 3);
77
+ const player = (0, player_1.transformToPlayer)(model);
78
+ (0, globals_1.expect)(player.age).toBe(19); // iter defaults to birth_iteration → offset = 0
79
+ });
80
+ (0, globals_1.it)('handles a large iteration gap correctly', () => {
81
+ const model = makeModel(15, 1);
82
+ const player = (0, player_1.transformToPlayer)(model, 53);
83
+ (0, globals_1.expect)(player.age).toBe(15 + 52); // 67
84
+ });
85
+ });
86
+ (0, globals_1.describe)('birthAge and birthIteration passthrough', () => {
87
+ (0, globals_1.it)('stores birthAge from birth_age', () => {
88
+ const model = makeModel(20, 1);
89
+ (0, globals_1.expect)((0, player_1.transformToPlayer)(model, 1).birthAge).toBe(20);
90
+ });
91
+ (0, globals_1.it)('stores birthIteration from birth_iteration', () => {
92
+ const model = makeModel(16, 4);
93
+ (0, globals_1.expect)((0, player_1.transformToPlayer)(model, 4).birthIteration).toBe(4);
94
+ });
95
+ (0, globals_1.it)('age, birthAge, and birthIteration are mutually consistent', () => {
96
+ const birthAge = 17;
97
+ const birthIteration = 2;
98
+ const currentIteration = 15;
99
+ const model = makeModel(birthAge, birthIteration);
100
+ const player = (0, player_1.transformToPlayer)(model, currentIteration);
101
+ (0, globals_1.expect)(player.age).toBe(player.birthAge + (currentIteration - player.birthIteration));
102
+ });
103
+ });
104
+ });
105
+ // ─── transformFromPlayer ──────────────────────────────────────────────────────
106
+ (0, globals_1.describe)('transformFromPlayer()', () => {
107
+ (0, globals_1.it)('writes birth_iteration from player.birthIteration', () => {
108
+ const model = makeModel(17, 3);
109
+ const player = (0, player_1.transformToPlayer)(model, 3);
110
+ const attrs = (0, player_1.transformFromPlayer)(player);
111
+ (0, globals_1.expect)(attrs.birth_iteration).toBe(3);
112
+ });
113
+ (0, globals_1.it)('writes birth_age from player.birthAge', () => {
114
+ const model = makeModel(19, 1);
115
+ const player = (0, player_1.transformToPlayer)(model, 1);
116
+ const attrs = (0, player_1.transformFromPlayer)(player);
117
+ (0, globals_1.expect)(attrs.birth_age).toBe(19);
118
+ });
119
+ (0, globals_1.it)('sets last_declined_iteration to null for new players', () => {
120
+ const model = makeModel(17, 1);
121
+ const player = (0, player_1.transformToPlayer)(model, 1);
122
+ const attrs = (0, player_1.transformFromPlayer)(player);
123
+ (0, globals_1.expect)(attrs.last_declined_iteration).toBeNull();
124
+ });
125
+ (0, globals_1.it)('does not write an age column (age is derived, not stored)', () => {
126
+ const model = makeModel(17, 1);
127
+ const player = (0, player_1.transformToPlayer)(model, 1);
128
+ const attrs = (0, player_1.transformFromPlayer)(player);
129
+ (0, globals_1.expect)('age' in attrs).toBe(false);
130
+ });
131
+ });
@@ -1,5 +1,5 @@
1
1
  import { Team } from '../../service';
2
2
  import { TeamAttributes, TeamModel } from '../models';
3
3
  declare function transformToAttributes(team: Team): TeamAttributes;
4
- declare function transformToObject(model: TeamModel): Team;
4
+ declare function transformToObject(model: TeamModel, currentIteration?: number): Team;
5
5
  export { transformToObject as transformToTeam, transformToAttributes as transformFromTeam };
@@ -16,8 +16,8 @@ function transformToAttributes(team) {
16
16
  division_id: team.divisionId
17
17
  };
18
18
  }
19
- function transformToObject(model) {
20
- const roster = (model.PlayerTeams ?? []).map((pt) => (0, _1.transformToPlayer)(pt.player));
19
+ function transformToObject(model, currentIteration) {
20
+ const roster = (model.PlayerTeams ?? []).map((pt) => (0, _1.transformToPlayer)(pt.player, currentIteration));
21
21
  const tactics = model.tactics != null && roster != null && roster.length > 0
22
22
  ? (0, _1.transformToTactics)(model.tactics, roster)
23
23
  : undefined;
@@ -30,7 +30,7 @@ export declare function rollRarity(pity: PityState, config?: GachaPullConfig): R
30
30
  export declare class PlayerGenerator {
31
31
  private constructor();
32
32
  private static generatePerformance;
33
- static generatePlayer(country: Country, _rarity?: Rarity, role?: Role, maxTraits?: boolean): Player;
33
+ static generatePlayer(country: Country, _rarity?: Rarity, role?: Role, maxTraits?: boolean, birthIteration?: number): Player;
34
34
  static generatePlayers(count: number, countries: Country[]): Player[];
35
35
  }
36
36
  export declare function pickPlayerCountry(teamCountry: Country, allCountries: Country[]): Country;
@@ -213,15 +213,15 @@ class PlayerGenerator {
213
213
  }
214
214
  }
215
215
  }
216
- static generatePlayer(country, _rarity, role, maxTraits) {
216
+ static generatePlayer(country, _rarity, role, maxTraits, birthIteration = 1) {
217
217
  const rarity = _rarity ?? rollRarity({ legendaryPity: 0, mythicPity: 0, specialPity: 0 }).rarity;
218
218
  const name = (0, utils_1.generatePlayerName)(country.locales, 1)[0];
219
219
  const stats = PlayerGenerator.generatePerformance(rarity, role);
220
220
  const roles = (0, role_1.assignRoles)(stats, rarity);
221
221
  const traits = (0, trait_1.assignTraits)(roles, rarity, maxTraits);
222
- const age = (0, node_crypto_1.randomInt)(15, 21);
222
+ const birthAge = (0, node_crypto_1.randomInt)(15, 21);
223
223
  const declineProfile = decline_1.declineProfiles[(0, node_crypto_1.randomInt)(0, decline_1.declineProfiles.length)];
224
- return player_1.Player.create({ id: (0, uuid_1.v4)(), name, country, stats, roles, traits, rarity, age, declineProfile });
224
+ return player_1.Player.create({ id: (0, uuid_1.v4)(), name, country, stats, roles, traits, rarity, age: birthAge, birthAge, birthIteration, declineProfile });
225
225
  }
226
226
  static generatePlayers(count, countries) {
227
227
  const players = [];
@@ -32,6 +32,8 @@ export declare class Player {
32
32
  readonly generalStats: Stat[];
33
33
  readonly rarity: Rarity;
34
34
  readonly age: number;
35
+ readonly birthAge: number;
36
+ readonly birthIteration: number;
35
37
  readonly declineProfile: DeclineProfile;
36
38
  readonly boxScores?: BoxScore[];
37
39
  readonly boxScoreTotals?: BoxScoreTotals;
@@ -54,7 +54,7 @@ class Player {
54
54
  stats: performance_stats_1.PerformanceStats.create(result.data.stats)
55
55
  });
56
56
  }
57
- constructor({ id, name, country, stats, roles, traits, rarity, age, declineProfile, boxScores, boxScoreTotals }) {
57
+ constructor({ id, name, country, stats, roles, traits, rarity, age, birthAge, birthIteration, declineProfile, boxScores, boxScoreTotals }) {
58
58
  this.id = id;
59
59
  this.name = name;
60
60
  this.country = country;
@@ -63,6 +63,8 @@ class Player {
63
63
  this.traits = traits;
64
64
  this.rarity = rarity;
65
65
  this.age = age;
66
+ this.birthAge = birthAge;
67
+ this.birthIteration = birthIteration;
66
68
  this.declineProfile = declineProfile;
67
69
  this.boxScores = boxScores;
68
70
  this.boxScoreTotals = boxScoreTotals;
@@ -61,6 +61,8 @@ export declare const PlayerInputSchema: z.ZodObject<{
61
61
  SPECIAL: RarityEnum.SPECIAL;
62
62
  }>;
63
63
  age: z.ZodNumber;
64
+ birthAge: z.ZodNumber;
65
+ birthIteration: z.ZodNumber;
64
66
  declineProfile: z.ZodEnum<{
65
67
  PRODIGY: DeclineProfileEnum.PRODIGY;
66
68
  STANDARD: DeclineProfileEnum.STANDARD;
@@ -34,6 +34,8 @@ exports.PlayerInputSchema = zod_1.z.object({
34
34
  traits: zod_1.z.array(zod_1.z.enum(Object.values(trait_1.TraitEnum))),
35
35
  rarity: zod_1.z.enum(Object.values(rarity_1.RarityEnum)),
36
36
  age: zod_1.z.number().int().min(0),
37
+ birthAge: zod_1.z.number().int().min(0),
38
+ birthIteration: zod_1.z.number().int().min(1),
37
39
  declineProfile: zod_1.z.enum(Object.values(decline_1.DeclineProfileEnum)),
38
40
  boxScores: zod_1.z.array(box_score_z_1.BoxScoreInputSchema).optional(),
39
41
  boxScoreTotals: BoxScoreTotalsInputSchema.optional()
@@ -46,6 +46,8 @@ function makePlayer(country, statValue = 50) {
46
46
  traits: [],
47
47
  rarity: rarity_1.RarityEnum.COMMON,
48
48
  age: 20,
49
+ birthAge: 20,
50
+ birthIteration: 1,
49
51
  declineProfile: decline_1.DeclineProfileEnum.STANDARD
50
52
  });
51
53
  }
@@ -10,7 +10,9 @@ export interface PlayerAttributes {
10
10
  first_name: string;
11
11
  last_name: string;
12
12
  country_id: string;
13
- age: number;
13
+ birth_age: number;
14
+ birth_iteration: number;
15
+ last_declined_iteration: number | null;
14
16
  decline_profile: DeclineProfile;
15
17
  PerformanceStat?: PerformanceStatsAttributes;
16
18
  BoxScores?: BoxScoreAttributes[];
@@ -26,7 +28,9 @@ export declare class PlayerModel extends Model<PlayerAttributes, PlayerCreationA
26
28
  first_name: string;
27
29
  last_name: string;
28
30
  country_id: string;
29
- age: number;
31
+ birth_age: number;
32
+ birth_iteration: number;
33
+ last_declined_iteration: number | null;
30
34
  decline_profile: DeclineProfile;
31
35
  country: CountryModel;
32
36
  getCountry: Sequelize.BelongsToGetAssociationMixin<CountryModel>;
@@ -37,11 +37,20 @@ export class PlayerModel extends Model {
37
37
  key: 'country_id'
38
38
  }
39
39
  },
40
- age: {
40
+ birth_age: {
41
41
  type: DataTypes.INTEGER,
42
42
  allowNull: false,
43
43
  defaultValue: 17
44
44
  },
45
+ birth_iteration: {
46
+ type: DataTypes.INTEGER,
47
+ allowNull: false,
48
+ defaultValue: 1
49
+ },
50
+ last_declined_iteration: {
51
+ type: DataTypes.INTEGER,
52
+ allowNull: true
53
+ },
45
54
  decline_profile: {
46
55
  type: DataTypes.ENUM(...Object.values(DeclineProfileEnum)),
47
56
  allowNull: false,
@@ -3,7 +3,6 @@ import { Model } from 'sequelize';
3
3
  import { PlayerId, PlayerModel, TeamId, TeamModel } from '.';
4
4
  export interface RetiredPlayerAttributes {
5
5
  player_id: string;
6
- user_id: string;
7
6
  team_id: string;
8
7
  retired_iteration: number;
9
8
  }
@@ -12,7 +11,6 @@ export type RetiredPlayerId = RetiredPlayerModel[RetiredPlayerPk];
12
11
  export type RetiredPlayerCreationAttributes = RetiredPlayerAttributes;
13
12
  export declare class RetiredPlayerModel extends Model<RetiredPlayerAttributes, RetiredPlayerCreationAttributes> implements RetiredPlayerAttributes {
14
13
  player_id: string;
15
- user_id: string;
16
14
  team_id: string;
17
15
  retired_iteration: number;
18
16
  player: PlayerModel;
@@ -11,14 +11,6 @@ export class RetiredPlayerModel extends Model {
11
11
  key: 'player_id'
12
12
  }
13
13
  },
14
- user_id: {
15
- type: DataTypes.UUID,
16
- allowNull: false,
17
- references: {
18
- model: 'AuthUser',
19
- key: 'user_id'
20
- }
21
- },
22
14
  team_id: {
23
15
  type: DataTypes.UUID,
24
16
  allowNull: false,
@@ -36,11 +28,17 @@ export class RetiredPlayerModel extends Model {
36
28
  tableName: 'RetiredPlayer',
37
29
  schema: 'public',
38
30
  timestamps: false,
39
- indexes: [{
31
+ indexes: [
32
+ {
40
33
  name: 'RetiredPlayer_pk',
41
34
  unique: true,
42
35
  fields: [{ name: 'player_id' }]
43
- }]
36
+ },
37
+ {
38
+ name: 'RetiredPlayer_team_id_idx',
39
+ fields: [{ name: 'team_id' }]
40
+ }
41
+ ]
44
42
  });
45
43
  }
46
44
  }
@@ -1,5 +1,5 @@
1
1
  import { MatchAttributes, MatchModel } from '../models';
2
2
  import { Match } from '../../service';
3
3
  declare function transformToAttributes(match: Match): MatchAttributes;
4
- declare function transformToObject(model: MatchModel): Match;
4
+ declare function transformToObject(model: MatchModel, currentIteration?: number): Match;
5
5
  export { transformToObject as transformToMatch, transformToAttributes as transformFromMatch };
@@ -11,7 +11,7 @@ function transformToAttributes(match) {
11
11
  status: match.status
12
12
  };
13
13
  }
14
- function transformToObject(model) {
14
+ function transformToObject(model, currentIteration) {
15
15
  const sets = (model.MatchSets ?? []).map(transformToMatchSet)
16
16
  .sort((s1, s2) => s1.order - s2.order);
17
17
  let homeScore = 0;
@@ -43,15 +43,15 @@ function transformToObject(model) {
43
43
  const VPERs = (model.VPERs ?? []).map(transformToVPER);
44
44
  return Match.create({
45
45
  id: model.match_id,
46
- homeTeam: transformToTeam(model.HomeTeam),
47
- awayTeam: transformToTeam(model.AwayTeam),
46
+ homeTeam: transformToTeam(model.HomeTeam, currentIteration),
47
+ awayTeam: transformToTeam(model.AwayTeam, currentIteration),
48
48
  scheduledDate: new Date(model.scheduled_date),
49
49
  sets,
50
50
  status: model.status,
51
51
  VPERs,
52
52
  homeScore,
53
53
  awayScore,
54
- winner: model.MatchResult?.Winner != null ? transformToTeam(model.MatchResult.Winner) : undefined
54
+ winner: model.MatchResult?.Winner != null ? transformToTeam(model.MatchResult.Winner, currentIteration) : undefined
55
55
  });
56
56
  }
57
57
  export { transformToObject as transformToMatch, transformToAttributes as transformFromMatch };
@@ -1,5 +1,5 @@
1
1
  import { PlayerAttributes, PlayerModel } from '../models';
2
2
  import { Player } from '../../service';
3
3
  declare function transformToAttributes(player: Player): PlayerAttributes;
4
- declare function transformToObject(model: PlayerModel): Player;
4
+ declare function transformToObject(model: PlayerModel, currentIteration?: number): Player;
5
5
  export { transformToObject as transformToPlayer, transformToAttributes as transformFromPlayer };
@@ -17,7 +17,9 @@ function transformToAttributes(player) {
17
17
  traits: player.traits,
18
18
  PerformanceStat: transformFromPerformanceStats(player.stats, player.id),
19
19
  rarity: player.rarity,
20
- age: player.age,
20
+ birth_age: player.birthAge,
21
+ birth_iteration: player.birthIteration,
22
+ last_declined_iteration: null,
21
23
  decline_profile: player.declineProfile
22
24
  };
23
25
  }
@@ -64,8 +66,10 @@ function transformToBoxScoreTotals(model) {
64
66
  }
65
67
  };
66
68
  }
67
- function transformToObject(model) {
69
+ function transformToObject(model, currentIteration) {
68
70
  const boxScoreTotals = model.BoxScoreTotals != null ? transformToBoxScoreTotals(model.BoxScoreTotals) : undefined;
71
+ // When currentIteration is not provided, fall back to birth_iteration so age = birthAge.
72
+ const iter = currentIteration ?? model.birth_iteration;
69
73
  return Player.create({
70
74
  id: model.player_id,
71
75
  name: {
@@ -77,7 +81,9 @@ function transformToObject(model) {
77
81
  traits: model.traits,
78
82
  stats: transformToPerformanceStats(model.PerformanceStat),
79
83
  rarity: model.rarity,
80
- age: model.age,
84
+ age: model.birth_age + (iter - model.birth_iteration),
85
+ birthAge: model.birth_age,
86
+ birthIteration: model.birth_iteration,
81
87
  declineProfile: model.decline_profile,
82
88
  boxScores: (model.BoxScores ?? []).map(transformToBoxScore),
83
89
  boxScoreTotals
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { transformToPlayer, transformFromPlayer } from './player';
4
+ import { DeclineProfileEnum, RarityEnum, RoleEnum } from '../../service';
5
+ // ─── shared mock ──────────────────────────────────────────────────────────────
6
+ /** Minimal PlayerModel-shaped object for transformer tests.
7
+ * Uses 'as unknown as PlayerModel' because Sequelize model instances carry
8
+ * internal state we don't need; plain objects are sufficient for unit testing. */
9
+ function makeModel(birthAge, birthIteration) {
10
+ const stat = 50;
11
+ return {
12
+ player_id: uuidv4(),
13
+ first_name: 'Test',
14
+ last_name: 'Player',
15
+ rarity: RarityEnum.COMMON,
16
+ roles: [RoleEnum.OUTSIDE_HITTER],
17
+ traits: [],
18
+ birth_age: birthAge,
19
+ birth_iteration: birthIteration,
20
+ last_declined_iteration: null,
21
+ decline_profile: DeclineProfileEnum.STANDARD,
22
+ BoxScores: [],
23
+ BoxScoreTotals: null,
24
+ country: {
25
+ country_id: uuidv4(),
26
+ name: 'Test Country',
27
+ alpha_2: 'TC',
28
+ alpha_3: 'TCN',
29
+ country_code: '999',
30
+ iso_3166_2: 'TC-TEST',
31
+ region: '',
32
+ region_code: '',
33
+ sub_region: '',
34
+ sub_region_code: '',
35
+ intermediate_region: '',
36
+ intermediate_region_code: ''
37
+ },
38
+ PerformanceStat: {
39
+ setting: stat,
40
+ serve: stat,
41
+ spike: stat,
42
+ quick: stat,
43
+ power: stat,
44
+ awareness: stat,
45
+ attack: stat,
46
+ back_attack: stat,
47
+ reception: stat,
48
+ overhand: stat,
49
+ bump: stat,
50
+ block: stat,
51
+ read: stat,
52
+ commit: stat,
53
+ focus: stat,
54
+ defense: stat,
55
+ stamina: stat,
56
+ reflex: stat
57
+ }
58
+ };
59
+ }
60
+ // ─── transformToPlayer ────────────────────────────────────────────────────────
61
+ describe('transformToPlayer()', () => {
62
+ describe('age computation', () => {
63
+ it('computes age as birthAge + (currentIteration - birthIteration)', () => {
64
+ const model = makeModel(17, 1);
65
+ const player = transformToPlayer(model, 10);
66
+ expect(player.age).toBe(17 + (10 - 1)); // 26
67
+ });
68
+ it('age equals birthAge when currentIteration equals birthIteration', () => {
69
+ const model = makeModel(18, 5);
70
+ const player = transformToPlayer(model, 5);
71
+ expect(player.age).toBe(18);
72
+ });
73
+ it('falls back to birthAge when currentIteration is omitted', () => {
74
+ const model = makeModel(19, 3);
75
+ const player = transformToPlayer(model);
76
+ expect(player.age).toBe(19); // iter defaults to birth_iteration → offset = 0
77
+ });
78
+ it('handles a large iteration gap correctly', () => {
79
+ const model = makeModel(15, 1);
80
+ const player = transformToPlayer(model, 53);
81
+ expect(player.age).toBe(15 + 52); // 67
82
+ });
83
+ });
84
+ describe('birthAge and birthIteration passthrough', () => {
85
+ it('stores birthAge from birth_age', () => {
86
+ const model = makeModel(20, 1);
87
+ expect(transformToPlayer(model, 1).birthAge).toBe(20);
88
+ });
89
+ it('stores birthIteration from birth_iteration', () => {
90
+ const model = makeModel(16, 4);
91
+ expect(transformToPlayer(model, 4).birthIteration).toBe(4);
92
+ });
93
+ it('age, birthAge, and birthIteration are mutually consistent', () => {
94
+ const birthAge = 17;
95
+ const birthIteration = 2;
96
+ const currentIteration = 15;
97
+ const model = makeModel(birthAge, birthIteration);
98
+ const player = transformToPlayer(model, currentIteration);
99
+ expect(player.age).toBe(player.birthAge + (currentIteration - player.birthIteration));
100
+ });
101
+ });
102
+ });
103
+ // ─── transformFromPlayer ──────────────────────────────────────────────────────
104
+ describe('transformFromPlayer()', () => {
105
+ it('writes birth_iteration from player.birthIteration', () => {
106
+ const model = makeModel(17, 3);
107
+ const player = transformToPlayer(model, 3);
108
+ const attrs = transformFromPlayer(player);
109
+ expect(attrs.birth_iteration).toBe(3);
110
+ });
111
+ it('writes birth_age from player.birthAge', () => {
112
+ const model = makeModel(19, 1);
113
+ const player = transformToPlayer(model, 1);
114
+ const attrs = transformFromPlayer(player);
115
+ expect(attrs.birth_age).toBe(19);
116
+ });
117
+ it('sets last_declined_iteration to null for new players', () => {
118
+ const model = makeModel(17, 1);
119
+ const player = transformToPlayer(model, 1);
120
+ const attrs = transformFromPlayer(player);
121
+ expect(attrs.last_declined_iteration).toBeNull();
122
+ });
123
+ it('does not write an age column (age is derived, not stored)', () => {
124
+ const model = makeModel(17, 1);
125
+ const player = transformToPlayer(model, 1);
126
+ const attrs = transformFromPlayer(player);
127
+ expect('age' in attrs).toBe(false);
128
+ });
129
+ });
@@ -1,5 +1,5 @@
1
1
  import { Team } from '../../service';
2
2
  import { TeamAttributes, TeamModel } from '../models';
3
3
  declare function transformToAttributes(team: Team): TeamAttributes;
4
- declare function transformToObject(model: TeamModel): Team;
4
+ declare function transformToObject(model: TeamModel, currentIteration?: number): Team;
5
5
  export { transformToObject as transformToTeam, transformToAttributes as transformFromTeam };
@@ -12,8 +12,8 @@ function transformToAttributes(team) {
12
12
  division_id: team.divisionId
13
13
  };
14
14
  }
15
- function transformToObject(model) {
16
- const roster = (model.PlayerTeams ?? []).map((pt) => transformToPlayer(pt.player));
15
+ function transformToObject(model, currentIteration) {
16
+ const roster = (model.PlayerTeams ?? []).map((pt) => transformToPlayer(pt.player, currentIteration));
17
17
  const tactics = model.tactics != null && roster != null && roster.length > 0
18
18
  ? transformToTactics(model.tactics, roster)
19
19
  : undefined;
@@ -30,7 +30,7 @@ export declare function rollRarity(pity: PityState, config?: GachaPullConfig): R
30
30
  export declare class PlayerGenerator {
31
31
  private constructor();
32
32
  private static generatePerformance;
33
- static generatePlayer(country: Country, _rarity?: Rarity, role?: Role, maxTraits?: boolean): Player;
33
+ static generatePlayer(country: Country, _rarity?: Rarity, role?: Role, maxTraits?: boolean, birthIteration?: number): Player;
34
34
  static generatePlayers(count: number, countries: Country[]): Player[];
35
35
  }
36
36
  export declare function pickPlayerCountry(teamCountry: Country, allCountries: Country[]): Country;
@@ -208,15 +208,15 @@ export class PlayerGenerator {
208
208
  }
209
209
  }
210
210
  }
211
- static generatePlayer(country, _rarity, role, maxTraits) {
211
+ static generatePlayer(country, _rarity, role, maxTraits, birthIteration = 1) {
212
212
  const rarity = _rarity ?? rollRarity({ legendaryPity: 0, mythicPity: 0, specialPity: 0 }).rarity;
213
213
  const name = generatePlayerName(country.locales, 1)[0];
214
214
  const stats = PlayerGenerator.generatePerformance(rarity, role);
215
215
  const roles = assignRoles(stats, rarity);
216
216
  const traits = assignTraits(roles, rarity, maxTraits);
217
- const age = randomInt(15, 21);
217
+ const birthAge = randomInt(15, 21);
218
218
  const declineProfile = declineProfiles[randomInt(0, declineProfiles.length)];
219
- return Player.create({ id: uuidv4(), name, country, stats, roles, traits, rarity, age, declineProfile });
219
+ return Player.create({ id: uuidv4(), name, country, stats, roles, traits, rarity, age: birthAge, birthAge, birthIteration, declineProfile });
220
220
  }
221
221
  static generatePlayers(count, countries) {
222
222
  const players = [];
@@ -32,6 +32,8 @@ export declare class Player {
32
32
  readonly generalStats: Stat[];
33
33
  readonly rarity: Rarity;
34
34
  readonly age: number;
35
+ readonly birthAge: number;
36
+ readonly birthIteration: number;
35
37
  readonly declineProfile: DeclineProfile;
36
38
  readonly boxScores?: BoxScore[];
37
39
  readonly boxScoreTotals?: BoxScoreTotals;
@@ -49,7 +49,7 @@ export class Player {
49
49
  stats: PerformanceStats.create(result.data.stats)
50
50
  });
51
51
  }
52
- constructor({ id, name, country, stats, roles, traits, rarity, age, declineProfile, boxScores, boxScoreTotals }) {
52
+ constructor({ id, name, country, stats, roles, traits, rarity, age, birthAge, birthIteration, declineProfile, boxScores, boxScoreTotals }) {
53
53
  this.id = id;
54
54
  this.name = name;
55
55
  this.country = country;
@@ -58,6 +58,8 @@ export class Player {
58
58
  this.traits = traits;
59
59
  this.rarity = rarity;
60
60
  this.age = age;
61
+ this.birthAge = birthAge;
62
+ this.birthIteration = birthIteration;
61
63
  this.declineProfile = declineProfile;
62
64
  this.boxScores = boxScores;
63
65
  this.boxScoreTotals = boxScoreTotals;
@@ -61,6 +61,8 @@ export declare const PlayerInputSchema: z.ZodObject<{
61
61
  SPECIAL: RarityEnum.SPECIAL;
62
62
  }>;
63
63
  age: z.ZodNumber;
64
+ birthAge: z.ZodNumber;
65
+ birthIteration: z.ZodNumber;
64
66
  declineProfile: z.ZodEnum<{
65
67
  PRODIGY: DeclineProfileEnum.PRODIGY;
66
68
  STANDARD: DeclineProfileEnum.STANDARD;
@@ -31,6 +31,8 @@ export const PlayerInputSchema = z.object({
31
31
  traits: z.array(z.enum(Object.values(TraitEnum))),
32
32
  rarity: z.enum(Object.values(RarityEnum)),
33
33
  age: z.number().int().min(0),
34
+ birthAge: z.number().int().min(0),
35
+ birthIteration: z.number().int().min(1),
34
36
  declineProfile: z.enum(Object.values(DeclineProfileEnum)),
35
37
  boxScores: z.array(BoxScoreInputSchema).optional(),
36
38
  boxScoreTotals: BoxScoreTotalsInputSchema.optional()
@@ -36,6 +36,8 @@ export function makePlayer(country, statValue = 50) {
36
36
  traits: [],
37
37
  rarity: RarityEnum.COMMON,
38
38
  age: 20,
39
+ birthAge: 20,
40
+ birthIteration: 1,
39
41
  declineProfile: DeclineProfileEnum.STANDARD
40
42
  });
41
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volleyballsimtypes",
3
- "version": "0.0.364",
3
+ "version": "0.0.366",
4
4
  "description": "vbsim types",
5
5
  "main": "./dist/cjs/src/index.js",
6
6
  "module": "./dist/esm/src/index.js",
@@ -68,9 +68,7 @@
68
68
  "build": "npm run test-types && yarn clean && tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
69
69
  "sync:consumers": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/sync-consumers.ps1",
70
70
  "release": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/release.ps1",
71
- "export:schema": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/export-schema.ps1",
72
- "preversion": "npm run clean && npm run build && git commit -a --amend --no-edit",
73
- "postversion": "git push --follow-tags && npm login && npm publish"
71
+ "export:schema": "powershell -NoProfile -ExecutionPolicy Bypass -File ./scripts/export-schema.ps1"
74
72
  },
75
73
  "author": "Francisco Farias <fariasfranciscoe@gmail.com>",
76
74
  "license": "ISC",