Ingredients as many-to-many relations + VS Code/Antigravity launch.json
- new ingredients collection (uid, name, emoji icon, diet_class) synced by update-menu.mjs; menu_items.ingredients is an M2M relation — the script maps data-file uids to fresh PB record ids - diet select removed: the green/red FSSAI badge is derived (non-veg when any linked ingredient is non-veg); 164 items tagged (11 ingredients) - menu cards render ingredient chips (icon + name) under the description - migration 1788500200_menu_ingredients.js (idempotent create — app.save returns nil on success in the JSVM, so don't test its return value) - .vscode/launch.json: PocketBase + Vite dev, build+preview, menu sync, full-stack compound (dev PB on :8091 — 8090 is taken on this host)
This commit is contained in:
+27
-8
@@ -2,8 +2,9 @@
|
||||
/**
|
||||
* Menu sync — replaces the PocketBase menu with app/src/data/menu-data.mjs.
|
||||
*
|
||||
* Deletes every record in menu_categories / menu_items and inserts the
|
||||
* current food menu from code. Nothing else is touched.
|
||||
* Deletes every record in menu_categories / ingredients / menu_items and
|
||||
* inserts the current food menu from code. Item ingredient uids are mapped
|
||||
* to the freshly created ingredient record ids. Nothing else is touched.
|
||||
*
|
||||
* Works against any PocketBase instance (local dev or production):
|
||||
*
|
||||
@@ -19,7 +20,7 @@ import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url))
|
||||
const { MENU_CATEGORIES, MENU_ITEMS } = await import(
|
||||
const { INGREDIENTS, MENU_CATEGORIES, MENU_ITEMS } = await import(
|
||||
new URL(`file://${join(here, '../app/src/data/menu-data.mjs')}`)
|
||||
)
|
||||
|
||||
@@ -84,26 +85,44 @@ async function createRecord(collection, token, body) {
|
||||
const text = await res.text()
|
||||
throw new Error(`create ${collection}/${body.uid} failed (HTTP ${res.status}): ${text}`)
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await auth()
|
||||
console.log(`[menu] authenticated against ${PB_URL}`)
|
||||
|
||||
for (const [collection, entries] of [
|
||||
['menu_categories', MENU_CATEGORIES],
|
||||
['menu_items', MENU_ITEMS],
|
||||
]) {
|
||||
async function replaceCollection(collection, entries) {
|
||||
const existing = await listAll(collection, token)
|
||||
for (const record of existing) {
|
||||
await deleteRecord(collection, token, record.id)
|
||||
}
|
||||
const idsByUid = new Map()
|
||||
for (const entry of entries) {
|
||||
await createRecord(collection, token, entry)
|
||||
const created = await createRecord(collection, token, entry)
|
||||
idsByUid.set(entry.uid, created.id)
|
||||
}
|
||||
console.log(`[menu] ${collection}: -${existing.length} old, +${entries.length} new`)
|
||||
return idsByUid
|
||||
}
|
||||
|
||||
// Ingredients first — menu items reference their PocketBase record ids.
|
||||
await replaceCollection('menu_categories', MENU_CATEGORIES)
|
||||
const ingredientIds = await replaceCollection('ingredients', INGREDIENTS)
|
||||
|
||||
const items = MENU_ITEMS.map((entry) => {
|
||||
const { ingredients, ...rest } = entry
|
||||
return {
|
||||
...rest,
|
||||
ingredients: (ingredients ?? []).map((uid) => {
|
||||
const id = ingredientIds.get(uid)
|
||||
if (!id) throw new Error(`menu item ${entry.uid} references unknown ingredient '${uid}'`)
|
||||
return id
|
||||
}),
|
||||
}
|
||||
})
|
||||
await replaceCollection('menu_items', items)
|
||||
|
||||
console.log('[menu] done — the live menu now matches app/src/data/menu-data.mjs')
|
||||
} catch (error) {
|
||||
console.error(`[menu] failed: ${error.message}`)
|
||||
|
||||
Reference in New Issue
Block a user