@voyant-travel/mice 0.2.0 → 0.3.0
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/booking-extension.d.ts +130 -0
- package/dist/booking-extension.d.ts.map +1 -0
- package/dist/booking-extension.js +83 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/routes.d.ts +398 -5
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +85 -0
- package/dist/schema-delegates.d.ts +340 -0
- package/dist/schema-delegates.d.ts.map +1 -0
- package/dist/schema-delegates.js +76 -0
- package/dist/schema-rooming.d.ts +333 -0
- package/dist/schema-rooming.d.ts.map +1 -0
- package/dist/schema-rooming.js +47 -0
- package/dist/schema.d.ts +4 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +3 -0
- package/dist/service-delegates.d.ts +40 -0
- package/dist/service-delegates.d.ts.map +1 -0
- package/dist/service-delegates.js +107 -0
- package/dist/service-rooming.d.ts +50 -0
- package/dist/service-rooming.d.ts.map +1 -0
- package/dist/service-rooming.js +102 -0
- package/dist/validation-delegates.d.ts +109 -0
- package/dist/validation-delegates.d.ts.map +1 -0
- package/dist/validation-delegates.js +41 -0
- package/dist/validation-rooming.d.ts +37 -0
- package/dist/validation-rooming.d.ts.map +1 -0
- package/dist/validation-rooming.js +28 -0
- package/dist/validation-sessions.d.ts +1 -1
- package/migrations/0002_mice_baseline.sql +86 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +8 -3
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* First-class rooming manifest (§9-Q3) — program-centric, replacing the
|
|
3
|
+
* fragmented roomTypeId + sharingGroupId + allocations-JSONB on booking
|
|
4
|
+
* traveler details. A shared room is one assignment with MANY delegates via the
|
|
5
|
+
* explicit join (§9-Q5). See RFC voyant#1489 (Phase 3).
|
|
6
|
+
*/
|
|
7
|
+
export declare const roomingAssignments: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
8
|
+
name: "mice_rooming_assignments";
|
|
9
|
+
schema: undefined;
|
|
10
|
+
columns: {
|
|
11
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
12
|
+
name: string;
|
|
13
|
+
tableName: "mice_rooming_assignments";
|
|
14
|
+
dataType: "string";
|
|
15
|
+
columnType: "PgText";
|
|
16
|
+
data: string;
|
|
17
|
+
driverParam: string;
|
|
18
|
+
notNull: true;
|
|
19
|
+
hasDefault: true;
|
|
20
|
+
isPrimaryKey: true;
|
|
21
|
+
isAutoincrement: false;
|
|
22
|
+
hasRuntimeDefault: true;
|
|
23
|
+
enumValues: [string, ...string[]];
|
|
24
|
+
baseColumn: never;
|
|
25
|
+
identity: undefined;
|
|
26
|
+
generated: undefined;
|
|
27
|
+
}, {}, {}>;
|
|
28
|
+
programId: import("drizzle-orm/pg-core").PgColumn<{
|
|
29
|
+
name: string;
|
|
30
|
+
tableName: "mice_rooming_assignments";
|
|
31
|
+
dataType: "string";
|
|
32
|
+
columnType: "PgText";
|
|
33
|
+
data: string;
|
|
34
|
+
driverParam: string;
|
|
35
|
+
notNull: true;
|
|
36
|
+
hasDefault: false;
|
|
37
|
+
isPrimaryKey: false;
|
|
38
|
+
isAutoincrement: false;
|
|
39
|
+
hasRuntimeDefault: false;
|
|
40
|
+
enumValues: [string, ...string[]];
|
|
41
|
+
baseColumn: never;
|
|
42
|
+
identity: undefined;
|
|
43
|
+
generated: undefined;
|
|
44
|
+
}, {}, {}>;
|
|
45
|
+
roomBlockId: import("drizzle-orm/pg-core").PgColumn<{
|
|
46
|
+
name: string;
|
|
47
|
+
tableName: "mice_rooming_assignments";
|
|
48
|
+
dataType: "string";
|
|
49
|
+
columnType: "PgText";
|
|
50
|
+
data: string;
|
|
51
|
+
driverParam: string;
|
|
52
|
+
notNull: false;
|
|
53
|
+
hasDefault: false;
|
|
54
|
+
isPrimaryKey: false;
|
|
55
|
+
isAutoincrement: false;
|
|
56
|
+
hasRuntimeDefault: false;
|
|
57
|
+
enumValues: [string, ...string[]];
|
|
58
|
+
baseColumn: never;
|
|
59
|
+
identity: undefined;
|
|
60
|
+
generated: undefined;
|
|
61
|
+
}, {}, {}>;
|
|
62
|
+
roomTypeId: import("drizzle-orm/pg-core").PgColumn<{
|
|
63
|
+
name: string;
|
|
64
|
+
tableName: "mice_rooming_assignments";
|
|
65
|
+
dataType: "string";
|
|
66
|
+
columnType: "PgText";
|
|
67
|
+
data: string;
|
|
68
|
+
driverParam: string;
|
|
69
|
+
notNull: false;
|
|
70
|
+
hasDefault: false;
|
|
71
|
+
isPrimaryKey: false;
|
|
72
|
+
isAutoincrement: false;
|
|
73
|
+
hasRuntimeDefault: false;
|
|
74
|
+
enumValues: [string, ...string[]];
|
|
75
|
+
baseColumn: never;
|
|
76
|
+
identity: undefined;
|
|
77
|
+
generated: undefined;
|
|
78
|
+
}, {}, {}>;
|
|
79
|
+
bedConfig: import("drizzle-orm/pg-core").PgColumn<{
|
|
80
|
+
name: "bed_config";
|
|
81
|
+
tableName: "mice_rooming_assignments";
|
|
82
|
+
dataType: "string";
|
|
83
|
+
columnType: "PgText";
|
|
84
|
+
data: string;
|
|
85
|
+
driverParam: string;
|
|
86
|
+
notNull: false;
|
|
87
|
+
hasDefault: false;
|
|
88
|
+
isPrimaryKey: false;
|
|
89
|
+
isAutoincrement: false;
|
|
90
|
+
hasRuntimeDefault: false;
|
|
91
|
+
enumValues: [string, ...string[]];
|
|
92
|
+
baseColumn: never;
|
|
93
|
+
identity: undefined;
|
|
94
|
+
generated: undefined;
|
|
95
|
+
}, {}, {}>;
|
|
96
|
+
sharingGroupId: import("drizzle-orm/pg-core").PgColumn<{
|
|
97
|
+
name: "sharing_group_id";
|
|
98
|
+
tableName: "mice_rooming_assignments";
|
|
99
|
+
dataType: "string";
|
|
100
|
+
columnType: "PgText";
|
|
101
|
+
data: string;
|
|
102
|
+
driverParam: string;
|
|
103
|
+
notNull: false;
|
|
104
|
+
hasDefault: false;
|
|
105
|
+
isPrimaryKey: false;
|
|
106
|
+
isAutoincrement: false;
|
|
107
|
+
hasRuntimeDefault: false;
|
|
108
|
+
enumValues: [string, ...string[]];
|
|
109
|
+
baseColumn: never;
|
|
110
|
+
identity: undefined;
|
|
111
|
+
generated: undefined;
|
|
112
|
+
}, {}, {}>;
|
|
113
|
+
checkIn: import("drizzle-orm/pg-core").PgColumn<{
|
|
114
|
+
name: "check_in";
|
|
115
|
+
tableName: "mice_rooming_assignments";
|
|
116
|
+
dataType: "string";
|
|
117
|
+
columnType: "PgDateString";
|
|
118
|
+
data: string;
|
|
119
|
+
driverParam: string;
|
|
120
|
+
notNull: false;
|
|
121
|
+
hasDefault: false;
|
|
122
|
+
isPrimaryKey: false;
|
|
123
|
+
isAutoincrement: false;
|
|
124
|
+
hasRuntimeDefault: false;
|
|
125
|
+
enumValues: undefined;
|
|
126
|
+
baseColumn: never;
|
|
127
|
+
identity: undefined;
|
|
128
|
+
generated: undefined;
|
|
129
|
+
}, {}, {}>;
|
|
130
|
+
checkOut: import("drizzle-orm/pg-core").PgColumn<{
|
|
131
|
+
name: "check_out";
|
|
132
|
+
tableName: "mice_rooming_assignments";
|
|
133
|
+
dataType: "string";
|
|
134
|
+
columnType: "PgDateString";
|
|
135
|
+
data: string;
|
|
136
|
+
driverParam: string;
|
|
137
|
+
notNull: false;
|
|
138
|
+
hasDefault: false;
|
|
139
|
+
isPrimaryKey: false;
|
|
140
|
+
isAutoincrement: false;
|
|
141
|
+
hasRuntimeDefault: false;
|
|
142
|
+
enumValues: undefined;
|
|
143
|
+
baseColumn: never;
|
|
144
|
+
identity: undefined;
|
|
145
|
+
generated: undefined;
|
|
146
|
+
}, {}, {}>;
|
|
147
|
+
specialRequests: import("drizzle-orm/pg-core").PgColumn<{
|
|
148
|
+
name: "special_requests";
|
|
149
|
+
tableName: "mice_rooming_assignments";
|
|
150
|
+
dataType: "string";
|
|
151
|
+
columnType: "PgText";
|
|
152
|
+
data: string;
|
|
153
|
+
driverParam: string;
|
|
154
|
+
notNull: false;
|
|
155
|
+
hasDefault: false;
|
|
156
|
+
isPrimaryKey: false;
|
|
157
|
+
isAutoincrement: false;
|
|
158
|
+
hasRuntimeDefault: false;
|
|
159
|
+
enumValues: [string, ...string[]];
|
|
160
|
+
baseColumn: never;
|
|
161
|
+
identity: undefined;
|
|
162
|
+
generated: undefined;
|
|
163
|
+
}, {}, {}>;
|
|
164
|
+
metadata: import("drizzle-orm/pg-core").PgColumn<{
|
|
165
|
+
name: "metadata";
|
|
166
|
+
tableName: "mice_rooming_assignments";
|
|
167
|
+
dataType: "json";
|
|
168
|
+
columnType: "PgJsonb";
|
|
169
|
+
data: Record<string, unknown>;
|
|
170
|
+
driverParam: unknown;
|
|
171
|
+
notNull: false;
|
|
172
|
+
hasDefault: false;
|
|
173
|
+
isPrimaryKey: false;
|
|
174
|
+
isAutoincrement: false;
|
|
175
|
+
hasRuntimeDefault: false;
|
|
176
|
+
enumValues: undefined;
|
|
177
|
+
baseColumn: never;
|
|
178
|
+
identity: undefined;
|
|
179
|
+
generated: undefined;
|
|
180
|
+
}, {}, {
|
|
181
|
+
$type: Record<string, unknown>;
|
|
182
|
+
}>;
|
|
183
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
184
|
+
name: "created_at";
|
|
185
|
+
tableName: "mice_rooming_assignments";
|
|
186
|
+
dataType: "date";
|
|
187
|
+
columnType: "PgTimestamp";
|
|
188
|
+
data: Date;
|
|
189
|
+
driverParam: string;
|
|
190
|
+
notNull: true;
|
|
191
|
+
hasDefault: true;
|
|
192
|
+
isPrimaryKey: false;
|
|
193
|
+
isAutoincrement: false;
|
|
194
|
+
hasRuntimeDefault: false;
|
|
195
|
+
enumValues: undefined;
|
|
196
|
+
baseColumn: never;
|
|
197
|
+
identity: undefined;
|
|
198
|
+
generated: undefined;
|
|
199
|
+
}, {}, {}>;
|
|
200
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
201
|
+
name: "updated_at";
|
|
202
|
+
tableName: "mice_rooming_assignments";
|
|
203
|
+
dataType: "date";
|
|
204
|
+
columnType: "PgTimestamp";
|
|
205
|
+
data: Date;
|
|
206
|
+
driverParam: string;
|
|
207
|
+
notNull: true;
|
|
208
|
+
hasDefault: true;
|
|
209
|
+
isPrimaryKey: false;
|
|
210
|
+
isAutoincrement: false;
|
|
211
|
+
hasRuntimeDefault: false;
|
|
212
|
+
enumValues: undefined;
|
|
213
|
+
baseColumn: never;
|
|
214
|
+
identity: undefined;
|
|
215
|
+
generated: undefined;
|
|
216
|
+
}, {}, {}>;
|
|
217
|
+
};
|
|
218
|
+
dialect: "pg";
|
|
219
|
+
}>;
|
|
220
|
+
export declare const roomingAssignmentDelegates: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
221
|
+
name: "mice_rooming_assignment_delegates";
|
|
222
|
+
schema: undefined;
|
|
223
|
+
columns: {
|
|
224
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
225
|
+
name: string;
|
|
226
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
227
|
+
dataType: "string";
|
|
228
|
+
columnType: "PgText";
|
|
229
|
+
data: string;
|
|
230
|
+
driverParam: string;
|
|
231
|
+
notNull: true;
|
|
232
|
+
hasDefault: true;
|
|
233
|
+
isPrimaryKey: true;
|
|
234
|
+
isAutoincrement: false;
|
|
235
|
+
hasRuntimeDefault: true;
|
|
236
|
+
enumValues: [string, ...string[]];
|
|
237
|
+
baseColumn: never;
|
|
238
|
+
identity: undefined;
|
|
239
|
+
generated: undefined;
|
|
240
|
+
}, {}, {}>;
|
|
241
|
+
roomingAssignmentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
242
|
+
name: string;
|
|
243
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
244
|
+
dataType: "string";
|
|
245
|
+
columnType: "PgText";
|
|
246
|
+
data: string;
|
|
247
|
+
driverParam: string;
|
|
248
|
+
notNull: true;
|
|
249
|
+
hasDefault: false;
|
|
250
|
+
isPrimaryKey: false;
|
|
251
|
+
isAutoincrement: false;
|
|
252
|
+
hasRuntimeDefault: false;
|
|
253
|
+
enumValues: [string, ...string[]];
|
|
254
|
+
baseColumn: never;
|
|
255
|
+
identity: undefined;
|
|
256
|
+
generated: undefined;
|
|
257
|
+
}, {}, {}>;
|
|
258
|
+
delegateId: import("drizzle-orm/pg-core").PgColumn<{
|
|
259
|
+
name: string;
|
|
260
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
261
|
+
dataType: "string";
|
|
262
|
+
columnType: "PgText";
|
|
263
|
+
data: string;
|
|
264
|
+
driverParam: string;
|
|
265
|
+
notNull: true;
|
|
266
|
+
hasDefault: false;
|
|
267
|
+
isPrimaryKey: false;
|
|
268
|
+
isAutoincrement: false;
|
|
269
|
+
hasRuntimeDefault: false;
|
|
270
|
+
enumValues: [string, ...string[]];
|
|
271
|
+
baseColumn: never;
|
|
272
|
+
identity: undefined;
|
|
273
|
+
generated: undefined;
|
|
274
|
+
}, {}, {}>;
|
|
275
|
+
isPrimary: import("drizzle-orm/pg-core").PgColumn<{
|
|
276
|
+
name: "is_primary";
|
|
277
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
278
|
+
dataType: "boolean";
|
|
279
|
+
columnType: "PgBoolean";
|
|
280
|
+
data: boolean;
|
|
281
|
+
driverParam: boolean;
|
|
282
|
+
notNull: true;
|
|
283
|
+
hasDefault: true;
|
|
284
|
+
isPrimaryKey: false;
|
|
285
|
+
isAutoincrement: false;
|
|
286
|
+
hasRuntimeDefault: false;
|
|
287
|
+
enumValues: undefined;
|
|
288
|
+
baseColumn: never;
|
|
289
|
+
identity: undefined;
|
|
290
|
+
generated: undefined;
|
|
291
|
+
}, {}, {}>;
|
|
292
|
+
bedLabel: import("drizzle-orm/pg-core").PgColumn<{
|
|
293
|
+
name: "bed_label";
|
|
294
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
295
|
+
dataType: "string";
|
|
296
|
+
columnType: "PgText";
|
|
297
|
+
data: string;
|
|
298
|
+
driverParam: string;
|
|
299
|
+
notNull: false;
|
|
300
|
+
hasDefault: false;
|
|
301
|
+
isPrimaryKey: false;
|
|
302
|
+
isAutoincrement: false;
|
|
303
|
+
hasRuntimeDefault: false;
|
|
304
|
+
enumValues: [string, ...string[]];
|
|
305
|
+
baseColumn: never;
|
|
306
|
+
identity: undefined;
|
|
307
|
+
generated: undefined;
|
|
308
|
+
}, {}, {}>;
|
|
309
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
310
|
+
name: "created_at";
|
|
311
|
+
tableName: "mice_rooming_assignment_delegates";
|
|
312
|
+
dataType: "date";
|
|
313
|
+
columnType: "PgTimestamp";
|
|
314
|
+
data: Date;
|
|
315
|
+
driverParam: string;
|
|
316
|
+
notNull: true;
|
|
317
|
+
hasDefault: true;
|
|
318
|
+
isPrimaryKey: false;
|
|
319
|
+
isAutoincrement: false;
|
|
320
|
+
hasRuntimeDefault: false;
|
|
321
|
+
enumValues: undefined;
|
|
322
|
+
baseColumn: never;
|
|
323
|
+
identity: undefined;
|
|
324
|
+
generated: undefined;
|
|
325
|
+
}, {}, {}>;
|
|
326
|
+
};
|
|
327
|
+
dialect: "pg";
|
|
328
|
+
}>;
|
|
329
|
+
export type RoomingAssignment = typeof roomingAssignments.$inferSelect;
|
|
330
|
+
export type NewRoomingAssignment = typeof roomingAssignments.$inferInsert;
|
|
331
|
+
export type RoomingAssignmentDelegate = typeof roomingAssignmentDelegates.$inferSelect;
|
|
332
|
+
export type NewRoomingAssignmentDelegate = typeof roomingAssignmentDelegates.$inferInsert;
|
|
333
|
+
//# sourceMappingURL=schema-rooming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-rooming.d.ts","sourceRoot":"","sources":["../src/schema-rooming.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwB9B,CAAA;AAED,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsBtC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,yBAAyB,GAAG,OAAO,0BAA0B,CAAC,YAAY,CAAA;AACtF,MAAM,MAAM,4BAA4B,GAAG,OAAO,0BAA0B,CAAC,YAAY,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { typeId, typeIdRef } from "@voyant-travel/db/lib/typeid-column";
|
|
2
|
+
import { boolean, date, index, jsonb, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
|
|
3
|
+
import { programs } from "./schema.js";
|
|
4
|
+
import { programDelegates } from "./schema-delegates.js";
|
|
5
|
+
/**
|
|
6
|
+
* First-class rooming manifest (§9-Q3) — program-centric, replacing the
|
|
7
|
+
* fragmented roomTypeId + sharingGroupId + allocations-JSONB on booking
|
|
8
|
+
* traveler details. A shared room is one assignment with MANY delegates via the
|
|
9
|
+
* explicit join (§9-Q5). See RFC voyant#1489 (Phase 3).
|
|
10
|
+
*/
|
|
11
|
+
export const roomingAssignments = pgTable("mice_rooming_assignments", {
|
|
12
|
+
id: typeId("mice_rooming_assignments"),
|
|
13
|
+
// Intra-package FK:
|
|
14
|
+
programId: typeIdRef("program_id")
|
|
15
|
+
.notNull()
|
|
16
|
+
.references(() => programs.id, { onDelete: "cascade" }),
|
|
17
|
+
// Cross-package → loose columns + defineLink at the deployment:
|
|
18
|
+
roomBlockId: typeIdRef("room_block_id"), // → accommodations.roomBlocks
|
|
19
|
+
roomTypeId: typeIdRef("room_type_id"), // → accommodations.roomTypes
|
|
20
|
+
bedConfig: text("bed_config"),
|
|
21
|
+
sharingGroupId: text("sharing_group_id"),
|
|
22
|
+
checkIn: date("check_in"),
|
|
23
|
+
checkOut: date("check_out"),
|
|
24
|
+
specialRequests: text("special_requests"),
|
|
25
|
+
metadata: jsonb("metadata").$type(),
|
|
26
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
27
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
28
|
+
}, (table) => [
|
|
29
|
+
index("idx_mice_rooming_assignments_program").on(table.programId),
|
|
30
|
+
index("idx_mice_rooming_assignments_room_block").on(table.roomBlockId),
|
|
31
|
+
]);
|
|
32
|
+
export const roomingAssignmentDelegates = pgTable("mice_rooming_assignment_delegates", {
|
|
33
|
+
id: typeId("mice_rooming_assignment_delegates"),
|
|
34
|
+
roomingAssignmentId: typeIdRef("rooming_assignment_id")
|
|
35
|
+
.notNull()
|
|
36
|
+
.references(() => roomingAssignments.id, { onDelete: "cascade" }),
|
|
37
|
+
delegateId: typeIdRef("delegate_id")
|
|
38
|
+
.notNull()
|
|
39
|
+
.references(() => programDelegates.id, { onDelete: "cascade" }),
|
|
40
|
+
isPrimary: boolean("is_primary").notNull().default(false),
|
|
41
|
+
bedLabel: text("bed_label"),
|
|
42
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
43
|
+
}, (table) => [
|
|
44
|
+
index("idx_mice_rooming_assignment_delegates_assignment").on(table.roomingAssignmentId),
|
|
45
|
+
// A delegate appears at most once per rooming assignment.
|
|
46
|
+
uniqueIndex("uidx_mice_rooming_assignment_delegates_pair").on(table.roomingAssignmentId, table.delegateId),
|
|
47
|
+
]);
|
package/dist/schema.d.ts
CHANGED
|
@@ -326,5 +326,9 @@ export declare const programs: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
326
326
|
}>;
|
|
327
327
|
export type Program = typeof programs.$inferSelect;
|
|
328
328
|
export type NewProgram = typeof programs.$inferInsert;
|
|
329
|
+
export type { BookingMiceDetail, NewBookingMiceDetail } from "./booking-extension.js";
|
|
330
|
+
export { bookingMiceDetails } from "./booking-extension.js";
|
|
331
|
+
export * from "./schema-delegates.js";
|
|
332
|
+
export * from "./schema-rooming.js";
|
|
329
333
|
export * from "./schema-sessions.js";
|
|
330
334
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,qGAM1B,CAAA;AAEF,eAAO,MAAM,iBAAiB,iHAO5B,CAAA;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BpB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,cAAc,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,qGAM1B,CAAA;AAEF,eAAO,MAAM,iBAAiB,iHAO5B,CAAA;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BpB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA"}
|
package/dist/schema.js
CHANGED
|
@@ -48,4 +48,7 @@ export const programs = pgTable("mice_programs", {
|
|
|
48
48
|
index("idx_mice_programs_status").on(table.status),
|
|
49
49
|
index("idx_mice_programs_dates").on(table.startDate, table.endDate),
|
|
50
50
|
]);
|
|
51
|
+
export { bookingMiceDetails } from "./booking-extension.js";
|
|
52
|
+
export * from "./schema-delegates.js";
|
|
53
|
+
export * from "./schema-rooming.js";
|
|
51
54
|
export * from "./schema-sessions.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
|
+
import { type DelegateSessionEnrollment, type ProgramDelegate } from "./schema-delegates.js";
|
|
3
|
+
import type { CreateDelegateBody, DelegateListQuery, EnrollDelegateBody, UpdateDelegateBody } from "./validation-delegates.js";
|
|
4
|
+
export type CreateDelegateOutcome = {
|
|
5
|
+
status: "ok";
|
|
6
|
+
delegate: ProgramDelegate;
|
|
7
|
+
} | {
|
|
8
|
+
status: "program_not_found";
|
|
9
|
+
};
|
|
10
|
+
export declare function createDelegate(db: PostgresJsDatabase, input: CreateDelegateBody): Promise<CreateDelegateOutcome>;
|
|
11
|
+
export declare function getDelegate(db: PostgresJsDatabase, id: string): Promise<(ProgramDelegate & {
|
|
12
|
+
enrollments: DelegateSessionEnrollment[];
|
|
13
|
+
}) | null>;
|
|
14
|
+
export declare function listDelegates(db: PostgresJsDatabase, query: DelegateListQuery): Promise<{
|
|
15
|
+
data: ProgramDelegate[];
|
|
16
|
+
limit: number;
|
|
17
|
+
offset: number;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function updateDelegate(db: PostgresJsDatabase, id: string, input: UpdateDelegateBody): Promise<ProgramDelegate | null>;
|
|
20
|
+
export type EnrollDelegateOutcome = {
|
|
21
|
+
status: "ok";
|
|
22
|
+
enrollment: DelegateSessionEnrollment;
|
|
23
|
+
idempotent: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
status: "delegate_not_found";
|
|
26
|
+
} | {
|
|
27
|
+
status: "session_not_found";
|
|
28
|
+
} | {
|
|
29
|
+
status: "program_mismatch";
|
|
30
|
+
};
|
|
31
|
+
/** Enroll a delegate in a session. Idempotent on (delegate, session). */
|
|
32
|
+
export declare function enrollDelegate(db: PostgresJsDatabase, delegateId: string, input: EnrollDelegateBody): Promise<EnrollDelegateOutcome>;
|
|
33
|
+
export declare const delegateService: {
|
|
34
|
+
createDelegate: typeof createDelegate;
|
|
35
|
+
getDelegate: typeof getDelegate;
|
|
36
|
+
listDelegates: typeof listDelegates;
|
|
37
|
+
updateDelegate: typeof updateDelegate;
|
|
38
|
+
enrollDelegate: typeof enrollDelegate;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=service-delegates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-delegates.d.ts","sourceRoot":"","sources":["../src/service-delegates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EACL,KAAK,yBAAyB,EAE9B,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,2BAA2B,CAAA;AAYlC,MAAM,MAAM,qBAAqB,GAC7B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAA;AAEnC,wBAAsB,cAAc,CAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,CAAC,eAAe,GAAG;IAAE,WAAW,EAAE,yBAAyB,EAAE,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CAYlF;AAED,wBAAsB,aAAa,CACjC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC;IAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAYrE;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAOjC;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,yBAAyB,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAC5E;IAAE,MAAM,EAAE,oBAAoB,CAAA;CAAE,GAChC;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAElC,yEAAyE;AACzE,wBAAsB,cAAc,CAClC,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,qBAAqB,CAAC,CAqChC;AAED,eAAO,MAAM,eAAe;;;;;;CAM3B,CAAA"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { and, asc, eq } from "drizzle-orm";
|
|
2
|
+
import { programs } from "./schema.js";
|
|
3
|
+
import { delegateSessionEnrollments, programDelegates, } from "./schema-delegates.js";
|
|
4
|
+
import { programSessions } from "./schema-sessions.js";
|
|
5
|
+
/** Coerce ISO datetime strings (from validation) into Date for timestamp columns. */
|
|
6
|
+
function withTimestamps(input) {
|
|
7
|
+
const { arrivalAt, departureAt, ...rest } = input;
|
|
8
|
+
return {
|
|
9
|
+
...rest,
|
|
10
|
+
...(arrivalAt !== undefined ? { arrivalAt: new Date(arrivalAt) } : {}),
|
|
11
|
+
...(departureAt !== undefined ? { departureAt: new Date(departureAt) } : {}),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function createDelegate(db, input) {
|
|
15
|
+
const [program] = await db
|
|
16
|
+
.select({ id: programs.id })
|
|
17
|
+
.from(programs)
|
|
18
|
+
.where(eq(programs.id, input.programId))
|
|
19
|
+
.limit(1);
|
|
20
|
+
if (!program)
|
|
21
|
+
return { status: "program_not_found" };
|
|
22
|
+
const [delegate] = await db.insert(programDelegates).values(withTimestamps(input)).returning();
|
|
23
|
+
if (!delegate)
|
|
24
|
+
throw new Error("createDelegate: insert returned no rows");
|
|
25
|
+
return { status: "ok", delegate };
|
|
26
|
+
}
|
|
27
|
+
export async function getDelegate(db, id) {
|
|
28
|
+
const [delegate] = await db
|
|
29
|
+
.select()
|
|
30
|
+
.from(programDelegates)
|
|
31
|
+
.where(eq(programDelegates.id, id))
|
|
32
|
+
.limit(1);
|
|
33
|
+
if (!delegate)
|
|
34
|
+
return null;
|
|
35
|
+
const enrollments = await db
|
|
36
|
+
.select()
|
|
37
|
+
.from(delegateSessionEnrollments)
|
|
38
|
+
.where(eq(delegateSessionEnrollments.delegateId, id));
|
|
39
|
+
return { ...delegate, enrollments };
|
|
40
|
+
}
|
|
41
|
+
export async function listDelegates(db, query) {
|
|
42
|
+
const conditions = [eq(programDelegates.programId, query.programId)];
|
|
43
|
+
if (query.status)
|
|
44
|
+
conditions.push(eq(programDelegates.status, query.status));
|
|
45
|
+
if (query.role)
|
|
46
|
+
conditions.push(eq(programDelegates.role, query.role));
|
|
47
|
+
const data = await db
|
|
48
|
+
.select()
|
|
49
|
+
.from(programDelegates)
|
|
50
|
+
.where(and(...conditions))
|
|
51
|
+
.orderBy(asc(programDelegates.createdAt))
|
|
52
|
+
.limit(query.limit)
|
|
53
|
+
.offset(query.offset);
|
|
54
|
+
return { data, limit: query.limit, offset: query.offset };
|
|
55
|
+
}
|
|
56
|
+
export async function updateDelegate(db, id, input) {
|
|
57
|
+
const [delegate] = await db
|
|
58
|
+
.update(programDelegates)
|
|
59
|
+
.set({ ...withTimestamps(input), updatedAt: new Date() })
|
|
60
|
+
.where(eq(programDelegates.id, id))
|
|
61
|
+
.returning();
|
|
62
|
+
return delegate ?? null;
|
|
63
|
+
}
|
|
64
|
+
/** Enroll a delegate in a session. Idempotent on (delegate, session). */
|
|
65
|
+
export async function enrollDelegate(db, delegateId, input) {
|
|
66
|
+
return db.transaction(async (tx) => {
|
|
67
|
+
const [delegate] = await tx
|
|
68
|
+
.select({ id: programDelegates.id, programId: programDelegates.programId })
|
|
69
|
+
.from(programDelegates)
|
|
70
|
+
.where(eq(programDelegates.id, delegateId))
|
|
71
|
+
.limit(1);
|
|
72
|
+
if (!delegate)
|
|
73
|
+
return { status: "delegate_not_found" };
|
|
74
|
+
const [session] = await tx
|
|
75
|
+
.select({ id: programSessions.id, programId: programSessions.programId })
|
|
76
|
+
.from(programSessions)
|
|
77
|
+
.where(eq(programSessions.id, input.sessionId))
|
|
78
|
+
.limit(1);
|
|
79
|
+
if (!session)
|
|
80
|
+
return { status: "session_not_found" };
|
|
81
|
+
// The session must belong to the delegate's program — neither the FK nor the
|
|
82
|
+
// unique index includes program_id, so guard against cross-program enrollment.
|
|
83
|
+
if (session.programId !== delegate.programId)
|
|
84
|
+
return { status: "program_mismatch" };
|
|
85
|
+
const [existing] = await tx
|
|
86
|
+
.select()
|
|
87
|
+
.from(delegateSessionEnrollments)
|
|
88
|
+
.where(and(eq(delegateSessionEnrollments.delegateId, delegateId), eq(delegateSessionEnrollments.sessionId, input.sessionId)))
|
|
89
|
+
.limit(1);
|
|
90
|
+
if (existing)
|
|
91
|
+
return { status: "ok", enrollment: existing, idempotent: true };
|
|
92
|
+
const [enrollment] = await tx
|
|
93
|
+
.insert(delegateSessionEnrollments)
|
|
94
|
+
.values({ delegateId, sessionId: input.sessionId, status: input.status })
|
|
95
|
+
.returning();
|
|
96
|
+
if (!enrollment)
|
|
97
|
+
throw new Error("enrollDelegate: insert returned no rows");
|
|
98
|
+
return { status: "ok", enrollment, idempotent: false };
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
export const delegateService = {
|
|
102
|
+
createDelegate,
|
|
103
|
+
getDelegate,
|
|
104
|
+
listDelegates,
|
|
105
|
+
updateDelegate,
|
|
106
|
+
enrollDelegate,
|
|
107
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
|
+
import { type RoomingAssignment, type RoomingAssignmentDelegate } from "./schema-rooming.js";
|
|
3
|
+
import type { CreateRoomingAssignmentBody, RoomingDelegateInput, UpdateRoomingAssignmentBody } from "./validation-rooming.js";
|
|
4
|
+
export type CreateRoomingAssignmentOutcome = {
|
|
5
|
+
status: "ok";
|
|
6
|
+
assignment: RoomingAssignment;
|
|
7
|
+
} | {
|
|
8
|
+
status: "program_not_found";
|
|
9
|
+
};
|
|
10
|
+
export declare function createRoomingAssignment(db: PostgresJsDatabase, input: CreateRoomingAssignmentBody): Promise<CreateRoomingAssignmentOutcome>;
|
|
11
|
+
export declare function getRoomingAssignment(db: PostgresJsDatabase, id: string): Promise<(RoomingAssignment & {
|
|
12
|
+
delegates: RoomingAssignmentDelegate[];
|
|
13
|
+
}) | null>;
|
|
14
|
+
export declare function listRoomingAssignments(db: PostgresJsDatabase, query: {
|
|
15
|
+
programId: string;
|
|
16
|
+
limit: number;
|
|
17
|
+
offset: number;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
data: RoomingAssignment[];
|
|
20
|
+
limit: number;
|
|
21
|
+
offset: number;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function updateRoomingAssignment(db: PostgresJsDatabase, id: string, input: UpdateRoomingAssignmentBody): Promise<RoomingAssignment | null>;
|
|
24
|
+
export type SetRoomingDelegatesOutcome = {
|
|
25
|
+
status: "ok";
|
|
26
|
+
delegates: RoomingAssignmentDelegate[];
|
|
27
|
+
} | {
|
|
28
|
+
status: "assignment_not_found";
|
|
29
|
+
} | {
|
|
30
|
+
status: "delegate_not_found";
|
|
31
|
+
missing: string[];
|
|
32
|
+
} | {
|
|
33
|
+
status: "program_mismatch";
|
|
34
|
+
offending: string[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Replace the occupants of a rooming assignment (full replace). Validates the
|
|
38
|
+
* assignment and that every delegate exists AND belongs to the assignment's
|
|
39
|
+
* program before touching the join — a stale id is a 4xx (not an FK 500) and a
|
|
40
|
+
* cross-program delegate can't corrupt the program-scoped manifest.
|
|
41
|
+
*/
|
|
42
|
+
export declare function setRoomingDelegates(db: PostgresJsDatabase, assignmentId: string, delegates: RoomingDelegateInput[]): Promise<SetRoomingDelegatesOutcome>;
|
|
43
|
+
export declare const roomingService: {
|
|
44
|
+
createRoomingAssignment: typeof createRoomingAssignment;
|
|
45
|
+
getRoomingAssignment: typeof getRoomingAssignment;
|
|
46
|
+
listRoomingAssignments: typeof listRoomingAssignments;
|
|
47
|
+
updateRoomingAssignment: typeof updateRoomingAssignment;
|
|
48
|
+
setRoomingDelegates: typeof setRoomingDelegates;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=service-rooming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-rooming.d.ts","sourceRoot":"","sources":["../src/service-rooming.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAG/B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EACV,2BAA2B,EAC3B,oBAAoB,EACpB,2BAA2B,EAC5B,MAAM,yBAAyB,CAAA;AAEhC,MAAM,MAAM,8BAA8B,GACtC;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAA;AAEnC,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,8BAA8B,CAAC,CAUzC;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,CAAC,iBAAiB,GAAG;IAAE,SAAS,EAAE,yBAAyB,EAAE,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CAYlF;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC;IAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CASvE;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAOnC;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,yBAAyB,EAAE,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,sBAAsB,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAEvD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,kBAAkB,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,oBAAoB,EAAE,GAChC,OAAO,CAAC,0BAA0B,CAAC,CAuCrC;AAED,eAAO,MAAM,cAAc;;;;;;CAM1B,CAAA"}
|