diff options
Diffstat (limited to 'db/schema')
| -rw-r--r-- | db/schema/projects.ts | 18 | ||||
| -rw-r--r-- | db/schema/vendorData.ts | 228 |
2 files changed, 147 insertions, 99 deletions
diff --git a/db/schema/projects.ts b/db/schema/projects.ts index 9e253d77..9220b249 100644 --- a/db/schema/projects.ts +++ b/db/schema/projects.ts @@ -1,13 +1,13 @@ -import { pgTable, varchar, text, timestamp ,serial} from "drizzle-orm/pg-core" +import { pgTable, varchar, text, timestamp, serial } from "drizzle-orm/pg-core" export const projects = pgTable("projects", { - id: serial("id").primaryKey(), - code: varchar("code", { length: 50 }).notNull(), - name: text("name").notNull(), - type: varchar("type", { length: 20 }).default("ship").notNull(), + id: serial("id").primaryKey(), + code: varchar("code", { length: 50 }).notNull(), + name: text("name").notNull(), + type: varchar("type", { length: 20 }).default("ship").notNull(), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updated_at").defaultNow().notNull(), - }) + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updated_at").defaultNow().notNull(), +}) - export type Project = typeof projects.$inferSelect
\ No newline at end of file +export type Project = typeof projects.$inferSelect
\ No newline at end of file diff --git a/db/schema/vendorData.ts b/db/schema/vendorData.ts index 03248fb8..36810e50 100644 --- a/db/schema/vendorData.ts +++ b/db/schema/vendorData.ts @@ -3,10 +3,21 @@ import { text, varchar, timestamp, - integer, numeric, date, unique, serial, jsonb, uniqueIndex + integer, + unique, + serial, + jsonb, + uniqueIndex, + primaryKey, + foreignKey, + pgView } from "drizzle-orm/pg-core" +import { and, eq} from "drizzle-orm"; + import { contractItems } from "./contract" +import { projects } from "./projects" // projects 테이블 임포트 가정 +// 기존 테이블들은 그대로 유지 export const forms = pgTable("forms", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), contractItemId: integer("contract_item_id") @@ -14,13 +25,10 @@ export const forms = pgTable("forms", { .references(() => contractItems.id, { onDelete: "cascade" }), formCode: varchar("form_code", { length: 100 }).notNull(), formName: varchar("form_name", { length: 255 }).notNull(), - // tagType: varchar("tag_type", { length: 50 }).notNull(), - // class: varchar("class", { length: 100 }).notNull(), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), }, (table) => { return { - // contractItemId와 formCode의 조합을 유니크하게 설정 contractItemFormCodeUnique: uniqueIndex("contract_item_form_code_unique").on( table.contractItemId, table.formCode @@ -28,25 +36,25 @@ export const forms = pgTable("forms", { } }) -export const formTemplates = pgTable("form_templates", { - id: serial("id").primaryKey(), - formId: integer("form_id").references(() => forms.id), - fileName: varchar("file_name", { length: 255 }).notNull(), - filePath: varchar("file_path", { length: 1024 }).notNull(), - - createdAt: timestamp("created_at").defaultNow().notNull(), - udpatedAt: timestamp("updated_at").defaultNow().notNull(), - -}); - - +// formMetas에 projectId 추가 export const formMetas = pgTable("form_metas", { id: serial("id").primaryKey(), + projectId: integer("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), formCode: varchar("form_code", { length: 50 }).notNull(), formName: varchar("form_name", { length: 255 }).notNull(), columns: jsonb("columns").notNull(), createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), +}, (table) => { + return { + // formCode는 프로젝트 내에서만 유니크하면 됨 + formCodeProjectUnique: unique("form_code_project_unique").on( + table.projectId, + table.formCode + ) + } }) export const formEntries = pgTable("form_entries", { @@ -60,148 +68,188 @@ export const formEntries = pgTable("form_entries", { updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), }) - -// ============ tags (각 계약 아이템에 대한 Tag) ============ -// "어느 계약의 어느 아이템에 대한 태그"임을 나타내려면 contract_items를 참조 export const tags = pgTable("tags", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), - - // 이 Tag가 속한 "계약 내 아이템" (즉 contract_items.id) contractItemId: integer("contract_item_id") .notNull() .references(() => contractItems.id, { onDelete: "cascade" }), - formId: integer("form_id") .references(() => forms.id, { onDelete: "set null" }), - tagNo: varchar("tag_no", { length: 100 }).notNull(), tagType: varchar("tag_type", { length: 50 }).notNull(), class: varchar("class", { length: 100 }).notNull(), description: text("description"), - createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), }) -export type Tag = typeof tags.$inferSelect -export type Form = typeof forms.$inferSelect -export type NewTag = typeof tags.$inferInsert - +// tagTypes에 projectId 추가 및 복합 기본키 생성 export const tagTypes = pgTable("tag_types", { - code: varchar("code", { length: 50 }).primaryKey(), + code: varchar("code", { length: 50 }).notNull(), + projectId: integer("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), description: text("description").notNull(), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), +}, (table) => { + return { + // code는 더 이상 단독 PK가 아니고, projectId와 함께 복합 PK 구성 + pk: primaryKey({ columns: [table.code, table.projectId] }) + } }) +// tagSubfields에 projectId 추가 및 FK/유니크 제약 업데이트 export const tagSubfields = pgTable("tag_subfields", { id: serial("id").primaryKey(), - - // 외래키: tagTypeCode -> tagTypes.code - tagTypeCode: varchar("tag_type_code", { length: 50 }) + projectId: integer("project_id") .notNull() - .references(() => tagTypes.code, { onDelete: "cascade" }), - - /** - * 나머지 필드 - */ - // tagTypeDescription: -> 이제 불필요. tagTypes.description로 join + .references(() => projects.id, { onDelete: "cascade" }), + tagTypeCode: varchar("tag_type_code", { length: 50 }).notNull(), attributesId: varchar("attributes_id", { length: 50 }).notNull(), attributesDescription: text("attributes_description").notNull(), - expression: text("expression"), delimiter: varchar("delimiter", { length: 10 }), - sortOrder: integer("sort_order").default(0).notNull(), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), }, (table) => { return { + // 유니크 제약은 이제 projectId를 포함 uniqTagTypeAttribute: unique("uniq_tag_type_attribute").on( + table.projectId, table.tagTypeCode, table.attributesId ), + // tagTypes 참조를 위한 복합 FK (tagTypeCode, projectId) + tagTypeRef: foreignKey({ + columns: [table.tagTypeCode, table.projectId], + foreignColumns: [tagTypes.code, tagTypes.projectId] + }).onDelete("cascade") }; }); +// tagSubfieldOptions에 projectId 추가 및 FK/유니크 제약 업데이트 export const tagSubfieldOptions = pgTable("tag_subfield_options", { id: serial("id").primaryKey(), - - // 어떤 subfield에 속하는 옵션인지 - attributesId: varchar("attributes_id", { length: 50 }) + projectId: integer("project_id") .notNull() - .references(() => tagSubfields.attributesId, { onDelete: "cascade" }), - - /** - * 실제 코드 (예: "PM", "AA", "VB", "VAR", "01", "02" ...) - */ + .references(() => projects.id, { onDelete: "cascade" }), + attributesId: varchar("attributes_id", { length: 50 }).notNull(), code: varchar("code", { length: 50 }).notNull(), - - /** - * 사용자에게 보여줄 레이블 (예: "Pump", "Pneumatic Motor", "Ball Valve", ...) - */ label: text("label").notNull(), - - /** - * 생성/수정 시각 (선택) - */ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), +}, (table) => { + return { + // 코드는 projectId + attributesId 조합 내에서 유니크해야 함 + uniqAttributeProjectCode: unique("uniq_attribute_project_code").on( + table.projectId, + table.attributesId, + table.code + ), + // tagSubfields 참조를 위한 복합 FK + // attributesId만으로는 더 이상 유니크하지 않으므로 projectId도 함께 참조 + attributesRef: foreignKey({ + columns: [table.attributesId, table.projectId], + // tagSubfields의 attributesId + projectId 참조 + foreignColumns: [tagSubfields.attributesId, tagSubfields.projectId] + }).onDelete("cascade") + }; }) +// tagClasses에 projectId 추가 및 FK 업데이트 export const tagClasses = pgTable("tag_classes", { id: integer("id").primaryKey().generatedAlwaysAsIdentity(), - - // 기존 code/label + projectId: integer("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), code: varchar("code", { length: 100 }).notNull(), label: text("label").notNull(), - - // 새 필드: tagTypeCode -> references tagTypes.code - tagTypeCode: varchar("tag_type_code", { length: 50 }) - .notNull() - .references(() => tagTypes.code, { onDelete: "cascade" }), - + tagTypeCode: varchar("tag_type_code", { length: 50 }).notNull(), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), +}, (table) => { + return { + // 코드는 프로젝트 내에서 유니크해야 함 + uniqCodeInProject: unique("uniq_code_in_project").on( + table.projectId, + table.code + ), + // tagTypes 참조를 위한 복합 FK + tagTypeRef: foreignKey({ + columns: [table.tagTypeCode, table.projectId], + foreignColumns: [tagTypes.code, tagTypes.projectId] + }).onDelete("cascade") + }; }) +// tagTypeClassFormMappings에 projectId 추가 export const tagTypeClassFormMappings = pgTable("tag_type_class_form_mappings", { id: serial("id").primaryKey(), - + projectId: integer("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), tagTypeLabel: varchar("tag_type_label", { length: 255 }).notNull(), classLabel: varchar("class_label", { length: 255 }).notNull(), - formCode: varchar("form_code", { length: 50 }).notNull(), formName: varchar("form_name", { length: 255 }).notNull(), - createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(), +}, (table) => { + return { + // 매핑은 프로젝트 내에서 유니크해야 함 + uniqMappingInProject: unique("uniq_mapping_in_project").on( + table.projectId, + table.tagTypeLabel, + table.classLabel, + table.formCode + ) + }; }) +// view_tag_subfields에도 projectId 추가 +export const viewTagSubfields = pgView("view_tag_subfields").as((qb) => { + return qb + .select({ + // id: tagSubfields.id, + // projectId: tagSubfields.projectId, + tagTypeCode: tagSubfields.tagTypeCode, + tagTypeDescription: tagTypes.description, + attributesId: tagSubfields.attributesId, + attributesDescription: tagSubfields.attributesDescription, + expression: tagSubfields.expression, + delimiter: tagSubfields.delimiter, + sortOrder: tagSubfields.sortOrder, + createdAt: tagSubfields.createdAt, + updatedAt: tagSubfields.updatedAt, + // 프로젝트 관련 정보 추가 + projectId: projects.id, + projectCode: projects.code, + projectName: projects.name + }) + .from(tagSubfields) + .innerJoin( + tagTypes, + and( + eq(tagSubfields.tagTypeCode, tagTypes.code), + eq(tagSubfields.projectId, tagTypes.projectId) + ) + ) + .innerJoin( + projects, + eq(tagSubfields.projectId, projects.id) + ) + }); + +// 타입 정의 업데이트 +export type Tag = typeof tags.$inferSelect +export type Form = typeof forms.$inferSelect +export type NewTag = typeof tags.$inferInsert export type TagTypeClassFormMappings = typeof tagTypeClassFormMappings.$inferSelect export type TagSubfields = typeof tagSubfields.$inferSelect export type TagSubfieldOption = typeof tagSubfieldOptions.$inferSelect export type TagClasses = typeof tagClasses.$inferSelect - - -export const viewTagSubfields = pgTable("view_tag_subfields", { - id: integer("id").primaryKey(), - - tagTypeCode: varchar("tag_type_code", { length: 50 }).notNull(), - tagTypeDescription: text("tag_type_description"), - attributesId: varchar("attributes_id", { length: 50 }).notNull(), - attributesDescription: text("attributes_description").notNull(), - - expression: text("expression"), - delimiter: varchar("delimiter", { length: 10 }), - sortOrder: integer("sort_order").default(0).notNull(), - - createdAt: timestamp("created_at", { withTimezone: true }), - updatedAt: timestamp("updated_at", { withTimezone: true }), -}) - export type ViewTagSubfields = typeof viewTagSubfields.$inferSelect export const vendorDataReportTemps = pgTable("vendor_data_report_temps", { @@ -217,9 +265,9 @@ export const vendorDataReportTemps = pgTable("vendor_data_report_temps", { createdAt: timestamp("created_at", { withTimezone: true }) .defaultNow() .notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }) + updatedAt: timestamp("updated_at", { withTimezone: true }) .defaultNow() .notNull(), - }); +}); - export type VendorDataReportTemps = typeof vendorDataReportTemps.$inferSelect;
\ No newline at end of file +export type VendorDataReportTemps = typeof vendorDataReportTemps.$inferSelect;
\ No newline at end of file |
