diff --git a/hono/src/drizzle/0008_fresh_lightspeed.sql b/hono/src/drizzle/0008_fresh_lightspeed.sql new file mode 100644 index 0000000..7c3b21f --- /dev/null +++ b/hono/src/drizzle/0008_fresh_lightspeed.sql @@ -0,0 +1,70 @@ +ALTER TABLE "items" RENAME TO "item";--> statement-breakpoint +ALTER TABLE "tags_to_items" RENAME TO "item_tag";--> statement-breakpoint +ALTER TABLE "outfits" RENAME TO "outfit";--> statement-breakpoint +ALTER TABLE "items_to_outfits" RENAME TO "outfit_item";--> statement-breakpoint +ALTER TABLE "tags_to_outfits" RENAME TO "outfit_tag";--> statement-breakpoint +ALTER TABLE "tags" RENAME TO "tag";--> statement-breakpoint +COMMENT ON TABLE "item" IS 'Table of items representing clothing pieces and accessories in user wardrobes.';--> statement-breakpoint +COMMENT ON TABLE "outfit" IS 'Table of outfits representing coordinated clothing combinations worn by users.';--> statement-breakpoint +COMMENT ON TABLE "tag" IS 'Table of tags representing categorical labels for organizing items and outfits.';--> statement-breakpoint +COMMENT ON TABLE "outfit_item" IS 'Table of outfit items representing the many-to-many relationship between outfits and items.';--> statement-breakpoint +COMMENT ON TABLE "item_tag" IS 'Table of item tags representing the many-to-many relationship between items and tags.';--> statement-breakpoint +COMMENT ON TABLE "outfit_tag" IS 'Table of outfit tags representing the many-to-many relationship between outfits and tags.';--> statement-breakpoint +ALTER TABLE "outfit" DROP CONSTRAINT "rating_check";--> statement-breakpoint +ALTER TABLE "tag" DROP CONSTRAINT "min_days_before_item_reuse";--> statement-breakpoint +ALTER TABLE "outfit_item" DROP CONSTRAINT "items_to_outfits_item_id_items_id_fk"; +--> statement-breakpoint +ALTER TABLE "outfit_item" DROP CONSTRAINT "items_to_outfits_outfit_id_outfits_id_fk"; +--> statement-breakpoint +ALTER TABLE "item_tag" DROP CONSTRAINT "tags_to_items_tag_id_tags_id_fk"; +--> statement-breakpoint +ALTER TABLE "item_tag" DROP CONSTRAINT "tags_to_items_item_id_items_id_fk"; +--> statement-breakpoint +ALTER TABLE "outfit_tag" DROP CONSTRAINT "tags_to_outfits_tag_id_tags_id_fk"; +--> statement-breakpoint +ALTER TABLE "outfit_tag" DROP CONSTRAINT "tags_to_outfits_outfit_id_outfits_id_fk"; +--> statement-breakpoint +ALTER TABLE "outfit_item" DROP CONSTRAINT "items_to_outfits_item_id_outfit_id_pk";--> statement-breakpoint +ALTER TABLE "item_tag" DROP CONSTRAINT "tags_to_items_tag_id_item_id_pk";--> statement-breakpoint +ALTER TABLE "outfit_tag" DROP CONSTRAINT "tags_to_outfits_tag_id_outfit_id_pk";--> statement-breakpoint +ALTER TABLE "outfit_item" ADD CONSTRAINT "outfit_item_outfit_id_item_id_pk" PRIMARY KEY("outfit_id","item_id");--> statement-breakpoint +ALTER TABLE "item_tag" ADD CONSTRAINT "item_tag_item_id_tag_id_pk" PRIMARY KEY("item_id","tag_id");--> statement-breakpoint +ALTER TABLE "outfit_tag" ADD CONSTRAINT "outfit_tag_outfit_id_tag_id_pk" PRIMARY KEY("outfit_id","tag_id");--> statement-breakpoint +ALTER TABLE "outfit_item" ADD CONSTRAINT "outfit_item_outfit_id_outfit_id_fk" FOREIGN KEY ("outfit_id") REFERENCES "public"."outfit"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "outfit_item" ADD CONSTRAINT "outfit_item_item_id_item_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."item"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "item_tag" ADD CONSTRAINT "item_tag_item_id_item_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."item"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "item_tag" ADD CONSTRAINT "item_tag_tag_id_tag_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tag"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "outfit_tag" ADD CONSTRAINT "outfit_tag_outfit_id_outfit_id_fk" FOREIGN KEY ("outfit_id") REFERENCES "public"."outfit"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "outfit_tag" ADD CONSTRAINT "outfit_tag_tag_id_tag_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tag"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "outfit" ADD CONSTRAINT "rating_check" CHECK ("outfit"."rating" >= 0 AND "outfit"."rating" <= 2);--> statement-breakpoint +ALTER TABLE "tag" ADD CONSTRAINT "min_days_before_item_reuse" CHECK ("tag"."min_days_before_item_reuse" >= -1);--> statement-breakpoint +COMMENT ON COLUMN "item"."id" IS 'The unique identifier of the entity.';--> statement-breakpoint +COMMENT ON COLUMN "item"."name" IS 'The name of the item.';--> statement-breakpoint +COMMENT ON COLUMN "item"."brand" IS 'The brand of the item.';--> statement-breakpoint +COMMENT ON COLUMN "item"."photo_url" IS 'The URL of the item photo.';--> statement-breakpoint +COMMENT ON COLUMN "item"."type" IS 'The type of the item.';--> statement-breakpoint +COMMENT ON COLUMN "item"."rating" IS 'The rating of the item.';--> statement-breakpoint +COMMENT ON COLUMN "item"."status" IS 'The status of the item.';--> statement-breakpoint +COMMENT ON COLUMN "item"."created_at" IS 'The timestamp when the entity was created.';--> statement-breakpoint +COMMENT ON COLUMN "item"."user_id" IS 'The ID of the user who created the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."id" IS 'The unique identifier of the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."rating" IS 'The rating of the outfit.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."wear_date" IS 'The date when the outfit was worn.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."location_latitude" IS 'The latitude of the location where the outfit was worn.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."location_longitude" IS 'The longitude of the location where the outfit was worn.';--> statement-breakpoint +COMMENT ON COLUMN "outfit"."user_id" IS 'The ID of the user who created the entity.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."id" IS 'The unique identifier of the entity.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."name" IS 'The name of the tag.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."hex_color" IS 'The hex color of the tag.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."min_days_before_item_reuse" IS 'The minimum days before an item can be reused.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."created_at" IS 'The timestamp when the entity was created.';--> statement-breakpoint +COMMENT ON COLUMN "tag"."user_id" IS 'The ID of the user who created the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_item"."outfit_id" IS 'The ID of the outfit associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_item"."item_id" IS 'The ID of the item associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_item"."item_type" IS 'The type of the item in the outfit.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_tag"."outfit_id" IS 'The ID of the outfit associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_tag"."tag_id" IS 'The ID of the tag associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "outfit_tag"."status" IS 'The status of the tag association.';--> statement-breakpoint +COMMENT ON COLUMN "item_tag"."item_id" IS 'The ID of the item associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "item_tag"."tag_id" IS 'The ID of the tag associated with the entity.';--> statement-breakpoint +COMMENT ON COLUMN "item_tag"."status" IS 'The status of the tag association.'; \ No newline at end of file diff --git a/hono/src/drizzle/meta/0008_snapshot.json b/hono/src/drizzle/meta/0008_snapshot.json new file mode 100644 index 0000000..4af7483 --- /dev/null +++ b/hono/src/drizzle/meta/0008_snapshot.json @@ -0,0 +1,386 @@ +{ + "id": "78937b18-caaf-485e-826e-1a3bf430e315", + "prevId": "873476ec-4fb7-4d51-917b-8b47d256ac3d", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.item": { + "name": "item", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "brand": { + "name": "brand", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "photo_url": { + "name": "photo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "itemType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "itemStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'available'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.item_tag": { + "name": "item_tag", + "schema": "", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "tagStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'suggested'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_tag_item_id_item_id_fk": { + "name": "item_tag_item_id_item_id_fk", + "tableFrom": "item_tag", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_tag_tag_id_tag_id_fk": { + "name": "item_tag_tag_id_tag_id_fk", + "tableFrom": "item_tag", + "tableTo": "tag", + "columnsFrom": ["tag_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_tag_item_id_tag_id_pk": { + "name": "item_tag_item_id_tag_id_pk", + "columns": ["item_id", "tag_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.outfit": { + "name": "outfit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "wear_date": { + "name": "wear_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "location_latitude": { + "name": "location_latitude", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "location_longitude": { + "name": "location_longitude", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "rating_check": { + "name": "rating_check", + "value": "\"outfit\".\"rating\" >= 0 AND \"outfit\".\"rating\" <= 2" + } + }, + "isRLSEnabled": false + }, + "public.outfit_item": { + "name": "outfit_item", + "schema": "", + "columns": { + "outfit_id": { + "name": "outfit_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "item_type": { + "name": "item_type", + "type": "itemType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "outfit_item_outfit_id_outfit_id_fk": { + "name": "outfit_item_outfit_id_outfit_id_fk", + "tableFrom": "outfit_item", + "tableTo": "outfit", + "columnsFrom": ["outfit_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "outfit_item_item_id_item_id_fk": { + "name": "outfit_item_item_id_item_id_fk", + "tableFrom": "outfit_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "outfit_item_outfit_id_item_id_pk": { + "name": "outfit_item_outfit_id_item_id_pk", + "columns": ["outfit_id", "item_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.outfit_tag": { + "name": "outfit_tag", + "schema": "", + "columns": { + "outfit_id": { + "name": "outfit_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "tagStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'suggested'" + } + }, + "indexes": {}, + "foreignKeys": { + "outfit_tag_outfit_id_outfit_id_fk": { + "name": "outfit_tag_outfit_id_outfit_id_fk", + "tableFrom": "outfit_tag", + "tableTo": "outfit", + "columnsFrom": ["outfit_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "outfit_tag_tag_id_tag_id_fk": { + "name": "outfit_tag_tag_id_tag_id_fk", + "tableFrom": "outfit_tag", + "tableTo": "tag", + "columnsFrom": ["tag_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "outfit_tag_outfit_id_tag_id_pk": { + "name": "outfit_tag_outfit_id_tag_id_pk", + "columns": ["outfit_id", "tag_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tag": { + "name": "tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hex_color": { + "name": "hex_color", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "min_days_before_item_reuse": { + "name": "min_days_before_item_reuse", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": -1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "min_days_before_item_reuse": { + "name": "min_days_before_item_reuse", + "value": "\"tag\".\"min_days_before_item_reuse\" >= -1" + } + }, + "isRLSEnabled": false + } + }, + "enums": { + "public.itemStatus": { + "name": "itemStatus", + "schema": "public", + "values": ["available", "withheld", "retired"] + }, + "public.itemType": { + "name": "itemType", + "schema": "public", + "values": ["layer", "top", "bottom", "footwear", "accessory"] + }, + "public.tagStatus": { + "name": "tagStatus", + "schema": "public", + "values": ["manually_assigned", "suggested", "suggestion_accepted", "suggestion_rejected"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/hono/src/drizzle/meta/_journal.json b/hono/src/drizzle/meta/_journal.json index bb8b08b..af65114 100644 --- a/hono/src/drizzle/meta/_journal.json +++ b/hono/src/drizzle/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1761023578962, "tag": "0007_concerned_nitro", "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1761110542840, + "tag": "0008_fresh_lightspeed", + "breakpoints": true } ] } diff --git a/hono/src/schema.ts b/hono/src/schema.ts index 095690d..959d116 100644 --- a/hono/src/schema.ts +++ b/hono/src/schema.ts @@ -31,9 +31,9 @@ export const itemStatusEnum: [string, ...string[]] = ['available', 'withheld', ' export const itemStatusEnumPg = pgEnum('itemStatus', itemStatusEnum) /** - * Items + * Item */ -export const items = pgTable('items', { +export const item = pgTable('item', { id: text('id') .$defaultFn(() => createId()) .primaryKey(), @@ -47,16 +47,16 @@ export const items = pgTable('items', { userId: text('user_id').notNull(), }) -export const itemsRelations = relations(items, ({ many }) => ({ - itemsToOutfits: many(itemsToOutfits), - tagsToItems: many(tagsToItems), +export const itemRelations = relations(item, ({ many }) => ({ + outfitItems: many(outfitItem), + itemTags: many(itemTag), })) /** - * Outfits + * Outfit */ -export const outfits = pgTable( - 'outfits', +export const outfit = pgTable( + 'outfit', { id: text('id') .$defaultFn(() => createId()) @@ -67,45 +67,39 @@ export const outfits = pgTable( locationLongitude: doublePrecision('location_longitude'), userId: text('user_id').notNull(), }, - (table) => ({ - ratingCheck: check('rating_check', sql`${table.rating} >= 0 AND ${table.rating} <= 2`), - }) + (table) => [check('rating_check', sql`${table.rating} >= 0 AND ${table.rating} <= 2`)] ) -export const outfitsRelations = relations(outfits, ({ many }) => ({ - itemsToOutfits: many(itemsToOutfits), - tagsToOutfits: many(tagsToOutfits), +export const outfitRelations = relations(outfit, ({ many }) => ({ + outfitItems: many(outfitItem), + outfitTags: many(outfitTag), })) /** - * Items to Outfits + * Outfit Item */ -export const itemsToOutfits = pgTable( - 'items_to_outfits', +export const outfitItem = pgTable( + 'outfit_item', { - itemId: text('item_id') - .notNull() - .references(() => items.id, { onDelete: 'cascade' }), outfitId: text('outfit_id') .notNull() - .references(() => outfits.id, { onDelete: 'cascade' }), + .references(() => outfit.id, { onDelete: 'cascade' }), + itemId: text('item_id') + .notNull() + .references(() => item.id, { onDelete: 'cascade' }), itemType: itemTypeEnumPg('item_type').notNull(), }, - (table) => { - return { - pk: primaryKey({ columns: [table.itemId, table.outfitId] }), - } - } + (table) => [primaryKey({ columns: [table.outfitId, table.itemId] })] ) -export const itemsToOutfitsRelations = relations(itemsToOutfits, ({ one }) => ({ - item: one(items, { - fields: [itemsToOutfits.itemId], - references: [items.id], +export const outfitItemRelations = relations(outfitItem, ({ one }) => ({ + outfit: one(outfit, { + fields: [outfitItem.outfitId], + references: [outfit.id], }), - outfit: one(outfits, { - fields: [itemsToOutfits.outfitId], - references: [outfits.id], + item: one(item, { + fields: [outfitItem.itemId], + references: [item.id], }), })) @@ -121,10 +115,10 @@ export const tagStatusEnum: [string, ...string[]] = [ export const tagStatusEnumPg = pgEnum('tagStatus', tagStatusEnum) /** - * Tags + * Tag */ -export const tags = pgTable( - 'tags', +export const tag = pgTable( + 'tag', { id: text('id') .$defaultFn(() => createId()) @@ -135,76 +129,66 @@ export const tags = pgTable( createdAt: timestamp('created_at').notNull().defaultNow(), userId: text('user_id').notNull(), }, - (table) => ({ - minDaysCheck: check('min_days_before_item_reuse', sql`${table.minDaysBeforeItemReuse} >= -1`), - }) + (table) => [check('min_days_before_item_reuse', sql`${table.minDaysBeforeItemReuse} >= -1`)] ) -export const tagsRelations = relations(tags, ({ many }) => ({ - tagsToOutfits: many(tagsToOutfits), - tagsToItems: many(tagsToItems), +export const tagRelations = relations(tag, ({ many }) => ({ + outfitTags: many(outfitTag), + itemTags: many(itemTag), })) /** - * Tags to Outfits + * Outfit Tag */ -export const tagsToOutfits = pgTable( - 'tags_to_outfits', +export const outfitTag = pgTable( + 'outfit_tag', { - tagId: text('tag_id') - .notNull() - .references(() => tags.id, { onDelete: 'cascade' }), outfitId: text('outfit_id') .notNull() - .references(() => outfits.id, { onDelete: 'cascade' }), + .references(() => outfit.id, { onDelete: 'cascade' }), + tagId: text('tag_id') + .notNull() + .references(() => tag.id, { onDelete: 'cascade' }), status: tagStatusEnumPg('status').notNull().default('suggested'), }, - (table) => { - return { - pk: primaryKey({ columns: [table.tagId, table.outfitId] }), - } - } + (table) => [primaryKey({ columns: [table.outfitId, table.tagId] })] ) -export const tagsToOutfitsRelations = relations(tagsToOutfits, ({ one }) => ({ - tag: one(tags, { - fields: [tagsToOutfits.tagId], - references: [tags.id], +export const outfitTagRelations = relations(outfitTag, ({ one }) => ({ + outfit: one(outfit, { + fields: [outfitTag.outfitId], + references: [outfit.id], }), - outfit: one(outfits, { - fields: [tagsToOutfits.outfitId], - references: [outfits.id], + tag: one(tag, { + fields: [outfitTag.tagId], + references: [tag.id], }), })) /** - * Tags to Items + * Item Tag */ -export const tagsToItems = pgTable( - 'tags_to_items', +export const itemTag = pgTable( + 'item_tag', { - tagId: text('tag_id') - .notNull() - .references(() => tags.id, { onDelete: 'cascade' }), itemId: text('item_id') .notNull() - .references(() => items.id, { onDelete: 'cascade' }), + .references(() => item.id, { onDelete: 'cascade' }), + tagId: text('tag_id') + .notNull() + .references(() => tag.id, { onDelete: 'cascade' }), status: tagStatusEnumPg('status').notNull().default('suggested'), }, - (table) => { - return { - pk: primaryKey({ columns: [table.tagId, table.itemId] }), - } - } + (table) => [primaryKey({ columns: [table.itemId, table.tagId] })] ) -export const tagsToItemsRelations = relations(tagsToItems, ({ one }) => ({ - tag: one(tags, { - fields: [tagsToItems.tagId], - references: [tags.id], +export const itemTagRelations = relations(itemTag, ({ one }) => ({ + item: one(item, { + fields: [itemTag.itemId], + references: [item.id], }), - item: one(items, { - fields: [tagsToItems.itemId], - references: [items.id], + tag: one(tag, { + fields: [itemTag.tagId], + references: [tag.id], }), })) diff --git a/hono/src/services/items.ts b/hono/src/services/items.ts index 6554afc..597c599 100644 --- a/hono/src/services/items.ts +++ b/hono/src/services/items.ts @@ -6,13 +6,13 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod' import { Hono } from 'hono' import { z } from 'zod' -import { itemStatusEnum, itemTypeEnum, items } from '../schema' +import { item, itemStatusEnum, itemTypeEnum } from '../schema' import { requireAuth } from '../utils/auth' import type { AuthVariables } from '../utils/auth' import type { DBVariables } from '../utils/inject-db' import injectDB from '../utils/inject-db' -const insertItemSchema = createInsertSchema(items, { +const insertItemSchema = createInsertSchema(item, { name: z.string().min(1).max(60), brand: z.string().min(1).max(60), photoUrl: z.string().url(), @@ -21,7 +21,7 @@ const insertItemSchema = createInsertSchema(items, { status: z.enum(itemStatusEnum).default('available'), }).omit({ id: true, createdAt: true, userId: true }) -const selectItemSchema = createSelectSchema(items, { +const selectItemSchema = createSelectSchema(item, { id: z.string().refine((val) => isCuid(val)), }) @@ -44,11 +44,11 @@ const paginationValidationItems = z .optional() const getItemQuery = (db: DBVariables['db'], whereClause: SQL | undefined) => { - return db.query.items + return db.query.item .findMany({ where: whereClause, with: { - itemsToOutfits: { + outfitItems: { with: { outfit: { columns: { @@ -57,7 +57,7 @@ const getItemQuery = (db: DBVariables['db'], whereClause: SQL | undefin }, }, }, - tagsToItems: { + itemTags: { columns: { itemId: false, }, @@ -75,11 +75,11 @@ const getItemQuery = (db: DBVariables['db'], whereClause: SQL | undefin status: item.status, createdAt: item.createdAt, userId: item.userId, - lastWornAt: item.itemsToOutfits.length - ? item.itemsToOutfits.filter((rel) => rel.outfit.wearDate !== null).length > 0 + lastWornAt: item.outfitItems.length + ? item.outfitItems.filter((rel) => rel.outfit.wearDate !== null).length > 0 ? new Date( Math.max( - ...item.itemsToOutfits + ...item.outfitItems .filter((rel) => rel.outfit.wearDate !== null) .map((rel) => rel.outfit.wearDate!.getTime()) ) @@ -88,7 +88,7 @@ const getItemQuery = (db: DBVariables['db'], whereClause: SQL | undefin .split('T')[0] : null : null, - tagsToItems: item.tagsToItems, + itemTags: item.itemTags, })) ) } @@ -106,10 +106,10 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ...search .toLowerCase() .split(/\s+/) - .map((word) => or(ilike(items.name, `%${word}%`), ilike(items.brand, `%${word}%`))), - eq(items.userId, userId) + .map((word) => or(ilike(item.name, `%${word}%`), ilike(item.brand, `%${word}%`))), + eq(item.userId, userId) ) - : eq(items.userId, userId) + : eq(item.userId, userId) const itemsData = await getItemQuery(c.get('db'), whereClause).then((items) => { // Sort by status (available first, then withheld, then retired), then lastWornAt (nulls first), then name @@ -159,7 +159,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const itemData = await getItemQuery( c.get('db'), - and(eq(items.id, id), eq(items.userId, userId)) + and(eq(item.id, id), eq(item.userId, userId)) ) // NOTE: Aware that this is not good practice, could be more efficient if (!itemData.length) { @@ -190,7 +190,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .insert(items) + .insert(item) .values({ ...body, userId, @@ -217,12 +217,12 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .update(items) + .update(item) .set({ ...body, userId, }) - .where(and(eq(items.id, params.id), eq(items.userId, userId))) + .where(and(eq(item.id, params.id), eq(item.userId, userId))) .returning() )[0] ) @@ -242,8 +242,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .delete(items) - .where(and(eq(items.id, params.id), eq(items.userId, userId))) + .delete(item) + .where(and(eq(item.id, params.id), eq(item.userId, userId))) .returning() )[0] ) diff --git a/hono/src/services/outfits.ts b/hono/src/services/outfits.ts index d1de835..46589ea 100644 --- a/hono/src/services/outfits.ts +++ b/hono/src/services/outfits.ts @@ -5,14 +5,14 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod' import { Hono } from 'hono' import { z } from 'zod' -import { itemTypeEnum, items, itemsToOutfits, outfits, tagsToOutfits } from '../schema' +import { item, itemTypeEnum, outfit, outfitItem, outfitTag } from '../schema' import { requireAuth } from '../utils/auth' import type { AuthVariables } from '../utils/auth' import type { DBVariables } from '../utils/inject-db' import injectDB from '../utils/inject-db' import { VIRTUAL_TAGS, getApplicableVirtualTags, isVirtualTag } from './tags' -const insertOutfitSchema = createInsertSchema(outfits, { +const insertOutfitSchema = createInsertSchema(outfit, { rating: z.number().min(0).max(2).default(1), wearDate: z.coerce.date().optional(), locationLatitude: z.number().min(-90).max(90).optional(), @@ -32,7 +32,7 @@ const insertOutfitSchema = createInsertSchema(outfits, { }) .omit({ id: true, userId: true }) -const selectOutfitSchema = createSelectSchema(outfits, { +const selectOutfitSchema = createSelectSchema(outfit, { id: z.string().refine((val) => isCuid(val)), }) @@ -76,25 +76,25 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const pageNumber: number = page ? +page : 0 const pageSize: number = size ? +size : 10 - const outfitsData = await c.get('db').query.outfits.findMany({ + const outfitsData = await c.get('db').query.outfit.findMany({ where: and( - eq(outfits.userId, userId), - sql`${outfits.wearDate} IS NOT NULL` // Exclude ghost outfits + eq(outfit.userId, userId), + sql`${outfit.wearDate} IS NOT NULL` // Exclude ghost outfits ), with: { - itemsToOutfits: { + outfitItems: { columns: { outfitId: false, }, - orderBy: (itemsToOutfits, { asc }) => [asc(itemsToOutfits.itemType)], + orderBy: (outfitItems, { asc }) => [asc(outfitItems.itemType)], }, - tagsToOutfits: { + outfitTags: { columns: { outfitId: false, }, }, }, - orderBy: (outfits, { desc }) => [desc(outfits.wearDate)], + orderBy: (outfit, { desc }) => [desc(outfit.wearDate)], offset: pageNumber * pageSize, limit: pageSize + 1, }) @@ -119,11 +119,11 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() if (itemIds.length > 0) { // Find which of these items (if any) are currently withheld or retired - const unavailableItems = await tx.query.items.findMany({ + const unavailableItems = await tx.query.item.findMany({ where: and( - inArray(items.id, itemIds), - sql`items.status != 'available'`, - eq(items.userId, userId) + inArray(item.id, itemIds), + sql`item.status != 'available'`, + eq(item.userId, userId) ), columns: { id: true, @@ -136,9 +136,9 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // Make the items available await tx - .update(items) + .update(item) .set({ status: 'available' }) - .where(inArray(items.id, unavailableItemIds)) + .where(inArray(item.id, unavailableItemIds)) } } @@ -148,11 +148,11 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() } const newOutfit = ( - await tx.insert(outfits).values(outfitData).onConflictDoNothing().returning() + await tx.insert(outfit).values(outfitData).onConflictDoNothing().returning() )[0] // Insert item to outfit relationships - await tx.insert(itemsToOutfits).values( + await tx.insert(outfitItem).values( body.itemIdsTypes.map((e) => ({ itemId: e.id, outfitId: newOutfit.id, @@ -166,7 +166,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const realTagIds = body.tagIds.filter((tagId) => !isVirtualTag(tagId)) if (realTagIds.length > 0) { - await tx.insert(tagsToOutfits).values( + await tx.insert(outfitTag).values( realTagIds.map((e) => ({ tagId: e, outfitId: newOutfit.id, @@ -194,8 +194,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .delete(outfits) - .where(and(eq(outfits.id, params.id), eq(outfits.userId, userId))) + .delete(outfit) + .where(and(eq(outfit.id, params.id), eq(outfit.userId, userId))) .returning() )[0] ) @@ -215,10 +215,10 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const regularTagId = isVirtualTagFilter ? undefined : tagId // STEP 1: Get all available items with last worn dates in a single query - const allItems = await c.get('db').query.items.findMany({ + const allItems = await c.get('db').query.item.findMany({ where: and( - eq(sql`items.user_id`, userId), - eq(items.status, 'available') // Exclude non-available items from suggestions + eq(sql`item.user_id`, userId), + eq(item.status, 'available') // Exclude non-available items from suggestions ), columns: { id: true, @@ -228,8 +228,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() }) // Get a list of non-available item IDs for checking if outfits contain unavailable items - const unavailableItems = await c.get('db').query.items.findMany({ - where: and(eq(sql`items.user_id`, userId), sql`items.status != 'available'`), + const unavailableItems = await c.get('db').query.item.findMany({ + where: and(eq(sql`item.user_id`, userId), sql`item.status != 'available'`), columns: { id: true, }, @@ -271,9 +271,9 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() io.item_id, MAX(o.wear_date) as last_worn_date FROM - items_to_outfits io + outfit_item io JOIN - outfits o ON o.id = io.outfit_id + outfit o ON o.id = io.outfit_id WHERE o.user_id = ${userId} GROUP BY @@ -352,17 +352,17 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() } // STEP 3: Get all eligible outfits in a single query - const eligibleOutfits = await c.get('db').query.outfits.findMany({ - where: and(eq(outfits.userId, userId), gte(outfits.rating, 1)), + const eligibleOutfits = await c.get('db').query.outfit.findMany({ + where: and(eq(outfit.userId, userId), gte(outfit.rating, 1)), with: { - itemsToOutfits: { + outfitItems: { columns: { outfitId: true, itemId: true, itemType: true, }, }, - tagsToOutfits: { + outfitTags: { columns: { outfitId: true, tagId: true, @@ -370,13 +370,13 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() }, }, }, - orderBy: (outfits, { desc }) => [desc(outfits.wearDate)], + orderBy: (outfits, { desc }) => [desc(outfit.wearDate)], }) // Filter out outfits that contain any unavailable items const availableOutfits = eligibleOutfits.filter((outfit) => { // Return true only if no items in the outfit are unavailable - return !outfit.itemsToOutfits.some((io) => unavailableItemIds.has(io.itemId)) + return !outfit.outfitItems.some((io) => unavailableItemIds.has(io.itemId)) }) // If no eligible outfits after filtering unavailable items, return empty result @@ -397,18 +397,18 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // Filter outfits to only include those with at least one layer/top, one bottom, and one footwear // And apply tag filter if provided const completeOutfits = availableOutfits.filter((outfit) => { - const hasTopOrLayer = outfit.itemsToOutfits.some( + const hasTopOrLayer = outfit.outfitItems.some( (io) => io.itemType === 'top' || io.itemType === 'layer' ) - const hasBottom = outfit.itemsToOutfits.some((io) => io.itemType === 'bottom') - const hasFootwear = outfit.itemsToOutfits.some((io) => io.itemType === 'footwear') + const hasBottom = outfit.outfitItems.some((io) => io.itemType === 'bottom') + const hasFootwear = outfit.outfitItems.some((io) => io.itemType === 'footwear') // Check for virtual tag filter const matchesVirtualTagFilter = !virtualTag || (virtualTag.appliesTo && virtualTag.appliesTo(outfit)) // If regular tagId is provided, check if the outfit has this tag - const hasTag = !regularTagId || outfit.tagsToOutfits.some((to) => to.tagId === regularTagId) + const hasTag = !regularTagId || outfit.outfitTags.some((to) => to.tagId === regularTagId) return hasTopOrLayer && hasBottom && hasFootwear && hasTag && matchesVirtualTagFilter }) @@ -436,7 +436,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // First pass: Group outfits by core items and find the most recent for each group for (const outfit of completeOutfits) { // Extract only layers, tops, and bottoms - not accessories or footwear - const coreItems = outfit.itemsToOutfits + const coreItems = outfit.outfitItems .filter((io) => ['layer', 'top', 'bottom'].includes(io.itemType)) .map((io) => io.itemId) .sort() // Sort to ensure consistent order @@ -468,7 +468,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // Second pass: Filter outfits to keep only the most recent for each core items group const uniqueOutfits = completeOutfits.filter((outfit) => { - const coreItems = outfit.itemsToOutfits + const coreItems = outfit.outfitItems .filter((io) => ['layer', 'top', 'bottom'].includes(io.itemType)) .map((io) => io.itemId) .sort() @@ -488,7 +488,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // For each filtered outfit, set its wear count to the total number of outfits with the same core items for (const outfit of uniqueOutfits) { - const coreItems = outfit.itemsToOutfits + const coreItems = outfit.outfitItems .filter((io) => ['layer', 'top', 'bottom'].includes(io.itemType)) .map((io) => io.itemId) .sort() @@ -517,8 +517,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ) // Get item freshness for all items in this outfit - const itemIds = outfit.itemsToOutfits.map((io) => io.itemId) - const nonAccessoryItems = outfit.itemsToOutfits.filter((io) => io.itemType !== 'accessory') + const itemIds = outfit.outfitItems.map((io) => io.itemId) + const nonAccessoryItems = outfit.outfitItems.filter((io) => io.itemType !== 'accessory') if (itemIds.length === 0) { // Empty outfit case - just return rating score @@ -651,16 +651,16 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() // STEP 7: Fetch full details for the paginated outfits in a single query const outfitIds = paginatedOutfits.map((o) => o.outfitId) - const outfitDetails = await c.get('db').query.outfits.findMany({ - where: inArray(outfits.id, outfitIds), + const outfitDetails = await c.get('db').query.outfit.findMany({ + where: inArray(outfit.id, outfitIds), with: { - itemsToOutfits: { + outfitItems: { columns: { outfitId: false, }, - orderBy: (itemsToOutfits, { asc }) => [asc(itemsToOutfits.itemType)], + orderBy: (outfitItems, { asc }) => [asc(outfitItems.itemType)], }, - tagsToOutfits: { + outfitTags: { columns: { outfitId: false, }, @@ -674,7 +674,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const scoreInfo = paginatedOutfits.find((s) => s.outfitId === outfit.id) // Add freshness score to each item - const itemsToOutfitsWithFreshness = outfit.itemsToOutfits.map((item) => { + const outfitItemsWithFreshness = outfit.outfitItems.map((item) => { const freshness = itemFreshnessMap.get(item.itemId) || 1.0 return { ...item, @@ -683,12 +683,12 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() }) // Add applicable virtual tags to the outfit - const tagsToOutfits = [...outfit.tagsToOutfits] + const outfitTags = [...outfit.outfitTags] const applicableVirtualTags = getApplicableVirtualTags(outfit) // Add all applicable virtual tags to this outfit for (const virtualTag of applicableVirtualTags) { - tagsToOutfits.push({ + outfitTags.push({ tagId: virtualTag.id, status: 'manually_assigned', }) @@ -696,8 +696,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() return { ...outfit, - itemsToOutfits: itemsToOutfitsWithFreshness, - tagsToOutfits, + outfitItems: outfitItemsWithFreshness, + outfitTags, scoringDetails: scoreInfo?.scoring_details || { ratingScore: 0, timeScore: 0, diff --git a/hono/src/services/tags.ts b/hono/src/services/tags.ts index c42e5e1..a1d43f5 100644 --- a/hono/src/services/tags.ts +++ b/hono/src/services/tags.ts @@ -5,20 +5,22 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod' import { Hono } from 'hono' import { z } from 'zod' -import type { outfits } from '../schema' -import { tags } from '../schema' +import type { outfit } from '../schema' +import { tag } from '../schema' import { requireAuth } from '../utils/auth' import type { AuthVariables } from '../utils/auth' import type { DBVariables } from '../utils/inject-db' import injectDB from '../utils/inject-db' -const insertTagSchema = createInsertSchema(tags, { +type OutfitSelect = typeof outfit.$inferSelect + +const insertTagSchema = createInsertSchema(tag, { name: z.string().min(1).max(60), hexColor: z.string().regex(/^#[0-9A-F]{6}$/i), minDaysBeforeItemReuse: z.number().min(-1).max(365).default(-1), }).omit({ id: true, createdAt: true, userId: true }) -const selectTagSchema = createSelectSchema(tags, { +const selectTagSchema = createSelectSchema(tag, { id: z.string().refine((val) => isCuid(val)), }) @@ -30,7 +32,7 @@ export type VirtualTag = { minDaysBeforeItemReuse: number createdAt: Date userId: string - appliesTo?: (outfit: typeof outfits.$inferSelect) => boolean // Function to determine if this tag applies to an outfit + appliesTo?: (outfit: OutfitSelect) => boolean // Function to determine if this tag applies to an outfit } // Define virtual tags registry @@ -53,7 +55,7 @@ export const isVirtualTag = (tagId: string): boolean => { } // Helper function to get virtual tags that apply to an outfit -export const getApplicableVirtualTags = (outfit: typeof outfits.$inferSelect): VirtualTag[] => { +export const getApplicableVirtualTags = (outfit: OutfitSelect): VirtualTag[] => { return Object.values(VIRTUAL_TAGS).filter((tag) => tag.appliesTo && tag.appliesTo(outfit)) } @@ -62,9 +64,9 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() const auth = c.get('auth') const userId = auth?.userId || '' - const tagsData = await c.get('db').query.tags.findMany({ - where: eq(tags.userId, userId), - orderBy: (tags, { asc }) => [asc(tags.name)], + const tagsData = await c.get('db').query.tag.findMany({ + where: eq(tag.userId, userId), + orderBy: (tags, { asc }) => [asc(tag.name)], }) // Add all virtual tags at the beginning of the tags list @@ -84,7 +86,7 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .insert(tags) + .insert(tag) .values({ ...body, userId, @@ -114,12 +116,12 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .update(tags) + .update(tag) .set({ ...body, userId, }) - .where(eq(tags.id, params.id)) + .where(eq(tag.id, params.id)) .returning() )[0] ) @@ -144,8 +146,8 @@ const app = new Hono<{ Variables: AuthVariables & DBVariables }>() ( await c .get('db') - .delete(tags) - .where(and(eq(tags.id, params.id), eq(tags.userId, userId))) + .delete(tag) + .where(and(eq(tag.id, params.id), eq(tag.userId, userId))) .returning() )[0] ) diff --git a/hono/test/utils/clean-db.sql b/hono/test/utils/clean-db.sql index da9d54b..5d6e4e1 100644 --- a/hono/test/utils/clean-db.sql +++ b/hono/test/utils/clean-db.sql @@ -1,18 +1,18 @@ DELETE -FROM tags_to_items; +FROM item_tag; DELETE -FROM tags_to_outfits; +FROM outfit_tag; DELETE -FROM items_to_outfits; +FROM outfit_item; DELETE -FROM items; +FROM item; DELETE -FROM outfits; +FROM outfit; DELETE -FROM tags; \ No newline at end of file +FROM tag; \ No newline at end of file diff --git a/hono/test/utils/factory/items-outfits.ts b/hono/test/utils/factory/items-outfits.ts index af6d477..07fcf01 100644 --- a/hono/test/utils/factory/items-outfits.ts +++ b/hono/test/utils/factory/items-outfits.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' -import { itemTypeEnum, itemsToOutfits } from '../../../src/schema' +import { itemTypeEnum, outfitItem } from '../../../src/schema' import { instance } from '../db' import type { ItemFactory, ItemType } from './items' import type { OutfitFactory } from './outfits' @@ -24,7 +24,7 @@ export class ItemToOutfitFactory implements ItemToOutfit { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(itemsToOutfits).values(this).onConflictDoNothing() + await db.insert(outfitItem).values(this).onConflictDoNothing() } itemId: string diff --git a/hono/test/utils/factory/items.ts b/hono/test/utils/factory/items.ts index 07e8c0f..14f6905 100644 --- a/hono/test/utils/factory/items.ts +++ b/hono/test/utils/factory/items.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker' import type { itemStatusEnum } from '../../../src/schema' -import { itemTypeEnum, items } from '../../../src/schema' +import { item, itemTypeEnum } from '../../../src/schema' import { instance } from '../db' export type ItemType = 'layer' | 'top' | 'bottom' | 'footwear' | 'accessory' @@ -61,7 +61,7 @@ export class ItemFactory implements Item { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(items).values(this).onConflictDoNothing() + await db.insert(item).values(this).onConflictDoNothing() } formatAPI({ omitLastWornAt = false }: { omitLastWornAt?: boolean } = {}): ItemAPI { diff --git a/hono/test/utils/factory/outfits.ts b/hono/test/utils/factory/outfits.ts index ed81709..597fe75 100644 --- a/hono/test/utils/factory/outfits.ts +++ b/hono/test/utils/factory/outfits.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' -import { outfits } from '../../../src/schema' +import { outfit } from '../../../src/schema' import { instance } from '../db' export interface Outfit { @@ -61,7 +61,7 @@ export class OutfitFactory implements Outfit { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(outfits).values(this).onConflictDoNothing() + await db.insert(outfit).values(this).onConflictDoNothing() } formatAPI(): OutfitAPI { diff --git a/hono/test/utils/factory/tags-items.ts b/hono/test/utils/factory/tags-items.ts index 8356177..bb9c193 100644 --- a/hono/test/utils/factory/tags-items.ts +++ b/hono/test/utils/factory/tags-items.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' -import { tagStatusEnum, tagsToItems } from '../../../src/schema' +import { itemTag, tagStatusEnum } from '../../../src/schema' import { instance } from '../db' export interface TagToItem { @@ -22,7 +22,7 @@ export class TagToItemFactory implements TagToItem { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(tagsToItems).values(this).onConflictDoNothing() + await db.insert(itemTag).values(this).onConflictDoNothing() } tagId: string diff --git a/hono/test/utils/factory/tags-outfits.ts b/hono/test/utils/factory/tags-outfits.ts index ccd1cc2..990eb93 100644 --- a/hono/test/utils/factory/tags-outfits.ts +++ b/hono/test/utils/factory/tags-outfits.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' -import { tagStatusEnum, tagsToOutfits } from '../../../src/schema' +import { outfitTag, tagStatusEnum } from '../../../src/schema' import { instance } from '../db' export interface TagToOutfit { @@ -22,7 +22,7 @@ export class TagToOutfitFactory implements TagToOutfit { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(tagsToOutfits).values(this).onConflictDoNothing() + await db.insert(outfitTag).values(this).onConflictDoNothing() } tagId: string diff --git a/hono/test/utils/factory/tags.ts b/hono/test/utils/factory/tags.ts index 0e52466..b8a84a2 100644 --- a/hono/test/utils/factory/tags.ts +++ b/hono/test/utils/factory/tags.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker' -import { tags } from '../../../src/schema' +import { tag } from '../../../src/schema' import { instance } from '../db' export interface Tag { @@ -42,7 +42,7 @@ export class TagFactory implements Tag { async store(name: string, port: number) { const db = instance(name, port) - await db.insert(tags).values(this).onConflictDoNothing() + await db.insert(tag).values(this).onConflictDoNothing() } formatAPI(): TagAPI { diff --git a/next/src/components/ItemList.tsx b/next/src/components/ItemList.tsx index 29fe348..3b2b796 100644 --- a/next/src/components/ItemList.tsx +++ b/next/src/components/ItemList.tsx @@ -4,10 +4,10 @@ import { ItemListLoading } from './ItemListLoading' import { ItemDisplay } from './ItemDisplay' import { SelectableItem } from './SelectableItem' -type ItemToOutfit = OutfitsResponse['outfits'][number]['itemsToOutfits'][number] | OutfitSuggestionsResponse['suggestions'][number]['itemsToOutfits'][number] +type ItemToOutfit = OutfitsResponse['outfits'][number]['outfitItems'][number] | OutfitSuggestionsResponse['suggestions'][number]['outfitItems'][number] interface ItemListProps { - itemsToOutfits: ItemToOutfit[] + outfitItems: ItemToOutfit[] coreItems?: string[] showLastWornAt?: boolean showThreeDotsMenu?: boolean @@ -24,7 +24,7 @@ interface ItemListProps { * or SelectableItem with three-dots menu when actions are needed. */ export function ItemList({ - itemsToOutfits, + outfitItems, coreItems = [], showLastWornAt = false, showThreeDotsMenu = false, @@ -41,11 +41,11 @@ export function ItemList({ return } - // Transform itemsToOutfits to items with additional data + // Transform outfitItems to items with additional data const transformedItems: (ItemsResponse['items'][number] & { itemType: string freshness?: number - })[] = itemsToOutfits + })[] = outfitItems .map((itemToOutfit) => { if (!itemToOutfit.itemId || !itemToOutfit.itemType) return null diff --git a/next/src/components/OutfitList.tsx b/next/src/components/OutfitList.tsx index 5653d7f..d54f888 100644 --- a/next/src/components/OutfitList.tsx +++ b/next/src/components/OutfitList.tsx @@ -103,8 +103,8 @@ export default function OutfitList() {
- {Array.isArray(outfit.tagsToOutfits) && outfit.tagsToOutfits.length > 0 ? ( - outfit.tagsToOutfits.map((tagToOutfit) => { + {Array.isArray(outfit.outfitTags) && outfit.outfitTags.length > 0 ? ( + outfit.outfitTags.map((tagToOutfit) => { const tag = tags?.find(t => t.id === tagToOutfit.tagId) return tag ? ( - suggestion.tagsToOutfits && suggestion.tagsToOutfits.length > 0 - ); return (
@@ -123,8 +118,8 @@ export default function OutfitSuggestions() {
- {Array.isArray(suggestion.tagsToOutfits) && suggestion.tagsToOutfits.length > 0 ? ( - suggestion.tagsToOutfits.map((tagToOutfit) => { + {Array.isArray(suggestion.outfitTags) && suggestion.outfitTags.length > 0 ? ( + suggestion.outfitTags.map((tagToOutfit) => { const tag = tags?.find(t => t.id === tagToOutfit.tagId) return tag ? (