@voyant-travel/inventory 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring/clone-content.d.ts +1 -0
- package/dist/authoring/clone-content.d.ts.map +1 -1
- package/dist/authoring/clone-content.js +35 -3
- package/dist/authoring/clone.d.ts.map +1 -1
- package/dist/authoring/clone.js +1 -0
- package/dist/interface.d.ts +299 -1
- package/dist/interface.d.ts.map +1 -1
- package/dist/routes-itinerary-translations.d.ts +301 -0
- package/dist/routes-itinerary-translations.d.ts.map +1 -0
- package/dist/routes-itinerary-translations.js +168 -0
- package/dist/routes-itinerary.d.ts +1 -1
- package/dist/routes.d.ts +299 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +2 -0
- package/dist/schema-itinerary.d.ts +256 -0
- package/dist/schema-itinerary.d.ts.map +1 -1
- package/dist/schema-itinerary.js +30 -0
- package/dist/schema-relations.d.ts +12 -0
- package/dist/schema-relations.d.ts.map +1 -1
- package/dist/schema-relations.js +20 -2
- package/dist/service-content-owned.d.ts +2 -6
- package/dist/service-content-owned.d.ts.map +1 -1
- package/dist/service-content-owned.js +80 -20
- package/dist/service-itinerary-translations.d.ts +122 -0
- package/dist/service-itinerary-translations.d.ts.map +1 -0
- package/dist/service-itinerary-translations.js +176 -0
- package/dist/service-option-translations.d.ts +1 -1
- package/dist/service.d.ts +136 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +2 -0
- package/migrations/0001_inventory_baseline.sql +28 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +2 -2
|
@@ -62,15 +62,27 @@ export declare const optionUnitTranslationsRelations: import("drizzle-orm").Rela
|
|
|
62
62
|
}>;
|
|
63
63
|
export declare const productItinerariesRelations: import("drizzle-orm").Relations<"product_itineraries", {
|
|
64
64
|
product: import("drizzle-orm").One<"products", true>;
|
|
65
|
+
translations: import("drizzle-orm").Many<"product_itinerary_translations">;
|
|
65
66
|
days: import("drizzle-orm").Many<"product_days">;
|
|
66
67
|
}>;
|
|
68
|
+
export declare const productItineraryTranslationsRelations: import("drizzle-orm").Relations<"product_itinerary_translations", {
|
|
69
|
+
itinerary: import("drizzle-orm").One<"product_itineraries", true>;
|
|
70
|
+
}>;
|
|
67
71
|
export declare const productDaysRelations: import("drizzle-orm").Relations<"product_days", {
|
|
68
72
|
itinerary: import("drizzle-orm").One<"product_itineraries", true>;
|
|
73
|
+
translations: import("drizzle-orm").Many<"product_day_translations">;
|
|
69
74
|
services: import("drizzle-orm").Many<"product_day_services">;
|
|
70
75
|
media: import("drizzle-orm").Many<"product_media">;
|
|
71
76
|
}>;
|
|
77
|
+
export declare const productDayTranslationsRelations: import("drizzle-orm").Relations<"product_day_translations", {
|
|
78
|
+
day: import("drizzle-orm").One<"product_days", true>;
|
|
79
|
+
}>;
|
|
72
80
|
export declare const productDayServicesRelations: import("drizzle-orm").Relations<"product_day_services", {
|
|
73
81
|
day: import("drizzle-orm").One<"product_days", true>;
|
|
82
|
+
translations: import("drizzle-orm").Many<"product_day_service_translations">;
|
|
83
|
+
}>;
|
|
84
|
+
export declare const productDayServiceTranslationsRelations: import("drizzle-orm").Relations<"product_day_service_translations", {
|
|
85
|
+
service: import("drizzle-orm").One<"product_day_services", true>;
|
|
74
86
|
}>;
|
|
75
87
|
export declare const productVersionsRelations: import("drizzle-orm").Relations<"product_versions", {
|
|
76
88
|
product: import("drizzle-orm").One<"products", true>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-relations.d.ts","sourceRoot":"","sources":["../src/schema-relations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema-relations.d.ts","sourceRoot":"","sources":["../src/schema-relations.ts"],"names":[],"mappings":"AAsCA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;EAsB3B,CAAA;AAEH,eAAO,MAAM,uBAAuB;;;;EAIjC,CAAA;AAEH,eAAO,MAAM,oBAAoB;;;EAG9B,CAAA;AAEH,eAAO,MAAM,kCAAkC;;EAQ9C,CAAA;AAED,eAAO,MAAM,8BAA8B;;EAKxC,CAAA;AAEH,eAAO,MAAM,kCAAkC;;EAQ9C,CAAA;AAED,eAAO,MAAM,4BAA4B;;EAKtC,CAAA;AAEH,eAAO,MAAM,+BAA+B;;EAKzC,CAAA;AAEH,eAAO,MAAM,wBAAwB;;EAKlC,CAAA;AAEH,eAAO,MAAM,oBAAoB;;EAK9B,CAAA;AAEH,eAAO,MAAM,yBAAyB;;EAKnC,CAAA;AAEH,eAAO,MAAM,4BAA4B;;EAKtC,CAAA;AAEH,eAAO,MAAM,kCAAkC;;EAQ9C,CAAA;AAED,eAAO,MAAM,+BAA+B;;EAKzC,CAAA;AAEH,eAAO,MAAM,2BAA2B;;;;EAOrC,CAAA;AAEH,eAAO,MAAM,qCAAqC;;EAQjD,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;EAQ9B,CAAA;AAEH,eAAO,MAAM,+BAA+B;;EAEzC,CAAA;AAEH,eAAO,MAAM,2BAA2B;;;EAGrC,CAAA;AAEH,eAAO,MAAM,sCAAsC;;EAQlD,CAAA;AAED,eAAO,MAAM,wBAAwB;;EAElC,CAAA;AAEH,eAAO,MAAM,qBAAqB;;EAE/B,CAAA;AAEH,eAAO,MAAM,qBAAqB;;;EAG/B,CAAA;AAEH,eAAO,MAAM,qBAAqB;;EAE/B,CAAA;AAEH,eAAO,MAAM,qBAAqB;;;;;EAS/B,CAAA;AAEH,eAAO,MAAM,gCAAgC;;EAK1C,CAAA;AAEH,eAAO,MAAM,0BAA0B;;;;EAQpC,CAAA;AAEH,eAAO,MAAM,oBAAoB;;EAE9B,CAAA;AAEH,eAAO,MAAM,gCAAgC;;;EAS1C,CAAA;AAEH,eAAO,MAAM,2BAA2B;;;EASrC,CAAA;AAEH,eAAO,MAAM,4BAA4B;;;EAStC,CAAA"}
|
package/dist/schema-relations.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { relations } from "drizzle-orm";
|
|
2
2
|
import { optionUnits, productOptions, products } from "./schema-core.js";
|
|
3
|
-
import { productDayServices, productDays, productItineraries, productMedia, productNotes, productVersions, } from "./schema-itinerary.js";
|
|
3
|
+
import { productDayServices, productDayServiceTranslations, productDays, productDayTranslations, productItineraries, productItineraryTranslations, productMedia, productNotes, productVersions, } from "./schema-itinerary.js";
|
|
4
4
|
import { optionUnitTranslations, productActivationSettings, productCapabilities, productDeliveryFormats, productFaqs, productFeatures, productLocations, productOptionTranslations, productTicketSettings, productTranslations, productVisibilitySettings, } from "./schema-settings.js";
|
|
5
5
|
import { destinations, destinationTranslations, productCategories, productCategoryProducts, productDestinations, productTagProducts, productTags, productTypes, } from "./schema-taxonomy.js";
|
|
6
6
|
export const productsRelations = relations(products, ({ one, many }) => ({
|
|
@@ -106,18 +106,36 @@ export const productItinerariesRelations = relations(productItineraries, ({ one,
|
|
|
106
106
|
fields: [productItineraries.productId],
|
|
107
107
|
references: [products.id],
|
|
108
108
|
}),
|
|
109
|
+
translations: many(productItineraryTranslations),
|
|
109
110
|
days: many(productDays),
|
|
110
111
|
}));
|
|
112
|
+
export const productItineraryTranslationsRelations = relations(productItineraryTranslations, ({ one }) => ({
|
|
113
|
+
itinerary: one(productItineraries, {
|
|
114
|
+
fields: [productItineraryTranslations.itineraryId],
|
|
115
|
+
references: [productItineraries.id],
|
|
116
|
+
}),
|
|
117
|
+
}));
|
|
111
118
|
export const productDaysRelations = relations(productDays, ({ one, many }) => ({
|
|
112
119
|
itinerary: one(productItineraries, {
|
|
113
120
|
fields: [productDays.itineraryId],
|
|
114
121
|
references: [productItineraries.id],
|
|
115
122
|
}),
|
|
123
|
+
translations: many(productDayTranslations),
|
|
116
124
|
services: many(productDayServices),
|
|
117
125
|
media: many(productMedia),
|
|
118
126
|
}));
|
|
119
|
-
export const
|
|
127
|
+
export const productDayTranslationsRelations = relations(productDayTranslations, ({ one }) => ({
|
|
128
|
+
day: one(productDays, { fields: [productDayTranslations.dayId], references: [productDays.id] }),
|
|
129
|
+
}));
|
|
130
|
+
export const productDayServicesRelations = relations(productDayServices, ({ one, many }) => ({
|
|
120
131
|
day: one(productDays, { fields: [productDayServices.dayId], references: [productDays.id] }),
|
|
132
|
+
translations: many(productDayServiceTranslations),
|
|
133
|
+
}));
|
|
134
|
+
export const productDayServiceTranslationsRelations = relations(productDayServiceTranslations, ({ one }) => ({
|
|
135
|
+
service: one(productDayServices, {
|
|
136
|
+
fields: [productDayServiceTranslations.serviceId],
|
|
137
|
+
references: [productDayServices.id],
|
|
138
|
+
}),
|
|
121
139
|
}));
|
|
122
140
|
export const productVersionsRelations = relations(productVersions, ({ one }) => ({
|
|
123
141
|
product: one(products, { fields: [productVersions.productId], references: [products.id] }),
|
|
@@ -20,15 +20,11 @@
|
|
|
20
20
|
* The projection reads in parallel:
|
|
21
21
|
* - `products` row → product summary + tags + supplier
|
|
22
22
|
* - `product_translations` → localized name + description per locale
|
|
23
|
-
* - `product_itineraries` + `product_days`
|
|
24
|
-
*
|
|
23
|
+
* - `product_itineraries` + `product_days` + translations → localized
|
|
24
|
+
* itinerary days + day service labels
|
|
25
25
|
* - `product_options` + `product_option_translations` → options +
|
|
26
26
|
* localized labels
|
|
27
27
|
* - `product_media` → hero + gallery
|
|
28
|
-
*
|
|
29
|
-
* Day translations don't exist in the schema yet — when
|
|
30
|
-
* `product_day_translations` lands, this function picks them up the
|
|
31
|
-
* same way.
|
|
32
28
|
*/
|
|
33
29
|
import type { ContentLocaleMatchKind } from "@voyant-travel/catalog";
|
|
34
30
|
import type { AnyDrizzleDb } from "@voyant-travel/db";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-content-owned.d.ts","sourceRoot":"","sources":["../src/service-content-owned.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"service-content-owned.d.ts","sourceRoot":"","sources":["../src/service-content-owned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAEpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,oBAAoB,CAAA;AAc3B,MAAM,WAAW,+BAA+B;IAC9C;;;;;OAKG;IACH,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC7C,qDAAqD;IACrD,OAAO,EAAE,cAAc,CAAA;IACvB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,EAAE,sBAAsB,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC,CA4LhD"}
|
|
@@ -20,20 +20,16 @@
|
|
|
20
20
|
* The projection reads in parallel:
|
|
21
21
|
* - `products` row → product summary + tags + supplier
|
|
22
22
|
* - `product_translations` → localized name + description per locale
|
|
23
|
-
* - `product_itineraries` + `product_days`
|
|
24
|
-
*
|
|
23
|
+
* - `product_itineraries` + `product_days` + translations → localized
|
|
24
|
+
* itinerary days + day service labels
|
|
25
25
|
* - `product_options` + `product_option_translations` → options +
|
|
26
26
|
* localized labels
|
|
27
27
|
* - `product_media` → hero + gallery
|
|
28
|
-
*
|
|
29
|
-
* Day translations don't exist in the schema yet — when
|
|
30
|
-
* `product_day_translations` lands, this function picks them up the
|
|
31
|
-
* same way.
|
|
32
28
|
*/
|
|
33
29
|
import { pickBestCachedLocale } from "@voyant-travel/catalog";
|
|
34
30
|
import { and, asc, eq, inArray, sql } from "drizzle-orm";
|
|
35
31
|
import { productContentSchema, validateProductContent, } from "./content-shape.js";
|
|
36
|
-
import { productDays, productItineraries, productMedia, productOptions, productOptionTranslations, products, productTranslations, } from "./schema.js";
|
|
32
|
+
import { productDayServices, productDayServiceTranslations, productDays, productDayTranslations, productItineraries, productMedia, productOptions, productOptionTranslations, products, productTranslations, } from "./schema.js";
|
|
37
33
|
/**
|
|
38
34
|
* Read the owned product + related rows and project to `ProductContent`,
|
|
39
35
|
* resolving translations against the supplied locale-preference chain.
|
|
@@ -71,6 +67,30 @@ export async function buildOwnedProductContent(db, entityId, options) {
|
|
|
71
67
|
.where(and(eq(productDays.itineraryId, defaultItinerary.id)))
|
|
72
68
|
.orderBy(asc(productDays.dayNumber))
|
|
73
69
|
: [];
|
|
70
|
+
const dayIds = days.map((d) => d.id);
|
|
71
|
+
const [dayTrns, dayServiceRows] = dayIds.length > 0
|
|
72
|
+
? await Promise.all([
|
|
73
|
+
db
|
|
74
|
+
.select()
|
|
75
|
+
.from(productDayTranslations)
|
|
76
|
+
.where(inArray(productDayTranslations.dayId, dayIds)),
|
|
77
|
+
db
|
|
78
|
+
.select()
|
|
79
|
+
.from(productDayServices)
|
|
80
|
+
.where(inArray(productDayServices.dayId, dayIds))
|
|
81
|
+
.orderBy(asc(productDayServices.dayId), asc(productDayServices.sortOrder)),
|
|
82
|
+
])
|
|
83
|
+
: [[], []];
|
|
84
|
+
const dayServiceIds = dayServiceRows.map((s) => s.id);
|
|
85
|
+
const dayServiceTrns = dayServiceIds.length > 0
|
|
86
|
+
? await db
|
|
87
|
+
.select()
|
|
88
|
+
.from(productDayServiceTranslations)
|
|
89
|
+
.where(inArray(productDayServiceTranslations.serviceId, dayServiceIds))
|
|
90
|
+
: [];
|
|
91
|
+
const dayTranslationsByDay = groupBy(dayTrns, (row) => row.dayId);
|
|
92
|
+
const dayServicesByDay = groupBy(dayServiceRows, (row) => row.dayId);
|
|
93
|
+
const serviceTranslationsByService = groupBy(dayServiceTrns, (row) => row.serviceId);
|
|
74
94
|
// Pull option translations in one round-trip for every option in this
|
|
75
95
|
// product. Fan-out per-option would be wasteful when products
|
|
76
96
|
// typically have a small number of options.
|
|
@@ -130,19 +150,23 @@ export async function buildOwnedProductContent(db, entityId, options) {
|
|
|
130
150
|
inclusions: [],
|
|
131
151
|
};
|
|
132
152
|
}),
|
|
133
|
-
days: days.map((d) =>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
days: days.map((d) => {
|
|
154
|
+
const bestDayTrn = pickBestDayTranslation(dayTranslationsByDay.get(d.id) ?? [], options.preferredLocales);
|
|
155
|
+
const services = (dayServicesByDay.get(d.id) ?? []).map((service) => {
|
|
156
|
+
const bestServiceTrn = pickBestDayServiceTranslation(serviceTranslationsByService.get(service.id) ?? [], options.preferredLocales);
|
|
157
|
+
return bestServiceTrn?.candidate.name ?? service.name;
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
day_number: d.dayNumber,
|
|
161
|
+
title: bestDayTrn?.candidate.title ?? d.title ?? null,
|
|
162
|
+
description: bestDayTrn?.candidate.description ?? d.description ?? null,
|
|
163
|
+
location: bestDayTrn?.candidate.location ?? d.location ?? null,
|
|
164
|
+
// Per-day hero — prefer the cover, fall back to the first sorted
|
|
165
|
+
// image attached to this day in `product_media`.
|
|
166
|
+
hero_image_url: pickDayHeroImage(mediaRows, d.id),
|
|
167
|
+
services,
|
|
168
|
+
};
|
|
169
|
+
}),
|
|
146
170
|
media: mediaRows
|
|
147
171
|
.filter((m) => !m.isBrochure)
|
|
148
172
|
.map((m) => ({
|
|
@@ -282,6 +306,28 @@ function pickBestOptionTranslation(rows, preferred) {
|
|
|
282
306
|
}));
|
|
283
307
|
return pickBestCachedLocale(candidates, preferred);
|
|
284
308
|
}
|
|
309
|
+
function pickBestDayTranslation(rows, preferred) {
|
|
310
|
+
if (rows.length === 0)
|
|
311
|
+
return null;
|
|
312
|
+
const candidates = rows.map((r) => ({
|
|
313
|
+
locale: r.languageTag,
|
|
314
|
+
title: r.title,
|
|
315
|
+
description: r.description,
|
|
316
|
+
location: r.location,
|
|
317
|
+
}));
|
|
318
|
+
return pickBestCachedLocale(candidates, preferred);
|
|
319
|
+
}
|
|
320
|
+
function pickBestDayServiceTranslation(rows, preferred) {
|
|
321
|
+
if (rows.length === 0)
|
|
322
|
+
return null;
|
|
323
|
+
const candidates = rows.map((r) => ({
|
|
324
|
+
locale: r.languageTag,
|
|
325
|
+
name: r.name,
|
|
326
|
+
description: r.description,
|
|
327
|
+
notes: r.notes,
|
|
328
|
+
}));
|
|
329
|
+
return pickBestCachedLocale(candidates, preferred);
|
|
330
|
+
}
|
|
285
331
|
/**
|
|
286
332
|
* When no translation rows exist for the product, the source row's
|
|
287
333
|
* `name` + `description` are surfaced. We don't know what locale they
|
|
@@ -327,3 +373,17 @@ function mediaType(value) {
|
|
|
327
373
|
return "document";
|
|
328
374
|
return "image";
|
|
329
375
|
}
|
|
376
|
+
function groupBy(rows, keyFor) {
|
|
377
|
+
const grouped = new Map();
|
|
378
|
+
for (const row of rows) {
|
|
379
|
+
const key = keyFor(row);
|
|
380
|
+
const bucket = grouped.get(key);
|
|
381
|
+
if (bucket) {
|
|
382
|
+
bucket.push(row);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
grouped.set(key, [row]);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return grouped;
|
|
389
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
|
+
import type { z } from "zod";
|
|
3
|
+
import type { dayServiceTranslationListQuerySchema, insertDayServiceTranslationSchema, insertProductItineraryTranslationSchema, productItineraryTranslationListQuerySchema, updateDayServiceTranslationSchema, updateProductItineraryTranslationSchema } from "./validation.js";
|
|
4
|
+
type ProductItineraryTranslationListQuery = z.infer<typeof productItineraryTranslationListQuerySchema>;
|
|
5
|
+
type CreateProductItineraryTranslationInput = z.infer<typeof insertProductItineraryTranslationSchema>;
|
|
6
|
+
type UpdateProductItineraryTranslationInput = z.infer<typeof updateProductItineraryTranslationSchema>;
|
|
7
|
+
type DayServiceTranslationListQuery = z.infer<typeof dayServiceTranslationListQuerySchema>;
|
|
8
|
+
type CreateDayServiceTranslationInput = z.infer<typeof insertDayServiceTranslationSchema>;
|
|
9
|
+
type UpdateDayServiceTranslationInput = z.infer<typeof updateDayServiceTranslationSchema>;
|
|
10
|
+
export declare const itineraryTranslationProductsService: {
|
|
11
|
+
listProductItineraryTranslations(db: PostgresJsDatabase, query: ProductItineraryTranslationListQuery): Promise<{
|
|
12
|
+
data: {
|
|
13
|
+
id: string;
|
|
14
|
+
itineraryId: string;
|
|
15
|
+
languageTag: string;
|
|
16
|
+
name: string;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
updatedAt: Date;
|
|
19
|
+
}[];
|
|
20
|
+
total: number;
|
|
21
|
+
limit: number;
|
|
22
|
+
offset: number;
|
|
23
|
+
}>;
|
|
24
|
+
getProductItineraryTranslationById(db: PostgresJsDatabase, id: string): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
itineraryId: string;
|
|
27
|
+
languageTag: string;
|
|
28
|
+
name: string;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
updatedAt: Date;
|
|
31
|
+
} | null>;
|
|
32
|
+
getItineraryTranslationForProductMutation(db: PostgresJsDatabase, id: string): Promise<{
|
|
33
|
+
productId: string;
|
|
34
|
+
id: string;
|
|
35
|
+
itineraryId: string;
|
|
36
|
+
languageTag: string;
|
|
37
|
+
name: string;
|
|
38
|
+
createdAt: Date;
|
|
39
|
+
updatedAt: Date;
|
|
40
|
+
} | null>;
|
|
41
|
+
createProductItineraryTranslation(db: PostgresJsDatabase, productId: string, itineraryId: string, data: CreateProductItineraryTranslationInput): Promise<{
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
createdAt: Date;
|
|
45
|
+
updatedAt: Date;
|
|
46
|
+
itineraryId: string;
|
|
47
|
+
languageTag: string;
|
|
48
|
+
} | null>;
|
|
49
|
+
updateProductItineraryTranslation(db: PostgresJsDatabase, id: string, data: UpdateProductItineraryTranslationInput): Promise<{
|
|
50
|
+
id: string;
|
|
51
|
+
itineraryId: string;
|
|
52
|
+
languageTag: string;
|
|
53
|
+
name: string;
|
|
54
|
+
createdAt: Date;
|
|
55
|
+
updatedAt: Date;
|
|
56
|
+
} | null>;
|
|
57
|
+
deleteProductItineraryTranslation(db: PostgresJsDatabase, id: string): Promise<{
|
|
58
|
+
id: string;
|
|
59
|
+
} | null>;
|
|
60
|
+
listDayServiceTranslations(db: PostgresJsDatabase, query: DayServiceTranslationListQuery): Promise<{
|
|
61
|
+
data: {
|
|
62
|
+
id: string;
|
|
63
|
+
serviceId: string;
|
|
64
|
+
languageTag: string;
|
|
65
|
+
name: string;
|
|
66
|
+
description: string | null;
|
|
67
|
+
notes: string | null;
|
|
68
|
+
createdAt: Date;
|
|
69
|
+
updatedAt: Date;
|
|
70
|
+
}[];
|
|
71
|
+
total: number;
|
|
72
|
+
limit: number;
|
|
73
|
+
offset: number;
|
|
74
|
+
}>;
|
|
75
|
+
getDayServiceTranslationById(db: PostgresJsDatabase, id: string): Promise<{
|
|
76
|
+
id: string;
|
|
77
|
+
serviceId: string;
|
|
78
|
+
languageTag: string;
|
|
79
|
+
name: string;
|
|
80
|
+
description: string | null;
|
|
81
|
+
notes: string | null;
|
|
82
|
+
createdAt: Date;
|
|
83
|
+
updatedAt: Date;
|
|
84
|
+
} | null>;
|
|
85
|
+
getDayServiceTranslationForProductMutation(db: PostgresJsDatabase, id: string): Promise<{
|
|
86
|
+
dayId: string;
|
|
87
|
+
productId: string;
|
|
88
|
+
id: string;
|
|
89
|
+
serviceId: string;
|
|
90
|
+
languageTag: string;
|
|
91
|
+
name: string;
|
|
92
|
+
description: string | null;
|
|
93
|
+
notes: string | null;
|
|
94
|
+
createdAt: Date;
|
|
95
|
+
updatedAt: Date;
|
|
96
|
+
} | null>;
|
|
97
|
+
createDayServiceTranslation(db: PostgresJsDatabase, productId: string, dayId: string, serviceId: string, data: CreateDayServiceTranslationInput): Promise<{
|
|
98
|
+
id: string;
|
|
99
|
+
name: string;
|
|
100
|
+
createdAt: Date;
|
|
101
|
+
description: string | null;
|
|
102
|
+
updatedAt: Date;
|
|
103
|
+
languageTag: string;
|
|
104
|
+
notes: string | null;
|
|
105
|
+
serviceId: string;
|
|
106
|
+
} | null>;
|
|
107
|
+
updateDayServiceTranslation(db: PostgresJsDatabase, id: string, data: UpdateDayServiceTranslationInput): Promise<{
|
|
108
|
+
id: string;
|
|
109
|
+
serviceId: string;
|
|
110
|
+
languageTag: string;
|
|
111
|
+
name: string;
|
|
112
|
+
description: string | null;
|
|
113
|
+
notes: string | null;
|
|
114
|
+
createdAt: Date;
|
|
115
|
+
updatedAt: Date;
|
|
116
|
+
} | null>;
|
|
117
|
+
deleteDayServiceTranslation(db: PostgresJsDatabase, id: string): Promise<{
|
|
118
|
+
id: string;
|
|
119
|
+
} | null>;
|
|
120
|
+
};
|
|
121
|
+
export {};
|
|
122
|
+
//# sourceMappingURL=service-itinerary-translations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-itinerary-translations.d.ts","sourceRoot":"","sources":["../src/service-itinerary-translations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAS5B,OAAO,KAAK,EACV,oCAAoC,EACpC,iCAAiC,EACjC,uCAAuC,EACvC,0CAA0C,EAC1C,iCAAiC,EACjC,uCAAuC,EACxC,MAAM,iBAAiB,CAAA;AAExB,KAAK,oCAAoC,GAAG,CAAC,CAAC,KAAK,CACjD,OAAO,0CAA0C,CAClD,CAAA;AACD,KAAK,sCAAsC,GAAG,CAAC,CAAC,KAAK,CACnD,OAAO,uCAAuC,CAC/C,CAAA;AACD,KAAK,sCAAsC,GAAG,CAAC,CAAC,KAAK,CACnD,OAAO,uCAAuC,CAC/C,CAAA;AACD,KAAK,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAA;AAC1F,KAAK,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAA;AACzF,KAAK,gCAAgC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAA;AAkCzF,eAAO,MAAM,mCAAmC;yCAExC,kBAAkB,SACf,oCAAoC;;;;;;;;;;;;;2CAuCA,kBAAkB,MAAM,MAAM;;;;;;;;kDAUvB,kBAAkB,MAAM,MAAM;;;;;;;;;0CAe5E,kBAAkB,aACX,MAAM,eACJ,MAAM,QACb,sCAAsC;;;;;;;;0CAgBxC,kBAAkB,MAClB,MAAM,QACJ,sCAAsC;;;;;;;;0CAWF,kBAAkB,MAAM,MAAM;;;mCASrC,kBAAkB,SAAS,8BAA8B;;;;;;;;;;;;;;;qCAsCvD,kBAAkB,MAAM,MAAM;;;;;;;;;;mDAUhB,kBAAkB,MAAM,MAAM;;;;;;;;;;;;oCAe7E,kBAAkB,aACX,MAAM,SACV,MAAM,aACF,MAAM,QACX,gCAAgC;;;;;;;;;;oCAgBlC,kBAAkB,MAClB,MAAM,QACJ,gCAAgC;;;;;;;;;;oCAWF,kBAAkB,MAAM,MAAM;;;CAQrE,CAAA"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { and, asc, eq, sql } from "drizzle-orm";
|
|
2
|
+
import { productDayServices, productDayServiceTranslations, productDays, productItineraries, productItineraryTranslations, } from "./schema.js";
|
|
3
|
+
async function getItineraryById(db, itineraryId) {
|
|
4
|
+
const [itinerary] = await db
|
|
5
|
+
.select({ id: productItineraries.id, productId: productItineraries.productId })
|
|
6
|
+
.from(productItineraries)
|
|
7
|
+
.where(eq(productItineraries.id, itineraryId))
|
|
8
|
+
.limit(1);
|
|
9
|
+
return itinerary ?? null;
|
|
10
|
+
}
|
|
11
|
+
async function getDayServiceById(db, serviceId) {
|
|
12
|
+
const [service] = await db
|
|
13
|
+
.select({
|
|
14
|
+
id: productDayServices.id,
|
|
15
|
+
dayId: productDayServices.dayId,
|
|
16
|
+
productId: productItineraries.productId,
|
|
17
|
+
})
|
|
18
|
+
.from(productDayServices)
|
|
19
|
+
.innerJoin(productDays, eq(productDayServices.dayId, productDays.id))
|
|
20
|
+
.innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
|
|
21
|
+
.where(eq(productDayServices.id, serviceId))
|
|
22
|
+
.limit(1);
|
|
23
|
+
return service ?? null;
|
|
24
|
+
}
|
|
25
|
+
export const itineraryTranslationProductsService = {
|
|
26
|
+
async listProductItineraryTranslations(db, query) {
|
|
27
|
+
const conditions = [];
|
|
28
|
+
if (query.itineraryId) {
|
|
29
|
+
conditions.push(eq(productItineraryTranslations.itineraryId, query.itineraryId));
|
|
30
|
+
}
|
|
31
|
+
if (query.languageTag) {
|
|
32
|
+
conditions.push(eq(productItineraryTranslations.languageTag, query.languageTag));
|
|
33
|
+
}
|
|
34
|
+
const where = conditions.length > 0 ? and(...conditions) : undefined;
|
|
35
|
+
const [rows, countResult] = await Promise.all([
|
|
36
|
+
db
|
|
37
|
+
.select()
|
|
38
|
+
.from(productItineraryTranslations)
|
|
39
|
+
.where(where)
|
|
40
|
+
.limit(query.limit)
|
|
41
|
+
.offset(query.offset)
|
|
42
|
+
.orderBy(asc(productItineraryTranslations.languageTag), asc(productItineraryTranslations.createdAt)),
|
|
43
|
+
db
|
|
44
|
+
.select({ count: sql `count(*)::int` })
|
|
45
|
+
.from(productItineraryTranslations)
|
|
46
|
+
.where(where),
|
|
47
|
+
]);
|
|
48
|
+
return {
|
|
49
|
+
data: rows,
|
|
50
|
+
total: countResult[0]?.count ?? 0,
|
|
51
|
+
limit: query.limit,
|
|
52
|
+
offset: query.offset,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
async getProductItineraryTranslationById(db, id) {
|
|
56
|
+
const [row] = await db
|
|
57
|
+
.select()
|
|
58
|
+
.from(productItineraryTranslations)
|
|
59
|
+
.where(eq(productItineraryTranslations.id, id))
|
|
60
|
+
.limit(1);
|
|
61
|
+
return row ?? null;
|
|
62
|
+
},
|
|
63
|
+
async getItineraryTranslationForProductMutation(db, id) {
|
|
64
|
+
const [row] = await db
|
|
65
|
+
.select()
|
|
66
|
+
.from(productItineraryTranslations)
|
|
67
|
+
.where(eq(productItineraryTranslations.id, id))
|
|
68
|
+
.limit(1);
|
|
69
|
+
if (!row) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const itineraryRef = await getItineraryById(db, row.itineraryId);
|
|
73
|
+
return itineraryRef ? { ...row, productId: itineraryRef.productId } : null;
|
|
74
|
+
},
|
|
75
|
+
async createProductItineraryTranslation(db, productId, itineraryId, data) {
|
|
76
|
+
const itineraryRef = await getItineraryById(db, itineraryId);
|
|
77
|
+
if (!itineraryRef || itineraryRef.productId !== productId) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const [row] = await db
|
|
81
|
+
.insert(productItineraryTranslations)
|
|
82
|
+
.values({ ...data, itineraryId })
|
|
83
|
+
.returning();
|
|
84
|
+
return row ?? null;
|
|
85
|
+
},
|
|
86
|
+
async updateProductItineraryTranslation(db, id, data) {
|
|
87
|
+
const [row] = await db
|
|
88
|
+
.update(productItineraryTranslations)
|
|
89
|
+
.set({ ...data, updatedAt: new Date() })
|
|
90
|
+
.where(eq(productItineraryTranslations.id, id))
|
|
91
|
+
.returning();
|
|
92
|
+
return row ?? null;
|
|
93
|
+
},
|
|
94
|
+
async deleteProductItineraryTranslation(db, id) {
|
|
95
|
+
const [row] = await db
|
|
96
|
+
.delete(productItineraryTranslations)
|
|
97
|
+
.where(eq(productItineraryTranslations.id, id))
|
|
98
|
+
.returning({ id: productItineraryTranslations.id });
|
|
99
|
+
return row ?? null;
|
|
100
|
+
},
|
|
101
|
+
async listDayServiceTranslations(db, query) {
|
|
102
|
+
const conditions = [];
|
|
103
|
+
if (query.serviceId) {
|
|
104
|
+
conditions.push(eq(productDayServiceTranslations.serviceId, query.serviceId));
|
|
105
|
+
}
|
|
106
|
+
if (query.languageTag) {
|
|
107
|
+
conditions.push(eq(productDayServiceTranslations.languageTag, query.languageTag));
|
|
108
|
+
}
|
|
109
|
+
const where = conditions.length > 0 ? and(...conditions) : undefined;
|
|
110
|
+
const [rows, countResult] = await Promise.all([
|
|
111
|
+
db
|
|
112
|
+
.select()
|
|
113
|
+
.from(productDayServiceTranslations)
|
|
114
|
+
.where(where)
|
|
115
|
+
.limit(query.limit)
|
|
116
|
+
.offset(query.offset)
|
|
117
|
+
.orderBy(asc(productDayServiceTranslations.languageTag), asc(productDayServiceTranslations.createdAt)),
|
|
118
|
+
db
|
|
119
|
+
.select({ count: sql `count(*)::int` })
|
|
120
|
+
.from(productDayServiceTranslations)
|
|
121
|
+
.where(where),
|
|
122
|
+
]);
|
|
123
|
+
return {
|
|
124
|
+
data: rows,
|
|
125
|
+
total: countResult[0]?.count ?? 0,
|
|
126
|
+
limit: query.limit,
|
|
127
|
+
offset: query.offset,
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
async getDayServiceTranslationById(db, id) {
|
|
131
|
+
const [row] = await db
|
|
132
|
+
.select()
|
|
133
|
+
.from(productDayServiceTranslations)
|
|
134
|
+
.where(eq(productDayServiceTranslations.id, id))
|
|
135
|
+
.limit(1);
|
|
136
|
+
return row ?? null;
|
|
137
|
+
},
|
|
138
|
+
async getDayServiceTranslationForProductMutation(db, id) {
|
|
139
|
+
const [row] = await db
|
|
140
|
+
.select()
|
|
141
|
+
.from(productDayServiceTranslations)
|
|
142
|
+
.where(eq(productDayServiceTranslations.id, id))
|
|
143
|
+
.limit(1);
|
|
144
|
+
if (!row) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const serviceRef = await getDayServiceById(db, row.serviceId);
|
|
148
|
+
return serviceRef ? { ...row, dayId: serviceRef.dayId, productId: serviceRef.productId } : null;
|
|
149
|
+
},
|
|
150
|
+
async createDayServiceTranslation(db, productId, dayId, serviceId, data) {
|
|
151
|
+
const serviceRef = await getDayServiceById(db, serviceId);
|
|
152
|
+
if (!serviceRef || serviceRef.productId !== productId || serviceRef.dayId !== dayId) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const [row] = await db
|
|
156
|
+
.insert(productDayServiceTranslations)
|
|
157
|
+
.values({ ...data, serviceId })
|
|
158
|
+
.returning();
|
|
159
|
+
return row ?? null;
|
|
160
|
+
},
|
|
161
|
+
async updateDayServiceTranslation(db, id, data) {
|
|
162
|
+
const [row] = await db
|
|
163
|
+
.update(productDayServiceTranslations)
|
|
164
|
+
.set({ ...data, updatedAt: new Date() })
|
|
165
|
+
.where(eq(productDayServiceTranslations.id, id))
|
|
166
|
+
.returning();
|
|
167
|
+
return row ?? null;
|
|
168
|
+
},
|
|
169
|
+
async deleteDayServiceTranslation(db, id) {
|
|
170
|
+
const [row] = await db
|
|
171
|
+
.delete(productDayServiceTranslations)
|
|
172
|
+
.where(eq(productDayServiceTranslations.id, id))
|
|
173
|
+
.returning({ id: productDayServiceTranslations.id });
|
|
174
|
+
return row ?? null;
|
|
175
|
+
},
|
|
176
|
+
};
|
|
@@ -127,10 +127,10 @@ export declare const optionTranslationProductsService: {
|
|
|
127
127
|
createdAt: Date;
|
|
128
128
|
description: string | null;
|
|
129
129
|
updatedAt: Date;
|
|
130
|
+
languageTag: string;
|
|
130
131
|
title: string | null;
|
|
131
132
|
location: string | null;
|
|
132
133
|
dayId: string;
|
|
133
|
-
languageTag: string;
|
|
134
134
|
} | null>;
|
|
135
135
|
updateProductDayTranslation(db: PostgresJsDatabase, id: string, data: UpdateProductDayTranslationInput): Promise<{
|
|
136
136
|
id: string;
|