@voyant-travel/inventory 0.3.6 → 0.3.8
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/read-model.d.ts +6 -2
- package/dist/read-model.d.ts.map +1 -1
- package/dist/read-model.js +11 -10
- package/dist/routes-public.d.ts.map +1 -1
- package/dist/routes-public.js +16 -4
- package/dist/service-catalog.d.ts +1 -0
- package/dist/service-catalog.d.ts.map +1 -1
- package/dist/service-catalog.js +3 -1
- package/dist/service-public.d.ts.map +1 -1
- package/dist/service-public.js +21 -5
- package/migrations/0000_inventory_baseline.sql +774 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +14 -10
package/dist/read-model.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { KVStore } from "@voyant-travel/utils/cache";
|
|
2
2
|
export declare function productDocKey(productId: string, variant: string): string;
|
|
3
|
-
export declare function productSlugMapKey(slug: string): string;
|
|
3
|
+
export declare function productSlugMapKey(slug: string, variant: string): string;
|
|
4
4
|
/** Stable variant id from the detail query (currently just the locale). */
|
|
5
5
|
export declare function productDocVariant(query: {
|
|
6
6
|
languageTag?: string | null;
|
|
7
7
|
}): string;
|
|
8
|
+
export interface ProductSlugResolution {
|
|
9
|
+
productId: string;
|
|
10
|
+
languageTag: string | null;
|
|
11
|
+
}
|
|
8
12
|
/**
|
|
9
13
|
* Read-through document fetch. `null` compute results (missing/inactive
|
|
10
14
|
* product) are never cached — a 404 must not mask a product that
|
|
@@ -15,7 +19,7 @@ export declare function readThroughProductDoc<T>(kv: KVStore | undefined, key: s
|
|
|
15
19
|
fromReadModel: boolean;
|
|
16
20
|
}>;
|
|
17
21
|
/** Resolve a slug to a product id through the KV mapping. */
|
|
18
|
-
export declare function readThroughSlugMapping(kv: KVStore | undefined, slug: string, resolve: () => Promise<
|
|
22
|
+
export declare function readThroughSlugMapping(kv: KVStore | undefined, slug: string, variant: string, resolve: () => Promise<ProductSlugResolution | null>): Promise<ProductSlugResolution | null>;
|
|
19
23
|
/**
|
|
20
24
|
* Drop every cached document variant for a product. Uses KV `list` by
|
|
21
25
|
* prefix (optional on the KVStore contract — silently a no-op without
|
package/dist/read-model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-model.d.ts","sourceRoot":"","sources":["../src/read-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AA2BzD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"read-model.d.ts","sourceRoot":"","sources":["../src/read-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AA2BzD,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,MAAM,CAEhF;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAC/B,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC,CAkBrD;AAED,6DAA6D;AAC7D,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,OAAO,GAAG,SAAS,EACvB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,GACnD,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAmBvC;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ9F"}
|
package/dist/read-model.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* `productsReadModelInvalidation` in routes.ts), and a generous TTL
|
|
11
11
|
* bounds staleness for anything invalidation misses.
|
|
12
12
|
*
|
|
13
|
-
* Slug lookups resolve through a short-lived slug→
|
|
14
|
-
* id-keyed document is shared between `/:id` and `/slug/:slug`. The
|
|
13
|
+
* Slug lookups resolve through a short-lived slug→product+locale mapping
|
|
14
|
+
* so the id-keyed document is shared between `/:id` and `/slug/:slug`. The
|
|
15
15
|
* mapping is deliberately NOT invalidated on mutation: it's cheap to
|
|
16
16
|
* refill, and its short TTL bounds the only affected case (a renamed
|
|
17
17
|
* slug serving the old document) to a few minutes.
|
|
@@ -24,8 +24,8 @@ const SLUG_MAP_TTL_SECONDS = 5 * 60;
|
|
|
24
24
|
export function productDocKey(productId, variant) {
|
|
25
25
|
return `${RM_PREFIX}:${productId}:${variant}`;
|
|
26
26
|
}
|
|
27
|
-
export function productSlugMapKey(slug) {
|
|
28
|
-
return `rm:v1:product-slug:${slug}`;
|
|
27
|
+
export function productSlugMapKey(slug, variant) {
|
|
28
|
+
return `rm:v1:product-slug:${variant}:${slug}`;
|
|
29
29
|
}
|
|
30
30
|
/** Stable variant id from the detail query (currently just the locale). */
|
|
31
31
|
export function productDocVariant(query) {
|
|
@@ -59,10 +59,11 @@ export async function readThroughProductDoc(kv, key, compute) {
|
|
|
59
59
|
return { data, fromReadModel: false };
|
|
60
60
|
}
|
|
61
61
|
/** Resolve a slug to a product id through the KV mapping. */
|
|
62
|
-
export async function readThroughSlugMapping(kv, slug, resolve) {
|
|
62
|
+
export async function readThroughSlugMapping(kv, slug, variant, resolve) {
|
|
63
|
+
const key = productSlugMapKey(slug, variant);
|
|
63
64
|
if (kv) {
|
|
64
65
|
try {
|
|
65
|
-
const hit = await kv.get(
|
|
66
|
+
const hit = await kv.get(key, { type: "json" });
|
|
66
67
|
if (hit)
|
|
67
68
|
return hit;
|
|
68
69
|
}
|
|
@@ -70,16 +71,16 @@ export async function readThroughSlugMapping(kv, slug, resolve) {
|
|
|
70
71
|
// fall through
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
74
|
+
const resolution = await resolve();
|
|
75
|
+
if (resolution && kv) {
|
|
75
76
|
try {
|
|
76
|
-
await kv.put(
|
|
77
|
+
await kv.put(key, JSON.stringify(resolution), { expirationTtl: SLUG_MAP_TTL_SECONDS });
|
|
77
78
|
}
|
|
78
79
|
catch {
|
|
79
80
|
// best-effort
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
|
-
return
|
|
83
|
+
return resolution;
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
* Drop every cached document variant for a product. Uses KV `list` by
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAqBjE,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE;QACR,mEAAmE;QACnE,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AA2DD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAqBjE,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE;QACR,mEAAmE;QACnE,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB,CAAA;IACD,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AA2DD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAgG5B,CAAA;AAEJ,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA"}
|
package/dist/routes-public.js
CHANGED
|
@@ -66,14 +66,26 @@ export const publicProductRoutes = new Hono()
|
|
|
66
66
|
const slug = c.req.param("slug");
|
|
67
67
|
// Resolve slug → id through the short-lived KV mapping so both detail
|
|
68
68
|
// routes share one id-keyed document per variant.
|
|
69
|
-
const
|
|
69
|
+
const requestedVariant = productDocVariant(query);
|
|
70
|
+
const resolution = await readThroughSlugMapping(kv, slug, requestedVariant, async () => {
|
|
70
71
|
const row = await publicProductsService.getCatalogProductBySlug(c.get("db"), slug, query);
|
|
71
|
-
|
|
72
|
+
const productId = row ? (row.id ?? null) : null;
|
|
73
|
+
if (!productId)
|
|
74
|
+
return null;
|
|
75
|
+
return {
|
|
76
|
+
productId,
|
|
77
|
+
languageTag: row.contentLanguageTag ??
|
|
78
|
+
query.languageTag ??
|
|
79
|
+
null,
|
|
80
|
+
};
|
|
72
81
|
});
|
|
73
|
-
if (!
|
|
82
|
+
if (!resolution) {
|
|
74
83
|
return c.json({ error: "Catalog product not found" }, 404);
|
|
75
84
|
}
|
|
76
|
-
const
|
|
85
|
+
const detailQuery = resolution.languageTag
|
|
86
|
+
? { ...query, languageTag: resolution.languageTag }
|
|
87
|
+
: query;
|
|
88
|
+
const { data } = await readThroughProductDoc(kv, productDocKey(resolution.productId, productDocVariant(detailQuery)), () => publicProductsService.getCatalogProductById(c.get("db"), resolution.productId, detailQuery));
|
|
77
89
|
if (!data) {
|
|
78
90
|
return c.json({ error: "Catalog product not found" }, 404);
|
|
79
91
|
}
|
|
@@ -7,6 +7,7 @@ type HydrateCatalogProductOptions = {
|
|
|
7
7
|
languageTag?: string | null;
|
|
8
8
|
fallbackLanguageTags?: string[];
|
|
9
9
|
};
|
|
10
|
+
export declare const DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS: readonly ["en", "ro"];
|
|
10
11
|
export declare const catalogProductsService: {
|
|
11
12
|
hydrateProducts(db: PostgresJsDatabase, productRows: CatalogProductRow[], options?: HydrateCatalogProductOptions): Promise<({
|
|
12
13
|
description: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAWL,QAAQ,EAMT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,qBAAqB,EACrB,8BAA8B,EAE/B,MAAM,yBAAyB,CAAA;AAEhC,KAAK,iBAAiB,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,KAAK,4BAA4B,GAAG;IAClC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;
|
|
1
|
+
{"version":3,"file":"service-catalog.d.ts","sourceRoot":"","sources":["../src/service-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAWL,QAAQ,EAMT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,qBAAqB,EACrB,8BAA8B,EAE/B,MAAM,yBAAyB,CAAA;AAEhC,KAAK,iBAAiB,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,KAAK,4BAA4B,GAAG;IAClC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,6CAA6C,uBAAwB,CAAA;AA2alF,eAAO,MAAM,sBAAsB;wBAE3B,kBAAkB,eACT,iBAAiB,EAAE,YACvB,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAkIjC,kBAAkB,SACf,8BAA8B,GACpC,OAAO,CAAC;QACT,IAAI,EAAE,qBAAqB,EAAE,CAAA;QAC7B,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;qCAoFI,kBAAkB,aACX,MAAM,UACV,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAa1F,CAAA"}
|
package/dist/service-catalog.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// agent-quality: file-size exception -- owner: inventory; existing service module stays co-located until a dedicated split preserves behavior and tests.
|
|
2
2
|
import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
|
|
3
3
|
import { destinations, destinationTranslations, productCapabilities, productCategories, productCategoryProducts, productDestinations, productFaqs, productFeatures, productLocations, productMedia, products, productTagProducts, productTags, productTranslations, productTypes, productVisibilitySettings, } from "./schema.js";
|
|
4
|
+
export const DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS = ["en", "ro"];
|
|
4
5
|
function normalizeDate(value) {
|
|
5
6
|
if (!value) {
|
|
6
7
|
return null;
|
|
@@ -456,7 +457,8 @@ export const catalogProductsService = {
|
|
|
456
457
|
const localizedProducts = (await this.hydrateProducts(db, rows, {
|
|
457
458
|
includeContent: true,
|
|
458
459
|
languageTag: query.languageTag,
|
|
459
|
-
fallbackLanguageTags: query.fallbackLanguageTags ??
|
|
460
|
+
fallbackLanguageTags: query.fallbackLanguageTags ??
|
|
461
|
+
(query.languageTag ? [...DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS] : []),
|
|
460
462
|
}));
|
|
461
463
|
const rowById = new Map(rows.map((row) => [row.id, row]));
|
|
462
464
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAmBjE,OAAO,KAAK,EACV,8BAA8B,EAC9B,iCAAiC,EACjC,6BAA6B,EAC7B,qCAAqC,EACrC,yBAAyB,EAC1B,MAAM,wBAAwB,CAAA;AA0I/B,eAAO,MAAM,qBAAqB;4BAE1B,kBAAkB,SACf,6BAA6B,GAAG;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA6H/D,kBAAkB,MAClB,MAAM,UACH;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA2BlC,kBAAkB,QAChB,MAAM,UACL,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAoDxC,kBAAkB,aACX,MAAM,UACV;QAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;;;;;;;;;;;;;8BAMR,kBAAkB,SAAS,8BAA8B;;;;;;;;;;;;;wBAkD/D,kBAAkB,SAAS,yBAAyB;;;;;;;;;gCA+B5C,kBAAkB,SAAS,iCAAiC;;;;;;;;;;;;;;;;;;;CAqG/F,CAAA"}
|
package/dist/service-public.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// agent-quality: file-size exception -- owner: inventory; existing service module stays co-located until a dedicated split preserves behavior and tests.
|
|
2
2
|
import { and, asc, desc, eq, ilike, inArray, notInArray, or, sql } from "drizzle-orm";
|
|
3
3
|
import { destinations, destinationTranslations, productCategories, productCategoryProducts, productDestinations, productLocations, products, productTagProducts, productTags, productTranslations, productVisibilitySettings, } from "./schema.js";
|
|
4
|
-
import { catalogProductsService } from "./service-catalog.js";
|
|
4
|
+
import { catalogProductsService, DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS, } from "./service-catalog.js";
|
|
5
5
|
function impossibleCondition() {
|
|
6
6
|
return sql `1 = 0`;
|
|
7
7
|
}
|
|
@@ -9,6 +9,11 @@ function normalizeLanguageTag(value) {
|
|
|
9
9
|
const normalized = value?.trim().toLowerCase();
|
|
10
10
|
return normalized || null;
|
|
11
11
|
}
|
|
12
|
+
function normalizeLanguageTagList(values) {
|
|
13
|
+
return Array.from(new Set(values
|
|
14
|
+
.map((value) => normalizeLanguageTag(value))
|
|
15
|
+
.filter((value) => Boolean(value))));
|
|
16
|
+
}
|
|
12
17
|
async function listProductIdsForCategory(db, categoryId) {
|
|
13
18
|
const rows = await db
|
|
14
19
|
.select({ productId: productCategoryProducts.productId })
|
|
@@ -198,6 +203,12 @@ export const publicProductsService = {
|
|
|
198
203
|
async getCatalogProductBySlug(db, slug, query = {}) {
|
|
199
204
|
const normalizedSlug = slug.trim().toLowerCase();
|
|
200
205
|
const normalizedLanguageTag = normalizeLanguageTag(query.languageTag);
|
|
206
|
+
const candidateLanguageTags = normalizedLanguageTag
|
|
207
|
+
? normalizeLanguageTagList([
|
|
208
|
+
normalizedLanguageTag,
|
|
209
|
+
...DEFAULT_CATALOG_SEARCH_FALLBACK_LANGUAGE_TAGS,
|
|
210
|
+
])
|
|
211
|
+
: [];
|
|
201
212
|
const conditions = [
|
|
202
213
|
// agent-quality: raw-sql reviewed -- owner: inventory; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
203
214
|
sql `lower(${productTranslations.slug}) = ${normalizedSlug}`,
|
|
@@ -206,9 +217,9 @@ export const publicProductsService = {
|
|
|
206
217
|
eq(products.visibility, "public"),
|
|
207
218
|
];
|
|
208
219
|
if (normalizedLanguageTag) {
|
|
209
|
-
conditions.push(
|
|
220
|
+
conditions.push(inArray(productTranslations.languageTag, candidateLanguageTags));
|
|
210
221
|
}
|
|
211
|
-
const
|
|
222
|
+
const rows = await db
|
|
212
223
|
.select({
|
|
213
224
|
productId: products.id,
|
|
214
225
|
languageTag: productTranslations.languageTag,
|
|
@@ -217,12 +228,17 @@ export const publicProductsService = {
|
|
|
217
228
|
.innerJoin(products, eq(products.id, productTranslations.productId))
|
|
218
229
|
.where(and(...conditions))
|
|
219
230
|
.orderBy(desc(productTranslations.updatedAt))
|
|
220
|
-
.limit(1);
|
|
231
|
+
.limit(candidateLanguageTags.length || 1);
|
|
232
|
+
const row = candidateLanguageTags.length > 0
|
|
233
|
+
? (candidateLanguageTags
|
|
234
|
+
.map((languageTag) => rows.find((item) => normalizeLanguageTag(item.languageTag) === languageTag))
|
|
235
|
+
.find(Boolean) ?? null)
|
|
236
|
+
: (rows[0] ?? null);
|
|
221
237
|
if (!row) {
|
|
222
238
|
return null;
|
|
223
239
|
}
|
|
224
240
|
return this.getCatalogProductById(db, row.productId, {
|
|
225
|
-
languageTag:
|
|
241
|
+
languageTag: row.languageTag,
|
|
226
242
|
});
|
|
227
243
|
},
|
|
228
244
|
async getCatalogProductBrochure(db, productId, query = {}) {
|
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
|
|
2
|
+
--> statement-breakpoint
|
|
3
|
+
DO $$ BEGIN
|
|
4
|
+
CREATE TYPE "public"."extra_collection_mode" AS ENUM('booking_total', 'cash_on_trip', 'external', 'included', 'none');
|
|
5
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
6
|
+
END $$;--> statement-breakpoint
|
|
7
|
+
DO $$ BEGIN
|
|
8
|
+
CREATE TYPE "public"."extra_pricing_mode" AS ENUM('included', 'per_person', 'per_booking', 'quantity_based', 'on_request', 'free');
|
|
9
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
10
|
+
END $$;--> statement-breakpoint
|
|
11
|
+
DO $$ BEGIN
|
|
12
|
+
CREATE TYPE "public"."extra_selection_type" AS ENUM('optional', 'required', 'default_selected', 'unavailable');
|
|
13
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
14
|
+
END $$;--> statement-breakpoint
|
|
15
|
+
DO $$ BEGIN
|
|
16
|
+
CREATE TYPE "public"."option_unit_type" AS ENUM('person', 'group', 'room', 'vehicle', 'service', 'other');
|
|
17
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
18
|
+
END $$;--> statement-breakpoint
|
|
19
|
+
DO $$ BEGIN
|
|
20
|
+
CREATE TYPE "public"."product_activation_mode" AS ENUM('manual', 'scheduled', 'channel_controlled');
|
|
21
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
22
|
+
END $$;--> statement-breakpoint
|
|
23
|
+
DO $$ BEGIN
|
|
24
|
+
CREATE TYPE "public"."product_booking_mode" AS ENUM('date', 'date_time', 'open', 'stay', 'transfer', 'itinerary', 'other');
|
|
25
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
26
|
+
END $$;--> statement-breakpoint
|
|
27
|
+
DO $$ BEGIN
|
|
28
|
+
CREATE TYPE "public"."product_capability" AS ENUM('instant_confirmation', 'on_request', 'pickup_available', 'dropoff_available', 'guided', 'private', 'shared', 'digital_ticket', 'voucher_required', 'external_inventory', 'multi_day', 'accommodation', 'transport');
|
|
29
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
30
|
+
END $$;--> statement-breakpoint
|
|
31
|
+
DO $$ BEGIN
|
|
32
|
+
CREATE TYPE "public"."product_capacity_mode" AS ENUM('free_sale', 'limited', 'on_request');
|
|
33
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
34
|
+
END $$;--> statement-breakpoint
|
|
35
|
+
DO $$ BEGIN
|
|
36
|
+
CREATE TYPE "public"."product_delivery_format" AS ENUM('voucher', 'ticket', 'pdf', 'qr_code', 'barcode', 'email', 'mobile', 'none');
|
|
37
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
38
|
+
END $$;--> statement-breakpoint
|
|
39
|
+
DO $$ BEGIN
|
|
40
|
+
CREATE TYPE "public"."product_feature_type" AS ENUM('inclusion', 'exclusion', 'highlight', 'important_information', 'other');
|
|
41
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
42
|
+
END $$;--> statement-breakpoint
|
|
43
|
+
DO $$ BEGIN
|
|
44
|
+
CREATE TYPE "public"."product_location_type" AS ENUM('start', 'end', 'meeting_point', 'pickup', 'dropoff', 'point_of_interest', 'other');
|
|
45
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
46
|
+
END $$;--> statement-breakpoint
|
|
47
|
+
DO $$ BEGIN
|
|
48
|
+
CREATE TYPE "public"."product_media_type" AS ENUM('image', 'video', 'document');
|
|
49
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
50
|
+
END $$;--> statement-breakpoint
|
|
51
|
+
DO $$ BEGIN
|
|
52
|
+
CREATE TYPE "public"."product_option_status" AS ENUM('draft', 'active', 'archived');
|
|
53
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
54
|
+
END $$;--> statement-breakpoint
|
|
55
|
+
DO $$ BEGIN
|
|
56
|
+
CREATE TYPE "public"."product_status" AS ENUM('draft', 'active', 'archived');
|
|
57
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
58
|
+
END $$;--> statement-breakpoint
|
|
59
|
+
DO $$ BEGIN
|
|
60
|
+
CREATE TYPE "public"."product_ticket_fulfillment" AS ENUM('none', 'per_booking', 'per_participant', 'per_item');
|
|
61
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
62
|
+
END $$;--> statement-breakpoint
|
|
63
|
+
DO $$ BEGIN
|
|
64
|
+
CREATE TYPE "public"."product_visibility" AS ENUM('public', 'private', 'hidden');
|
|
65
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
66
|
+
END $$;--> statement-breakpoint
|
|
67
|
+
DO $$ BEGIN
|
|
68
|
+
CREATE TYPE "public"."service_type" AS ENUM('accommodation', 'transfer', 'experience', 'guide', 'meal', 'other');
|
|
69
|
+
EXCEPTION WHEN duplicate_object THEN null;
|
|
70
|
+
END $$;--> statement-breakpoint
|
|
71
|
+
CREATE TABLE "booking_item_product_details" (
|
|
72
|
+
"booking_item_id" text PRIMARY KEY NOT NULL,
|
|
73
|
+
"product_id" text,
|
|
74
|
+
"option_id" text,
|
|
75
|
+
"unit_id" text,
|
|
76
|
+
"supplier_service_id" text,
|
|
77
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
78
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
79
|
+
);
|
|
80
|
+
--> statement-breakpoint
|
|
81
|
+
CREATE TABLE "booking_product_details" (
|
|
82
|
+
"booking_id" text PRIMARY KEY NOT NULL,
|
|
83
|
+
"product_id" text,
|
|
84
|
+
"option_id" text,
|
|
85
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
86
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
87
|
+
);
|
|
88
|
+
--> statement-breakpoint
|
|
89
|
+
CREATE TABLE "products_sourced_content" (
|
|
90
|
+
"entity_id" text NOT NULL,
|
|
91
|
+
"locale" text NOT NULL,
|
|
92
|
+
"market" text DEFAULT '*' NOT NULL,
|
|
93
|
+
"payload" jsonb NOT NULL,
|
|
94
|
+
"content_schema_version" text NOT NULL,
|
|
95
|
+
"returned_locale" text NOT NULL,
|
|
96
|
+
"machine_translated" boolean DEFAULT false NOT NULL,
|
|
97
|
+
"source_updated_at" timestamp with time zone,
|
|
98
|
+
"fetched_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
99
|
+
"fresh_until" timestamp with time zone,
|
|
100
|
+
"etag" text,
|
|
101
|
+
"fetch_status" text DEFAULT 'ok' NOT NULL,
|
|
102
|
+
"fetch_error" text,
|
|
103
|
+
CONSTRAINT "products_sourced_content_entity_id_locale_market_pk" PRIMARY KEY("entity_id","locale","market")
|
|
104
|
+
);
|
|
105
|
+
--> statement-breakpoint
|
|
106
|
+
CREATE TABLE "extras_sourced_content" (
|
|
107
|
+
"entity_id" text NOT NULL,
|
|
108
|
+
"locale" text NOT NULL,
|
|
109
|
+
"market" text DEFAULT '*' NOT NULL,
|
|
110
|
+
"payload" jsonb NOT NULL,
|
|
111
|
+
"content_schema_version" text NOT NULL,
|
|
112
|
+
"returned_locale" text NOT NULL,
|
|
113
|
+
"machine_translated" boolean DEFAULT false NOT NULL,
|
|
114
|
+
"source_updated_at" timestamp with time zone,
|
|
115
|
+
"fetched_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
116
|
+
"fresh_until" timestamp with time zone,
|
|
117
|
+
"etag" text,
|
|
118
|
+
"fetch_status" text DEFAULT 'ok' NOT NULL,
|
|
119
|
+
"fetch_error" text,
|
|
120
|
+
CONSTRAINT "extras_sourced_content_entity_id_locale_market_pk" PRIMARY KEY("entity_id","locale","market")
|
|
121
|
+
);
|
|
122
|
+
--> statement-breakpoint
|
|
123
|
+
CREATE TABLE "option_extra_configs" (
|
|
124
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
125
|
+
"option_id" text NOT NULL,
|
|
126
|
+
"product_extra_id" text NOT NULL,
|
|
127
|
+
"selection_type" "extra_selection_type",
|
|
128
|
+
"pricing_mode" "extra_pricing_mode",
|
|
129
|
+
"priced_per_person" boolean,
|
|
130
|
+
"min_quantity" integer,
|
|
131
|
+
"max_quantity" integer,
|
|
132
|
+
"default_quantity" integer,
|
|
133
|
+
"is_default" boolean DEFAULT false NOT NULL,
|
|
134
|
+
"active" boolean DEFAULT true NOT NULL,
|
|
135
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
136
|
+
"notes" text,
|
|
137
|
+
"metadata" jsonb,
|
|
138
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
139
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
140
|
+
);
|
|
141
|
+
--> statement-breakpoint
|
|
142
|
+
CREATE TABLE "product_extras" (
|
|
143
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
144
|
+
"product_id" text NOT NULL,
|
|
145
|
+
"supplier_id" text,
|
|
146
|
+
"code" text,
|
|
147
|
+
"name" text NOT NULL,
|
|
148
|
+
"description" text,
|
|
149
|
+
"selection_type" "extra_selection_type" DEFAULT 'optional' NOT NULL,
|
|
150
|
+
"pricing_mode" "extra_pricing_mode" DEFAULT 'per_booking' NOT NULL,
|
|
151
|
+
"priced_per_person" boolean DEFAULT false NOT NULL,
|
|
152
|
+
"collection_mode" "extra_collection_mode" DEFAULT 'booking_total' NOT NULL,
|
|
153
|
+
"show_on_slot_manifest" boolean DEFAULT true NOT NULL,
|
|
154
|
+
"min_quantity" integer,
|
|
155
|
+
"max_quantity" integer,
|
|
156
|
+
"default_quantity" integer,
|
|
157
|
+
"active" boolean DEFAULT true NOT NULL,
|
|
158
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
159
|
+
"metadata" jsonb,
|
|
160
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
161
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
162
|
+
);
|
|
163
|
+
--> statement-breakpoint
|
|
164
|
+
CREATE TABLE "option_units" (
|
|
165
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
166
|
+
"option_id" text NOT NULL,
|
|
167
|
+
"name" text NOT NULL,
|
|
168
|
+
"code" text,
|
|
169
|
+
"description" text,
|
|
170
|
+
"unit_type" "option_unit_type" DEFAULT 'person' NOT NULL,
|
|
171
|
+
"min_quantity" integer,
|
|
172
|
+
"max_quantity" integer,
|
|
173
|
+
"min_age" integer,
|
|
174
|
+
"max_age" integer,
|
|
175
|
+
"occupancy_min" integer,
|
|
176
|
+
"occupancy_max" integer,
|
|
177
|
+
"is_required" boolean DEFAULT false NOT NULL,
|
|
178
|
+
"is_hidden" boolean DEFAULT false NOT NULL,
|
|
179
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
180
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
181
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
182
|
+
);
|
|
183
|
+
--> statement-breakpoint
|
|
184
|
+
CREATE TABLE "product_options" (
|
|
185
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
186
|
+
"product_id" text NOT NULL,
|
|
187
|
+
"name" text NOT NULL,
|
|
188
|
+
"code" text,
|
|
189
|
+
"description" text,
|
|
190
|
+
"status" "product_option_status" DEFAULT 'draft' NOT NULL,
|
|
191
|
+
"is_default" boolean DEFAULT false NOT NULL,
|
|
192
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
193
|
+
"available_from" date,
|
|
194
|
+
"available_to" date,
|
|
195
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
196
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
197
|
+
);
|
|
198
|
+
--> statement-breakpoint
|
|
199
|
+
CREATE TABLE "product_pax_pricing_tiers" (
|
|
200
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
201
|
+
"product_id" text NOT NULL,
|
|
202
|
+
"option_unit_id" text,
|
|
203
|
+
"tier_pax" integer NOT NULL,
|
|
204
|
+
"price_per_pax_cents" integer NOT NULL,
|
|
205
|
+
"promo_price_per_pax_cents" integer,
|
|
206
|
+
"effective_from" date,
|
|
207
|
+
"effective_to" date,
|
|
208
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
209
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
210
|
+
);
|
|
211
|
+
--> statement-breakpoint
|
|
212
|
+
CREATE TABLE "products" (
|
|
213
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
214
|
+
"name" text NOT NULL,
|
|
215
|
+
"status" "product_status" DEFAULT 'draft' NOT NULL,
|
|
216
|
+
"description" text,
|
|
217
|
+
"inclusions_html" text,
|
|
218
|
+
"exclusions_html" text,
|
|
219
|
+
"terms_html" text,
|
|
220
|
+
"terms_show_on_contract" boolean DEFAULT false NOT NULL,
|
|
221
|
+
"booking_mode" "product_booking_mode" DEFAULT 'date' NOT NULL,
|
|
222
|
+
"capacity_mode" "product_capacity_mode" DEFAULT 'limited' NOT NULL,
|
|
223
|
+
"timezone" text,
|
|
224
|
+
"default_language_tag" text,
|
|
225
|
+
"visibility" "product_visibility" DEFAULT 'private' NOT NULL,
|
|
226
|
+
"activated" boolean DEFAULT false NOT NULL,
|
|
227
|
+
"reservation_timeout_minutes" integer,
|
|
228
|
+
"sell_currency" text NOT NULL,
|
|
229
|
+
"sell_amount_cents" integer,
|
|
230
|
+
"cost_amount_cents" integer,
|
|
231
|
+
"margin_percent" integer,
|
|
232
|
+
"facility_id" text,
|
|
233
|
+
"supplier_id" text,
|
|
234
|
+
"start_date" date,
|
|
235
|
+
"end_date" date,
|
|
236
|
+
"pax" integer,
|
|
237
|
+
"product_type_id" text,
|
|
238
|
+
"contract_template_id" text,
|
|
239
|
+
"tax_class_id" text,
|
|
240
|
+
"customer_payment_policy" jsonb,
|
|
241
|
+
"tags" jsonb DEFAULT '[]'::jsonb,
|
|
242
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
243
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
244
|
+
);
|
|
245
|
+
--> statement-breakpoint
|
|
246
|
+
CREATE TABLE "product_day_services" (
|
|
247
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
248
|
+
"day_id" text NOT NULL,
|
|
249
|
+
"supplier_service_id" text,
|
|
250
|
+
"service_type" "service_type" NOT NULL,
|
|
251
|
+
"name" text NOT NULL,
|
|
252
|
+
"description" text,
|
|
253
|
+
"country_code" text,
|
|
254
|
+
"cost_currency" text NOT NULL,
|
|
255
|
+
"cost_amount_cents" integer NOT NULL,
|
|
256
|
+
"quantity" integer DEFAULT 1 NOT NULL,
|
|
257
|
+
"sort_order" integer,
|
|
258
|
+
"notes" text,
|
|
259
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
260
|
+
);
|
|
261
|
+
--> statement-breakpoint
|
|
262
|
+
CREATE TABLE "product_day_translations" (
|
|
263
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
264
|
+
"day_id" text NOT NULL,
|
|
265
|
+
"language_tag" text NOT NULL,
|
|
266
|
+
"title" text,
|
|
267
|
+
"description" text,
|
|
268
|
+
"location" text,
|
|
269
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
270
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
271
|
+
);
|
|
272
|
+
--> statement-breakpoint
|
|
273
|
+
CREATE TABLE "product_days" (
|
|
274
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
275
|
+
"itinerary_id" text NOT NULL,
|
|
276
|
+
"day_number" integer NOT NULL,
|
|
277
|
+
"title" text,
|
|
278
|
+
"description" text,
|
|
279
|
+
"location" text,
|
|
280
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
281
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
282
|
+
);
|
|
283
|
+
--> statement-breakpoint
|
|
284
|
+
CREATE TABLE "product_itineraries" (
|
|
285
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
286
|
+
"product_id" text NOT NULL,
|
|
287
|
+
"name" text NOT NULL,
|
|
288
|
+
"is_default" boolean DEFAULT false NOT NULL,
|
|
289
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
290
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
291
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
292
|
+
);
|
|
293
|
+
--> statement-breakpoint
|
|
294
|
+
CREATE TABLE "product_media" (
|
|
295
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
296
|
+
"product_id" text NOT NULL,
|
|
297
|
+
"day_id" text,
|
|
298
|
+
"media_type" "product_media_type" NOT NULL,
|
|
299
|
+
"name" text NOT NULL,
|
|
300
|
+
"url" text NOT NULL,
|
|
301
|
+
"storage_key" text,
|
|
302
|
+
"mime_type" text,
|
|
303
|
+
"file_size" integer,
|
|
304
|
+
"alt_text" text,
|
|
305
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
306
|
+
"is_cover" boolean DEFAULT false NOT NULL,
|
|
307
|
+
"is_brochure" boolean DEFAULT false NOT NULL,
|
|
308
|
+
"is_brochure_current" boolean DEFAULT false NOT NULL,
|
|
309
|
+
"brochure_version" integer,
|
|
310
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
311
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
312
|
+
);
|
|
313
|
+
--> statement-breakpoint
|
|
314
|
+
CREATE TABLE "product_notes" (
|
|
315
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
316
|
+
"product_id" text NOT NULL,
|
|
317
|
+
"author_id" text NOT NULL,
|
|
318
|
+
"content" text NOT NULL,
|
|
319
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
320
|
+
);
|
|
321
|
+
--> statement-breakpoint
|
|
322
|
+
CREATE TABLE "product_versions" (
|
|
323
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
324
|
+
"product_id" text NOT NULL,
|
|
325
|
+
"version_number" integer NOT NULL,
|
|
326
|
+
"snapshot" jsonb NOT NULL,
|
|
327
|
+
"author_id" text NOT NULL,
|
|
328
|
+
"notes" text,
|
|
329
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
330
|
+
);
|
|
331
|
+
--> statement-breakpoint
|
|
332
|
+
CREATE TABLE "option_unit_translations" (
|
|
333
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
334
|
+
"unit_id" text NOT NULL,
|
|
335
|
+
"language_tag" text NOT NULL,
|
|
336
|
+
"name" text NOT NULL,
|
|
337
|
+
"short_description" text,
|
|
338
|
+
"description" text,
|
|
339
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
340
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
341
|
+
);
|
|
342
|
+
--> statement-breakpoint
|
|
343
|
+
CREATE TABLE "product_activation_settings" (
|
|
344
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
345
|
+
"product_id" text NOT NULL,
|
|
346
|
+
"activation_mode" "product_activation_mode" DEFAULT 'manual' NOT NULL,
|
|
347
|
+
"activate_at" timestamp with time zone,
|
|
348
|
+
"deactivate_at" timestamp with time zone,
|
|
349
|
+
"sell_at" timestamp with time zone,
|
|
350
|
+
"stop_sell_at" timestamp with time zone,
|
|
351
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
352
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
353
|
+
);
|
|
354
|
+
--> statement-breakpoint
|
|
355
|
+
CREATE TABLE "product_capabilities" (
|
|
356
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
357
|
+
"product_id" text NOT NULL,
|
|
358
|
+
"capability" "product_capability" NOT NULL,
|
|
359
|
+
"enabled" boolean DEFAULT true NOT NULL,
|
|
360
|
+
"notes" text,
|
|
361
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
362
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
363
|
+
);
|
|
364
|
+
--> statement-breakpoint
|
|
365
|
+
CREATE TABLE "product_delivery_formats" (
|
|
366
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
367
|
+
"product_id" text NOT NULL,
|
|
368
|
+
"format" "product_delivery_format" NOT NULL,
|
|
369
|
+
"is_default" boolean DEFAULT false NOT NULL,
|
|
370
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
371
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
372
|
+
);
|
|
373
|
+
--> statement-breakpoint
|
|
374
|
+
CREATE TABLE "product_faqs" (
|
|
375
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
376
|
+
"product_id" text NOT NULL,
|
|
377
|
+
"question" text NOT NULL,
|
|
378
|
+
"answer" text NOT NULL,
|
|
379
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
380
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
381
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
382
|
+
);
|
|
383
|
+
--> statement-breakpoint
|
|
384
|
+
CREATE TABLE "product_features" (
|
|
385
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
386
|
+
"product_id" text NOT NULL,
|
|
387
|
+
"feature_type" "product_feature_type" DEFAULT 'highlight' NOT NULL,
|
|
388
|
+
"title" text NOT NULL,
|
|
389
|
+
"description" text,
|
|
390
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
391
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
392
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
393
|
+
);
|
|
394
|
+
--> statement-breakpoint
|
|
395
|
+
CREATE TABLE "product_locations" (
|
|
396
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
397
|
+
"product_id" text NOT NULL,
|
|
398
|
+
"location_type" "product_location_type" DEFAULT 'point_of_interest' NOT NULL,
|
|
399
|
+
"title" text NOT NULL,
|
|
400
|
+
"address" text,
|
|
401
|
+
"city" text,
|
|
402
|
+
"country_code" text,
|
|
403
|
+
"latitude" double precision,
|
|
404
|
+
"longitude" double precision,
|
|
405
|
+
"google_place_id" text,
|
|
406
|
+
"apple_place_id" text,
|
|
407
|
+
"tripadvisor_location_id" text,
|
|
408
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
409
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
410
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
411
|
+
);
|
|
412
|
+
--> statement-breakpoint
|
|
413
|
+
CREATE TABLE "product_option_translations" (
|
|
414
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
415
|
+
"option_id" text NOT NULL,
|
|
416
|
+
"language_tag" text NOT NULL,
|
|
417
|
+
"name" text NOT NULL,
|
|
418
|
+
"short_description" text,
|
|
419
|
+
"description" text,
|
|
420
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
421
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
422
|
+
);
|
|
423
|
+
--> statement-breakpoint
|
|
424
|
+
CREATE TABLE "product_ticket_settings" (
|
|
425
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
426
|
+
"product_id" text NOT NULL,
|
|
427
|
+
"fulfillment_mode" "product_ticket_fulfillment" DEFAULT 'none' NOT NULL,
|
|
428
|
+
"default_delivery_format" "product_delivery_format" DEFAULT 'none' NOT NULL,
|
|
429
|
+
"ticket_per_unit" boolean DEFAULT false NOT NULL,
|
|
430
|
+
"barcode_format" text,
|
|
431
|
+
"voucher_message" text,
|
|
432
|
+
"ticket_message" text,
|
|
433
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
434
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
435
|
+
);
|
|
436
|
+
--> statement-breakpoint
|
|
437
|
+
CREATE TABLE "product_translations" (
|
|
438
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
439
|
+
"product_id" text NOT NULL,
|
|
440
|
+
"language_tag" text NOT NULL,
|
|
441
|
+
"slug" text,
|
|
442
|
+
"name" text NOT NULL,
|
|
443
|
+
"short_description" text,
|
|
444
|
+
"description" text,
|
|
445
|
+
"inclusions_html" text,
|
|
446
|
+
"exclusions_html" text,
|
|
447
|
+
"terms_html" text,
|
|
448
|
+
"seo_title" text,
|
|
449
|
+
"seo_description" text,
|
|
450
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
451
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
452
|
+
);
|
|
453
|
+
--> statement-breakpoint
|
|
454
|
+
CREATE TABLE "product_visibility_settings" (
|
|
455
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
456
|
+
"product_id" text NOT NULL,
|
|
457
|
+
"is_searchable" boolean DEFAULT false NOT NULL,
|
|
458
|
+
"is_bookable" boolean DEFAULT false NOT NULL,
|
|
459
|
+
"is_featured" boolean DEFAULT false NOT NULL,
|
|
460
|
+
"requires_authentication" boolean DEFAULT false NOT NULL,
|
|
461
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
462
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
463
|
+
);
|
|
464
|
+
--> statement-breakpoint
|
|
465
|
+
CREATE TABLE "destination_translations" (
|
|
466
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
467
|
+
"destination_id" text NOT NULL,
|
|
468
|
+
"language_tag" text NOT NULL,
|
|
469
|
+
"name" text NOT NULL,
|
|
470
|
+
"description" text,
|
|
471
|
+
"seo_title" text,
|
|
472
|
+
"seo_description" text,
|
|
473
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
474
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
475
|
+
);
|
|
476
|
+
--> statement-breakpoint
|
|
477
|
+
CREATE TABLE "destinations" (
|
|
478
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
479
|
+
"parent_id" text,
|
|
480
|
+
"slug" text NOT NULL,
|
|
481
|
+
"code" text,
|
|
482
|
+
"canonical_place_id" text,
|
|
483
|
+
"destination_type" text DEFAULT 'destination' NOT NULL,
|
|
484
|
+
"latitude" double precision,
|
|
485
|
+
"longitude" double precision,
|
|
486
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
487
|
+
"active" boolean DEFAULT true NOT NULL,
|
|
488
|
+
"metadata" jsonb,
|
|
489
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
490
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
491
|
+
);
|
|
492
|
+
--> statement-breakpoint
|
|
493
|
+
CREATE TABLE "product_categories" (
|
|
494
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
495
|
+
"parent_id" text,
|
|
496
|
+
"name" text NOT NULL,
|
|
497
|
+
"slug" text NOT NULL,
|
|
498
|
+
"description" text,
|
|
499
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
500
|
+
"active" boolean DEFAULT true NOT NULL,
|
|
501
|
+
"customer_payment_policy" jsonb,
|
|
502
|
+
"metadata" jsonb,
|
|
503
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
504
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
505
|
+
);
|
|
506
|
+
--> statement-breakpoint
|
|
507
|
+
CREATE TABLE "product_category_products" (
|
|
508
|
+
"product_id" text NOT NULL,
|
|
509
|
+
"category_id" text NOT NULL,
|
|
510
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
511
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
512
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
513
|
+
CONSTRAINT "product_category_products_product_id_category_id_pk" PRIMARY KEY("product_id","category_id")
|
|
514
|
+
);
|
|
515
|
+
--> statement-breakpoint
|
|
516
|
+
CREATE TABLE "product_category_translations" (
|
|
517
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
518
|
+
"category_id" text NOT NULL,
|
|
519
|
+
"language_tag" text NOT NULL,
|
|
520
|
+
"name" text NOT NULL,
|
|
521
|
+
"description" text,
|
|
522
|
+
"seo_title" text,
|
|
523
|
+
"seo_description" text,
|
|
524
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
525
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
526
|
+
);
|
|
527
|
+
--> statement-breakpoint
|
|
528
|
+
CREATE TABLE "product_destinations" (
|
|
529
|
+
"product_id" text NOT NULL,
|
|
530
|
+
"destination_id" text NOT NULL,
|
|
531
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
532
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
533
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
534
|
+
CONSTRAINT "product_destinations_product_id_destination_id_pk" PRIMARY KEY("product_id","destination_id")
|
|
535
|
+
);
|
|
536
|
+
--> statement-breakpoint
|
|
537
|
+
CREATE TABLE "product_tag_products" (
|
|
538
|
+
"product_id" text NOT NULL,
|
|
539
|
+
"tag_id" text NOT NULL,
|
|
540
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
541
|
+
CONSTRAINT "product_tag_products_product_id_tag_id_pk" PRIMARY KEY("product_id","tag_id")
|
|
542
|
+
);
|
|
543
|
+
--> statement-breakpoint
|
|
544
|
+
CREATE TABLE "product_tag_translations" (
|
|
545
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
546
|
+
"tag_id" text NOT NULL,
|
|
547
|
+
"language_tag" text NOT NULL,
|
|
548
|
+
"name" text NOT NULL,
|
|
549
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
550
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
551
|
+
);
|
|
552
|
+
--> statement-breakpoint
|
|
553
|
+
CREATE TABLE "product_tags" (
|
|
554
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
555
|
+
"name" text NOT NULL,
|
|
556
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
557
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
558
|
+
);
|
|
559
|
+
--> statement-breakpoint
|
|
560
|
+
CREATE TABLE "product_types" (
|
|
561
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
562
|
+
"name" text NOT NULL,
|
|
563
|
+
"code" text NOT NULL,
|
|
564
|
+
"description" text,
|
|
565
|
+
"sort_order" integer DEFAULT 0 NOT NULL,
|
|
566
|
+
"active" boolean DEFAULT true NOT NULL,
|
|
567
|
+
"metadata" jsonb,
|
|
568
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
569
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
570
|
+
);
|
|
571
|
+
--> statement-breakpoint
|
|
572
|
+
ALTER TABLE "option_extra_configs" ADD CONSTRAINT "option_extra_configs_product_extra_id_product_extras_id_fk" FOREIGN KEY ("product_extra_id") REFERENCES "public"."product_extras"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
573
|
+
ALTER TABLE "option_units" ADD CONSTRAINT "option_units_option_id_product_options_id_fk" FOREIGN KEY ("option_id") REFERENCES "public"."product_options"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
574
|
+
ALTER TABLE "product_options" ADD CONSTRAINT "product_options_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
575
|
+
ALTER TABLE "product_pax_pricing_tiers" ADD CONSTRAINT "product_pax_pricing_tiers_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
576
|
+
ALTER TABLE "product_pax_pricing_tiers" ADD CONSTRAINT "product_pax_pricing_tiers_option_unit_id_option_units_id_fk" FOREIGN KEY ("option_unit_id") REFERENCES "public"."option_units"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
577
|
+
ALTER TABLE "product_day_services" ADD CONSTRAINT "product_day_services_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
578
|
+
ALTER TABLE "product_day_translations" ADD CONSTRAINT "product_day_translations_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
579
|
+
ALTER TABLE "product_days" ADD CONSTRAINT "product_days_itinerary_id_product_itineraries_id_fk" FOREIGN KEY ("itinerary_id") REFERENCES "public"."product_itineraries"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
580
|
+
ALTER TABLE "product_itineraries" ADD CONSTRAINT "product_itineraries_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
581
|
+
ALTER TABLE "product_media" ADD CONSTRAINT "product_media_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
582
|
+
ALTER TABLE "product_media" ADD CONSTRAINT "product_media_day_id_product_days_id_fk" FOREIGN KEY ("day_id") REFERENCES "public"."product_days"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
583
|
+
ALTER TABLE "product_notes" ADD CONSTRAINT "product_notes_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
584
|
+
ALTER TABLE "product_versions" ADD CONSTRAINT "product_versions_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
585
|
+
ALTER TABLE "option_unit_translations" ADD CONSTRAINT "option_unit_translations_unit_id_option_units_id_fk" FOREIGN KEY ("unit_id") REFERENCES "public"."option_units"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
586
|
+
ALTER TABLE "product_activation_settings" ADD CONSTRAINT "product_activation_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
587
|
+
ALTER TABLE "product_capabilities" ADD CONSTRAINT "product_capabilities_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
588
|
+
ALTER TABLE "product_delivery_formats" ADD CONSTRAINT "product_delivery_formats_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
589
|
+
ALTER TABLE "product_faqs" ADD CONSTRAINT "product_faqs_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
590
|
+
ALTER TABLE "product_features" ADD CONSTRAINT "product_features_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
591
|
+
ALTER TABLE "product_locations" ADD CONSTRAINT "product_locations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
592
|
+
ALTER TABLE "product_option_translations" ADD CONSTRAINT "product_option_translations_option_id_product_options_id_fk" FOREIGN KEY ("option_id") REFERENCES "public"."product_options"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
593
|
+
ALTER TABLE "product_ticket_settings" ADD CONSTRAINT "product_ticket_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
594
|
+
ALTER TABLE "product_translations" ADD CONSTRAINT "product_translations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
595
|
+
ALTER TABLE "product_visibility_settings" ADD CONSTRAINT "product_visibility_settings_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
596
|
+
ALTER TABLE "destination_translations" ADD CONSTRAINT "destination_translations_destination_id_destinations_id_fk" FOREIGN KEY ("destination_id") REFERENCES "public"."destinations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
597
|
+
ALTER TABLE "product_category_products" ADD CONSTRAINT "product_category_products_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
598
|
+
ALTER TABLE "product_category_products" ADD CONSTRAINT "product_category_products_category_id_product_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."product_categories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
599
|
+
ALTER TABLE "product_category_translations" ADD CONSTRAINT "product_category_translations_category_id_product_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."product_categories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
600
|
+
ALTER TABLE "product_destinations" ADD CONSTRAINT "product_destinations_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
601
|
+
ALTER TABLE "product_destinations" ADD CONSTRAINT "product_destinations_destination_id_destinations_id_fk" FOREIGN KEY ("destination_id") REFERENCES "public"."destinations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
602
|
+
ALTER TABLE "product_tag_products" ADD CONSTRAINT "product_tag_products_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
603
|
+
ALTER TABLE "product_tag_products" ADD CONSTRAINT "product_tag_products_tag_id_product_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."product_tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
604
|
+
ALTER TABLE "product_tag_translations" ADD CONSTRAINT "product_tag_translations_tag_id_product_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."product_tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
605
|
+
CREATE INDEX "idx_bipd_product" ON "booking_item_product_details" USING btree ("product_id");--> statement-breakpoint
|
|
606
|
+
CREATE INDEX "idx_bipd_option" ON "booking_item_product_details" USING btree ("option_id");--> statement-breakpoint
|
|
607
|
+
CREATE INDEX "idx_bipd_unit" ON "booking_item_product_details" USING btree ("unit_id");--> statement-breakpoint
|
|
608
|
+
CREATE INDEX "idx_bipd_supplier_service" ON "booking_item_product_details" USING btree ("supplier_service_id");--> statement-breakpoint
|
|
609
|
+
CREATE INDEX "idx_bpd_product" ON "booking_product_details" USING btree ("product_id");--> statement-breakpoint
|
|
610
|
+
CREATE INDEX "idx_bpd_option" ON "booking_product_details" USING btree ("option_id");--> statement-breakpoint
|
|
611
|
+
CREATE INDEX "products_sourced_content_locale_fresh_idx" ON "products_sourced_content" USING btree ("locale","fresh_until");--> statement-breakpoint
|
|
612
|
+
CREATE INDEX "products_sourced_content_returned_locale_idx" ON "products_sourced_content" USING btree ("entity_id","returned_locale");--> statement-breakpoint
|
|
613
|
+
CREATE INDEX "products_sourced_content_schema_version_idx" ON "products_sourced_content" USING btree ("content_schema_version");--> statement-breakpoint
|
|
614
|
+
CREATE INDEX "extras_sourced_content_locale_fresh_idx" ON "extras_sourced_content" USING btree ("locale","fresh_until");--> statement-breakpoint
|
|
615
|
+
CREATE INDEX "extras_sourced_content_returned_locale_idx" ON "extras_sourced_content" USING btree ("entity_id","returned_locale");--> statement-breakpoint
|
|
616
|
+
CREATE INDEX "extras_sourced_content_schema_version_idx" ON "extras_sourced_content" USING btree ("content_schema_version");--> statement-breakpoint
|
|
617
|
+
CREATE INDEX "idx_option_extra_configs_sort_default" ON "option_extra_configs" USING btree ("sort_order","is_default");--> statement-breakpoint
|
|
618
|
+
CREATE INDEX "idx_option_extra_configs_option_sort_default" ON "option_extra_configs" USING btree ("option_id","sort_order","is_default");--> statement-breakpoint
|
|
619
|
+
CREATE INDEX "idx_option_extra_configs_extra_sort_default" ON "option_extra_configs" USING btree ("product_extra_id","sort_order","is_default");--> statement-breakpoint
|
|
620
|
+
CREATE INDEX "idx_option_extra_configs_active_sort_default" ON "option_extra_configs" USING btree ("active","sort_order","is_default");--> statement-breakpoint
|
|
621
|
+
CREATE UNIQUE INDEX "uidx_option_extra_configs_option_extra" ON "option_extra_configs" USING btree ("option_id","product_extra_id");--> statement-breakpoint
|
|
622
|
+
CREATE INDEX "idx_product_extras_sort_name" ON "product_extras" USING btree ("sort_order","name");--> statement-breakpoint
|
|
623
|
+
CREATE INDEX "idx_product_extras_product_sort_name" ON "product_extras" USING btree ("product_id","sort_order","name");--> statement-breakpoint
|
|
624
|
+
CREATE INDEX "idx_product_extras_supplier_sort_name" ON "product_extras" USING btree ("supplier_id","sort_order","name");--> statement-breakpoint
|
|
625
|
+
CREATE INDEX "idx_product_extras_active_sort_name" ON "product_extras" USING btree ("active","sort_order","name");--> statement-breakpoint
|
|
626
|
+
CREATE UNIQUE INDEX "uidx_product_extras_product_code" ON "product_extras" USING btree ("product_id","code");--> statement-breakpoint
|
|
627
|
+
CREATE INDEX "idx_option_units_option" ON "option_units" USING btree ("option_id");--> statement-breakpoint
|
|
628
|
+
CREATE INDEX "idx_option_units_option_sort" ON "option_units" USING btree ("option_id","sort_order","created_at");--> statement-breakpoint
|
|
629
|
+
CREATE INDEX "idx_option_units_type" ON "option_units" USING btree ("unit_type");--> statement-breakpoint
|
|
630
|
+
CREATE UNIQUE INDEX "uidx_option_units_option_code" ON "option_units" USING btree ("option_id","code");--> statement-breakpoint
|
|
631
|
+
CREATE INDEX "idx_product_options_product" ON "product_options" USING btree ("product_id");--> statement-breakpoint
|
|
632
|
+
CREATE INDEX "idx_product_options_product_sort" ON "product_options" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
|
|
633
|
+
CREATE INDEX "idx_product_options_status" ON "product_options" USING btree ("status");--> statement-breakpoint
|
|
634
|
+
CREATE INDEX "idx_product_options_default" ON "product_options" USING btree ("is_default");--> statement-breakpoint
|
|
635
|
+
CREATE UNIQUE INDEX "uidx_product_options_product_code" ON "product_options" USING btree ("product_id","code");--> statement-breakpoint
|
|
636
|
+
CREATE INDEX "idx_pax_tiers_product" ON "product_pax_pricing_tiers" USING btree ("product_id");--> statement-breakpoint
|
|
637
|
+
CREATE INDEX "idx_pax_tiers_unit" ON "product_pax_pricing_tiers" USING btree ("option_unit_id");--> statement-breakpoint
|
|
638
|
+
CREATE UNIQUE INDEX "uidx_pax_tiers_unit_pax" ON "product_pax_pricing_tiers" USING btree ("option_unit_id","tier_pax");--> statement-breakpoint
|
|
639
|
+
CREATE INDEX "idx_products_status" ON "products" USING btree ("status");--> statement-breakpoint
|
|
640
|
+
CREATE INDEX "idx_products_facility" ON "products" USING btree ("facility_id");--> statement-breakpoint
|
|
641
|
+
CREATE INDEX "idx_products_supplier" ON "products" USING btree ("supplier_id");--> statement-breakpoint
|
|
642
|
+
CREATE INDEX "idx_products_product_type" ON "products" USING btree ("product_type_id");--> statement-breakpoint
|
|
643
|
+
CREATE INDEX "idx_products_contract_template" ON "products" USING btree ("contract_template_id");--> statement-breakpoint
|
|
644
|
+
CREATE INDEX "idx_products_status_created" ON "products" USING btree ("status","created_at");--> statement-breakpoint
|
|
645
|
+
CREATE INDEX "idx_products_booking_mode_created" ON "products" USING btree ("booking_mode","created_at");--> statement-breakpoint
|
|
646
|
+
CREATE INDEX "idx_products_capacity_mode_created" ON "products" USING btree ("capacity_mode","created_at");--> statement-breakpoint
|
|
647
|
+
CREATE INDEX "idx_products_visibility_created" ON "products" USING btree ("visibility","created_at");--> statement-breakpoint
|
|
648
|
+
CREATE INDEX "idx_products_activated_created" ON "products" USING btree ("activated","created_at");--> statement-breakpoint
|
|
649
|
+
CREATE INDEX "idx_products_facility_created" ON "products" USING btree ("facility_id","created_at");--> statement-breakpoint
|
|
650
|
+
CREATE INDEX "idx_products_supplier_created" ON "products" USING btree ("supplier_id","created_at");--> statement-breakpoint
|
|
651
|
+
CREATE INDEX "idx_products_product_type_created" ON "products" USING btree ("product_type_id","created_at");--> statement-breakpoint
|
|
652
|
+
CREATE INDEX "idx_products_public_created" ON "products" USING btree ("status","activated","visibility","created_at");--> statement-breakpoint
|
|
653
|
+
CREATE INDEX "idx_products_name_trgm" ON "products" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
|
|
654
|
+
CREATE INDEX "idx_products_description_trgm" ON "products" USING gin ("description" gin_trgm_ops);--> statement-breakpoint
|
|
655
|
+
CREATE INDEX "idx_product_day_services_day" ON "product_day_services" USING btree ("day_id");--> statement-breakpoint
|
|
656
|
+
CREATE INDEX "idx_product_day_services_day_sort" ON "product_day_services" USING btree ("day_id","sort_order");--> statement-breakpoint
|
|
657
|
+
CREATE INDEX "idx_product_day_services_supplier_service" ON "product_day_services" USING btree ("supplier_service_id");--> statement-breakpoint
|
|
658
|
+
CREATE INDEX "idx_product_day_translations_day" ON "product_day_translations" USING btree ("day_id");--> statement-breakpoint
|
|
659
|
+
CREATE INDEX "idx_product_day_translations_language" ON "product_day_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
660
|
+
CREATE UNIQUE INDEX "uidx_product_day_translations_day_language" ON "product_day_translations" USING btree ("day_id","language_tag");--> statement-breakpoint
|
|
661
|
+
CREATE INDEX "idx_product_days_itinerary" ON "product_days" USING btree ("itinerary_id");--> statement-breakpoint
|
|
662
|
+
CREATE INDEX "idx_product_days_itinerary_day_number" ON "product_days" USING btree ("itinerary_id","day_number");--> statement-breakpoint
|
|
663
|
+
CREATE INDEX "idx_product_itineraries_product" ON "product_itineraries" USING btree ("product_id");--> statement-breakpoint
|
|
664
|
+
CREATE INDEX "idx_product_itineraries_product_sort" ON "product_itineraries" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
|
|
665
|
+
CREATE INDEX "idx_product_itineraries_product_default" ON "product_itineraries" USING btree ("product_id","is_default");--> statement-breakpoint
|
|
666
|
+
CREATE UNIQUE INDEX "uidx_product_itineraries_default" ON "product_itineraries" USING btree ("product_id") WHERE "product_itineraries"."is_default" = true;--> statement-breakpoint
|
|
667
|
+
CREATE INDEX "idx_product_media_product" ON "product_media" USING btree ("product_id");--> statement-breakpoint
|
|
668
|
+
CREATE INDEX "idx_product_media_day" ON "product_media" USING btree ("day_id");--> statement-breakpoint
|
|
669
|
+
CREATE INDEX "idx_product_media_product_day" ON "product_media" USING btree ("product_id","day_id");--> statement-breakpoint
|
|
670
|
+
CREATE INDEX "idx_product_media_product_cover_sort" ON "product_media" USING btree ("product_id","is_cover","sort_order","created_at");--> statement-breakpoint
|
|
671
|
+
CREATE INDEX "idx_product_media_product_day_cover_sort" ON "product_media" USING btree ("product_id","day_id","is_cover","sort_order","created_at");--> statement-breakpoint
|
|
672
|
+
CREATE INDEX "idx_product_media_product_brochure_current_version" ON "product_media" USING btree ("product_id","is_brochure","day_id","is_brochure_current","brochure_version","updated_at","created_at");--> statement-breakpoint
|
|
673
|
+
CREATE INDEX "idx_product_notes_product" ON "product_notes" USING btree ("product_id");--> statement-breakpoint
|
|
674
|
+
CREATE INDEX "idx_product_notes_product_created" ON "product_notes" USING btree ("product_id","created_at");--> statement-breakpoint
|
|
675
|
+
CREATE INDEX "idx_product_versions_product" ON "product_versions" USING btree ("product_id");--> statement-breakpoint
|
|
676
|
+
CREATE INDEX "idx_product_versions_product_version" ON "product_versions" USING btree ("product_id","version_number");--> statement-breakpoint
|
|
677
|
+
CREATE INDEX "idx_option_unit_translations_unit" ON "option_unit_translations" USING btree ("unit_id");--> statement-breakpoint
|
|
678
|
+
CREATE INDEX "idx_option_unit_translations_language" ON "option_unit_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
679
|
+
CREATE INDEX "idx_option_unit_translations_unit_language_created" ON "option_unit_translations" USING btree ("unit_id","language_tag","created_at");--> statement-breakpoint
|
|
680
|
+
CREATE INDEX "idx_option_unit_translations_language_created" ON "option_unit_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
681
|
+
CREATE UNIQUE INDEX "uidx_option_unit_translations_unit_language" ON "option_unit_translations" USING btree ("unit_id","language_tag");--> statement-breakpoint
|
|
682
|
+
CREATE UNIQUE INDEX "uidx_product_activation_settings_product" ON "product_activation_settings" USING btree ("product_id");--> statement-breakpoint
|
|
683
|
+
CREATE INDEX "idx_product_activation_settings_created" ON "product_activation_settings" USING btree ("created_at");--> statement-breakpoint
|
|
684
|
+
CREATE INDEX "idx_product_activation_settings_mode" ON "product_activation_settings" USING btree ("activation_mode");--> statement-breakpoint
|
|
685
|
+
CREATE INDEX "idx_product_activation_settings_mode_created" ON "product_activation_settings" USING btree ("activation_mode","created_at");--> statement-breakpoint
|
|
686
|
+
CREATE INDEX "idx_product_capabilities_product" ON "product_capabilities" USING btree ("product_id");--> statement-breakpoint
|
|
687
|
+
CREATE INDEX "idx_product_capabilities_capability" ON "product_capabilities" USING btree ("capability");--> statement-breakpoint
|
|
688
|
+
CREATE INDEX "idx_product_capabilities_capability_created" ON "product_capabilities" USING btree ("capability","created_at");--> statement-breakpoint
|
|
689
|
+
CREATE INDEX "idx_product_capabilities_enabled_capability_created" ON "product_capabilities" USING btree ("enabled","capability","created_at");--> statement-breakpoint
|
|
690
|
+
CREATE UNIQUE INDEX "uidx_product_capabilities_product_capability" ON "product_capabilities" USING btree ("product_id","capability");--> statement-breakpoint
|
|
691
|
+
CREATE INDEX "idx_product_delivery_formats_product" ON "product_delivery_formats" USING btree ("product_id");--> statement-breakpoint
|
|
692
|
+
CREATE INDEX "idx_product_delivery_formats_default_created" ON "product_delivery_formats" USING btree ("is_default","created_at");--> statement-breakpoint
|
|
693
|
+
CREATE INDEX "idx_product_delivery_formats_product_default_created" ON "product_delivery_formats" USING btree ("product_id","is_default","created_at");--> statement-breakpoint
|
|
694
|
+
CREATE INDEX "idx_product_delivery_formats_format_default_created" ON "product_delivery_formats" USING btree ("format","is_default","created_at");--> statement-breakpoint
|
|
695
|
+
CREATE UNIQUE INDEX "uidx_product_delivery_formats_product_format" ON "product_delivery_formats" USING btree ("product_id","format");--> statement-breakpoint
|
|
696
|
+
CREATE INDEX "idx_product_faqs_product" ON "product_faqs" USING btree ("product_id");--> statement-breakpoint
|
|
697
|
+
CREATE INDEX "idx_product_faqs_sort" ON "product_faqs" USING btree ("sort_order","created_at");--> statement-breakpoint
|
|
698
|
+
CREATE INDEX "idx_product_faqs_product_sort" ON "product_faqs" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
|
|
699
|
+
CREATE INDEX "idx_product_features_product" ON "product_features" USING btree ("product_id");--> statement-breakpoint
|
|
700
|
+
CREATE INDEX "idx_product_features_sort" ON "product_features" USING btree ("sort_order","created_at");--> statement-breakpoint
|
|
701
|
+
CREATE INDEX "idx_product_features_product_sort" ON "product_features" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
|
|
702
|
+
CREATE INDEX "idx_product_features_type" ON "product_features" USING btree ("feature_type");--> statement-breakpoint
|
|
703
|
+
CREATE INDEX "idx_product_features_type_sort" ON "product_features" USING btree ("feature_type","sort_order","created_at");--> statement-breakpoint
|
|
704
|
+
CREATE INDEX "idx_product_features_product_type_sort" ON "product_features" USING btree ("product_id","feature_type","sort_order","created_at");--> statement-breakpoint
|
|
705
|
+
CREATE INDEX "idx_product_locations_product" ON "product_locations" USING btree ("product_id");--> statement-breakpoint
|
|
706
|
+
CREATE INDEX "idx_product_locations_sort" ON "product_locations" USING btree ("sort_order","created_at");--> statement-breakpoint
|
|
707
|
+
CREATE INDEX "idx_product_locations_product_sort" ON "product_locations" USING btree ("product_id","sort_order","created_at");--> statement-breakpoint
|
|
708
|
+
CREATE INDEX "idx_product_locations_type" ON "product_locations" USING btree ("location_type");--> statement-breakpoint
|
|
709
|
+
CREATE INDEX "idx_product_locations_type_product" ON "product_locations" USING btree ("location_type","product_id");--> statement-breakpoint
|
|
710
|
+
CREATE INDEX "idx_product_locations_type_sort" ON "product_locations" USING btree ("location_type","sort_order","created_at");--> statement-breakpoint
|
|
711
|
+
CREATE INDEX "idx_product_locations_product_type_sort" ON "product_locations" USING btree ("product_id","location_type","sort_order","created_at");--> statement-breakpoint
|
|
712
|
+
CREATE INDEX "idx_product_locations_country_product" ON "product_locations" USING btree ("country_code","product_id");--> statement-breakpoint
|
|
713
|
+
CREATE INDEX "idx_product_locations_title_trgm" ON "product_locations" USING gin ("title" gin_trgm_ops);--> statement-breakpoint
|
|
714
|
+
CREATE INDEX "idx_product_locations_city_trgm" ON "product_locations" USING gin ("city" gin_trgm_ops);--> statement-breakpoint
|
|
715
|
+
CREATE INDEX "idx_product_option_translations_option" ON "product_option_translations" USING btree ("option_id");--> statement-breakpoint
|
|
716
|
+
CREATE INDEX "idx_product_option_translations_language" ON "product_option_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
717
|
+
CREATE INDEX "idx_product_option_translations_option_language_created" ON "product_option_translations" USING btree ("option_id","language_tag","created_at");--> statement-breakpoint
|
|
718
|
+
CREATE INDEX "idx_product_option_translations_language_created" ON "product_option_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
719
|
+
CREATE UNIQUE INDEX "uidx_product_option_translations_option_language" ON "product_option_translations" USING btree ("option_id","language_tag");--> statement-breakpoint
|
|
720
|
+
CREATE UNIQUE INDEX "uidx_product_ticket_settings_product" ON "product_ticket_settings" USING btree ("product_id");--> statement-breakpoint
|
|
721
|
+
CREATE INDEX "idx_product_ticket_settings_created" ON "product_ticket_settings" USING btree ("created_at");--> statement-breakpoint
|
|
722
|
+
CREATE INDEX "idx_product_ticket_settings_fulfillment_created" ON "product_ticket_settings" USING btree ("fulfillment_mode","created_at");--> statement-breakpoint
|
|
723
|
+
CREATE INDEX "idx_product_translations_product" ON "product_translations" USING btree ("product_id");--> statement-breakpoint
|
|
724
|
+
CREATE INDEX "idx_product_translations_language" ON "product_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
725
|
+
CREATE INDEX "idx_product_translations_product_language_created" ON "product_translations" USING btree ("product_id","language_tag","created_at");--> statement-breakpoint
|
|
726
|
+
CREATE INDEX "idx_product_translations_language_created" ON "product_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
727
|
+
CREATE UNIQUE INDEX "uidx_product_translations_product_language" ON "product_translations" USING btree ("product_id","language_tag");--> statement-breakpoint
|
|
728
|
+
CREATE UNIQUE INDEX "uidx_product_visibility_settings_product" ON "product_visibility_settings" USING btree ("product_id");--> statement-breakpoint
|
|
729
|
+
CREATE INDEX "idx_product_visibility_settings_created" ON "product_visibility_settings" USING btree ("created_at");--> statement-breakpoint
|
|
730
|
+
CREATE INDEX "idx_product_visibility_settings_searchable_created" ON "product_visibility_settings" USING btree ("is_searchable","created_at");--> statement-breakpoint
|
|
731
|
+
CREATE INDEX "idx_product_visibility_settings_bookable_created" ON "product_visibility_settings" USING btree ("is_bookable","created_at");--> statement-breakpoint
|
|
732
|
+
CREATE INDEX "idx_product_visibility_settings_featured_product" ON "product_visibility_settings" USING btree ("is_featured","product_id");--> statement-breakpoint
|
|
733
|
+
CREATE UNIQUE INDEX "uidx_destination_translations_locale" ON "destination_translations" USING btree ("destination_id","language_tag");--> statement-breakpoint
|
|
734
|
+
CREATE INDEX "idx_destination_translations_language" ON "destination_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
735
|
+
CREATE INDEX "idx_destination_translations_destination_language_created" ON "destination_translations" USING btree ("destination_id","language_tag","created_at");--> statement-breakpoint
|
|
736
|
+
CREATE INDEX "idx_destination_translations_language_created" ON "destination_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
737
|
+
CREATE INDEX "idx_destination_translations_name_trgm" ON "destination_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
|
|
738
|
+
CREATE INDEX "idx_destination_translations_description_trgm" ON "destination_translations" USING gin ("description" gin_trgm_ops);--> statement-breakpoint
|
|
739
|
+
CREATE UNIQUE INDEX "uidx_destinations_slug" ON "destinations" USING btree ("slug");--> statement-breakpoint
|
|
740
|
+
CREATE UNIQUE INDEX "uidx_destinations_code" ON "destinations" USING btree ("code");--> statement-breakpoint
|
|
741
|
+
CREATE INDEX "idx_destinations_parent" ON "destinations" USING btree ("parent_id");--> statement-breakpoint
|
|
742
|
+
CREATE INDEX "idx_destinations_active" ON "destinations" USING btree ("active");--> statement-breakpoint
|
|
743
|
+
CREATE INDEX "idx_destinations_canonical_place" ON "destinations" USING btree ("canonical_place_id");--> statement-breakpoint
|
|
744
|
+
CREATE INDEX "idx_destinations_sort_slug" ON "destinations" USING btree ("sort_order","slug");--> statement-breakpoint
|
|
745
|
+
CREATE INDEX "idx_destinations_active_sort_slug" ON "destinations" USING btree ("active","sort_order","slug");--> statement-breakpoint
|
|
746
|
+
CREATE INDEX "idx_destinations_type_sort_slug" ON "destinations" USING btree ("destination_type","sort_order","slug");--> statement-breakpoint
|
|
747
|
+
CREATE INDEX "idx_destinations_parent_sort_slug" ON "destinations" USING btree ("parent_id","sort_order","slug");--> statement-breakpoint
|
|
748
|
+
CREATE UNIQUE INDEX "uidx_product_categories_slug" ON "product_categories" USING btree ("slug");--> statement-breakpoint
|
|
749
|
+
CREATE INDEX "idx_product_categories_parent" ON "product_categories" USING btree ("parent_id");--> statement-breakpoint
|
|
750
|
+
CREATE INDEX "idx_product_categories_active" ON "product_categories" USING btree ("active");--> statement-breakpoint
|
|
751
|
+
CREATE INDEX "idx_product_categories_sort_name" ON "product_categories" USING btree ("sort_order","name");--> statement-breakpoint
|
|
752
|
+
CREATE INDEX "idx_product_categories_active_sort_name" ON "product_categories" USING btree ("active","sort_order","name");--> statement-breakpoint
|
|
753
|
+
CREATE INDEX "idx_product_categories_parent_sort_name" ON "product_categories" USING btree ("parent_id","sort_order","name");--> statement-breakpoint
|
|
754
|
+
CREATE INDEX "idx_product_categories_name_trgm" ON "product_categories" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
|
|
755
|
+
CREATE INDEX "idx_product_categories_slug_trgm" ON "product_categories" USING gin ("slug" gin_trgm_ops);--> statement-breakpoint
|
|
756
|
+
CREATE INDEX "idx_pcp_product_sort" ON "product_category_products" USING btree ("product_id","sort_order");--> statement-breakpoint
|
|
757
|
+
CREATE INDEX "idx_pcp_category" ON "product_category_products" USING btree ("category_id");--> statement-breakpoint
|
|
758
|
+
CREATE UNIQUE INDEX "uidx_product_category_translations_locale" ON "product_category_translations" USING btree ("category_id","language_tag");--> statement-breakpoint
|
|
759
|
+
CREATE INDEX "idx_product_category_translations_language" ON "product_category_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
760
|
+
CREATE INDEX "idx_product_category_translations_category_language_created" ON "product_category_translations" USING btree ("category_id","language_tag","created_at");--> statement-breakpoint
|
|
761
|
+
CREATE INDEX "idx_product_category_translations_language_created" ON "product_category_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
762
|
+
CREATE INDEX "idx_product_destinations_product_sort" ON "product_destinations" USING btree ("product_id","sort_order");--> statement-breakpoint
|
|
763
|
+
CREATE INDEX "idx_product_destinations_destination_sort" ON "product_destinations" USING btree ("destination_id","sort_order");--> statement-breakpoint
|
|
764
|
+
CREATE INDEX "idx_ptp_tag" ON "product_tag_products" USING btree ("tag_id");--> statement-breakpoint
|
|
765
|
+
CREATE UNIQUE INDEX "uidx_product_tag_translations_locale" ON "product_tag_translations" USING btree ("tag_id","language_tag");--> statement-breakpoint
|
|
766
|
+
CREATE INDEX "idx_product_tag_translations_language" ON "product_tag_translations" USING btree ("language_tag");--> statement-breakpoint
|
|
767
|
+
CREATE INDEX "idx_product_tag_translations_tag_language_created" ON "product_tag_translations" USING btree ("tag_id","language_tag","created_at");--> statement-breakpoint
|
|
768
|
+
CREATE INDEX "idx_product_tag_translations_language_created" ON "product_tag_translations" USING btree ("language_tag","created_at");--> statement-breakpoint
|
|
769
|
+
CREATE UNIQUE INDEX "uidx_product_tags_name" ON "product_tags" USING btree ("name");--> statement-breakpoint
|
|
770
|
+
CREATE INDEX "idx_product_tags_name_trgm" ON "product_tags" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
|
|
771
|
+
CREATE UNIQUE INDEX "uidx_product_types_code" ON "product_types" USING btree ("code");--> statement-breakpoint
|
|
772
|
+
CREATE INDEX "idx_product_types_active" ON "product_types" USING btree ("active");--> statement-breakpoint
|
|
773
|
+
CREATE INDEX "idx_product_types_sort_name" ON "product_types" USING btree ("sort_order","name");--> statement-breakpoint
|
|
774
|
+
CREATE INDEX "idx_product_types_active_sort_name" ON "product_types" USING btree ("active","sort_order","name");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/inventory",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -162,26 +162,29 @@
|
|
|
162
162
|
"pdf-lib": "^1.17.1",
|
|
163
163
|
"sanitize-html": "^2.17.4",
|
|
164
164
|
"zod": "^4.3.6",
|
|
165
|
-
"@voyant-travel/action-ledger": "^0.105.
|
|
166
|
-
"@voyant-travel/catalog": "^0.124.
|
|
167
|
-
"@voyant-travel/core": "^0.110.0",
|
|
168
|
-
"@voyant-travel/db": "^0.108.3",
|
|
165
|
+
"@voyant-travel/action-ledger": "^0.105.3",
|
|
166
|
+
"@voyant-travel/catalog": "^0.124.1",
|
|
169
167
|
"@voyant-travel/extras-contracts": "^0.104.2",
|
|
168
|
+
"@voyant-travel/core": "^0.110.0",
|
|
169
|
+
"@voyant-travel/db": "^0.108.4",
|
|
170
170
|
"@voyant-travel/hono": "^0.112.2",
|
|
171
|
-
"@voyant-travel/commerce": "^0.8.
|
|
172
|
-
"@voyant-travel/products-contracts": "^0.105.7",
|
|
171
|
+
"@voyant-travel/commerce": "^0.8.1",
|
|
173
172
|
"@voyant-travel/storage": "^0.105.0",
|
|
174
173
|
"@voyant-travel/utils": "^0.105.2",
|
|
175
|
-
"@voyant-travel/
|
|
174
|
+
"@voyant-travel/products-contracts": "^0.105.7",
|
|
175
|
+
"@voyant-travel/operations": "^0.1.7"
|
|
176
176
|
},
|
|
177
177
|
"devDependencies": {
|
|
178
178
|
"@types/sanitize-html": "^2.16.1",
|
|
179
|
+
"drizzle-kit": "^0.31.10",
|
|
179
180
|
"typescript": "^6.0.2",
|
|
180
181
|
"vitest": "^4.1.2",
|
|
181
182
|
"@voyant-travel/voyant-typescript-config": "^0.1.0"
|
|
182
183
|
},
|
|
183
184
|
"files": [
|
|
184
|
-
"dist"
|
|
185
|
+
"dist",
|
|
186
|
+
"migrations/*.sql",
|
|
187
|
+
"migrations/meta/_journal.json"
|
|
185
188
|
],
|
|
186
189
|
"publishConfig": {
|
|
187
190
|
"access": "public"
|
|
@@ -202,7 +205,8 @@
|
|
|
202
205
|
"lint": "biome check src/",
|
|
203
206
|
"test": "vitest run",
|
|
204
207
|
"build": "tsc -p tsconfig.json",
|
|
205
|
-
"clean": "rm -rf dist tsconfig.tsbuildinfo"
|
|
208
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
209
|
+
"db:generate": "drizzle-kit generate --config=drizzle.migrations.config.ts --name=inventory_baseline && node ../../scripts/d2/guard-create-type.mjs ./migrations && node ../../scripts/d2/ensure-extensions.mjs ./migrations"
|
|
206
210
|
},
|
|
207
211
|
"main": "./dist/index.js",
|
|
208
212
|
"types": "./dist/index.d.ts"
|