/** * ๐Ÿ—„๏ธ ํ…Œ์ด๋ธ” ํƒ€์ž…๊ด€๋ฆฌ ์‹œ์Šคํ…œ ์ „์šฉ ํƒ€์ž… ์ •์˜ * * ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ, ์ปฌ๋Ÿผ ํƒ€์ž…, ์›นํƒ€์ž… ๋งคํ•‘ ๋“ฑ ํ…Œ์ด๋ธ” ๊ด€๋ฆฌ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…๋“ค */ import { DynamicWebType, CompanyCode, ActiveStatus, TimestampFields, BaseApiResponse, PaginatedResponse, ConditionOperator, } from "./unified-core"; // ===== ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ์ •๋ณด ===== /** * ํ…Œ์ด๋ธ” ์ •๋ณด */ export interface TableInfo { tableName: string; displayName: string; description: string; columnCount: number; companyCode?: CompanyCode; isActive?: ActiveStatus; createdDate?: Date; updatedDate?: Date; } /** * ํ†ตํ•ฉ๋œ ์ปฌ๋Ÿผ ์ •๋ณด (ํ”„๋ก ํŠธ์—”๋“œ/๋ฐฑ์—”๋“œ ํ˜ธํ™˜) */ export interface UnifiedColumnInfo { // ๊ธฐ๋ณธ ์ •๋ณด tableName: string; columnName: string; displayName: string; // ๋ฐ์ดํ„ฐ ํƒ€์ž… dataType: string; // DB ๋ฐ์ดํ„ฐ ํƒ€์ž… (varchar, integer, timestamp ๋“ฑ) dbType: string; // DB ๋‚ด๋ถ€ ํƒ€์ž… webType: DynamicWebType; // ์›น ์ž…๋ ฅ ํƒ€์ž… (text, number, date ๋“ฑ) // ์ž…๋ ฅ ์„ค์ • inputType: "direct" | "auto"; detailSettings?: Record; // JSON ํŒŒ์‹ฑ๋œ ๊ฐ์ฒด description?: string; // ์ œ์•ฝ ์กฐ๊ฑด isNullable: boolean; // Y/N โ†’ boolean ๋ณ€ํ™˜ isPrimaryKey: boolean; defaultValue?: string; // ํฌ๊ธฐ ์ œํ•œ maxLength?: number; numericPrecision?: number; numericScale?: number; // ํ‘œ์‹œ ์˜ต์…˜ isVisible?: boolean; displayOrder?: number; // ์ฐธ์กฐ ๊ด€๊ณ„ codeCategory?: string; codeValue?: string; referenceTable?: string; referenceColumn?: string; displayColumn?: string; // ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ companyCode?: CompanyCode; createdDate?: Date; updatedDate?: Date; } /** * ๋ฐฑ์—”๋“œ ํ˜ธํ™˜์šฉ ์ปฌ๋Ÿผ ํƒ€์ž… ์ •๋ณด (๊ธฐ์กด ColumnTypeInfo) */ export interface ColumnTypeInfo { columnName: string; displayName: string; dataType: string; dbType: string; webType: string; // string ํƒ€์ž… (๋ฐฑ์—”๋“œ ํ˜ธํ™˜) inputType?: "direct" | "auto"; detailSettings: string; // JSON ๋ฌธ์ž์—ด description: string; // ํ•„์ˆ˜ ํ•„๋“œ isNullable: string; // Y/N ๋ฌธ์ž์—ด isPrimaryKey: boolean; defaultValue?: string; maxLength?: number; numericPrecision?: number; numericScale?: number; codeCategory?: string; codeValue?: string; referenceTable?: string; referenceColumn?: string; displayColumn?: string; displayOrder?: number; isVisible?: boolean; } /** * ์ปฌ๋Ÿผ ์„ค์ • (์—…๋ฐ์ดํŠธ์šฉ) */ export interface ColumnSettings { columnName?: string; // ์ปฌ๋Ÿผ๋ช… (์—…๋ฐ์ดํŠธ ์‹œ ํ•„์š”) columnLabel: string; // ์ปฌ๋Ÿผ ํ‘œ์‹œ๋ช… webType: string; // ์›น ์ž…๋ ฅ ํƒ€์ž… detailSettings: string; // ์ƒ์„ธ ์„ค์ • (JSON ๋ฌธ์ž์—ด) codeCategory: string; // ์ฝ”๋“œ ์นดํ…Œ๊ณ ๋ฆฌ codeValue: string; // ์ฝ”๋“œ ๊ฐ’ referenceTable: string; // ์ฐธ์กฐ ํ…Œ์ด๋ธ” referenceColumn: string; // ์ฐธ์กฐ ์ปฌ๋Ÿผ displayColumn?: string; // ํ‘œ์‹œํ•  ์ปฌ๋Ÿผ๋ช… displayOrder?: number; // ํ‘œ์‹œ ์ˆœ์„œ isVisible?: boolean; // ํ‘œ์‹œ ์—ฌ๋ถ€ } // ===== ์›นํƒ€์ž… ํ‘œ์ค€ ์ •์˜ ===== /** * ์›นํƒ€์ž… ํ‘œ์ค€ ์ •๋ณด (DB์˜ web_type_standards ํ…Œ์ด๋ธ”) */ export interface WebTypeStandard extends TimestampFields { web_type: string; type_name: string; type_name_eng?: string; description?: string; category: string; default_config?: unknown; // JSON validation_rules?: unknown; // JSON default_style?: unknown; // JSON input_properties?: unknown; // JSON sort_order?: number; is_active: ActiveStatus; component_name?: string; config_panel?: string; } /** * ํ”„๋ก ํŠธ์—”๋“œ์šฉ ์›นํƒ€์ž… ์ •์˜ (WebTypeStandard ๋ณ€ํ™˜) */ export interface WebTypeDefinition { webType: string; // web_type ํ•„๋“œ typeName: string; // type_name ํ•„๋“œ typeNameEng?: string; // type_name_eng ํ•„๋“œ description?: string; category: string; defaultConfig: Record; // JSON ํƒ€์ž… ๋งคํ•‘ validationRules?: Record; // JSON ํƒ€์ž… ๋งคํ•‘ defaultStyle?: Record; // JSON ํƒ€์ž… ๋งคํ•‘ inputProperties?: Record; // JSON ํƒ€์ž… ๋งคํ•‘ componentName?: string; // component_name ํ•„๋“œ configPanel?: string; // config_panel ํ•„๋“œ sortOrder?: number; // sort_order ํ•„๋“œ isActive: boolean; // is_active Y/N โ†’ boolean ๋ณ€ํ™˜ } // ===== ํ…Œ์ด๋ธ” ๋ผ๋ฒจ ๊ด€๋ฆฌ ===== /** * ํ…Œ์ด๋ธ” ๋ผ๋ฒจ */ export interface TableLabels extends TimestampFields { tableName: string; tableLabel?: string; description?: string; companyCode?: CompanyCode; } /** * ์ปฌ๋Ÿผ ๋ผ๋ฒจ */ export interface ColumnLabels extends TimestampFields { id?: number; tableName: string; columnName: string; columnLabel?: string; webType?: string; detailSettings?: string; description?: string; displayOrder?: number; isVisible?: boolean; codeCategory?: string; codeValue?: string; referenceTable?: string; referenceColumn?: string; displayColumn?: string; companyCode?: CompanyCode; } // ===== ์—”ํ‹ฐํ‹ฐ ์กฐ์ธ ๊ด€๋ฆฌ ===== /** * ์—”ํ‹ฐํ‹ฐ ์กฐ์ธ ์„ค์ • */ export interface EntityJoinConfig { sourceTable: string; // ์›๋ณธ ํ…Œ์ด๋ธ” (์˜ˆ: companies) sourceColumn: string; // ์›๋ณธ ์ปฌ๋Ÿผ (์˜ˆ: writer) referenceTable: string; // ์ฐธ์กฐ ํ…Œ์ด๋ธ” (์˜ˆ: user_info) referenceColumn: string; // ์กฐ์ธ ํ‚ค (์˜ˆ: user_id) displayColumn: string; // ํ‘œ์‹œํ•  ๊ฐ’ (์˜ˆ: user_name) aliasColumn: string; // ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ๋ช… (์˜ˆ: writer_name) companyCode?: CompanyCode; } /** * ์—”ํ‹ฐํ‹ฐ ์กฐ์ธ ์‘๋‹ต */ export interface EntityJoinResponse { data: Record[]; total: number; page: number; size: number; totalPages: number; entityJoinInfo?: { joinConfigs: EntityJoinConfig[]; strategy: "full_join" | "cache_lookup" | "hybrid"; performance: { queryTime: number; cacheHitRate?: number; hybridBreakdown?: { dbJoins: number; cacheJoins: number; }; }; }; } /** * ๋ฐฐ์น˜ ์กฐํšŒ ์š”์ฒญ */ export interface BatchLookupRequest { table: string; key: string; displayColumn: string; companyCode?: CompanyCode; } /** * ๋ฐฐ์น˜ ์กฐํšŒ ์‘๋‹ต */ export interface BatchLookupResponse { key: string; value: unknown; } // ===== ํ…Œ์ด๋ธ” ๊ด€๊ณ„ ๊ด€๋ฆฌ ===== /** * ํ…Œ์ด๋ธ” ๊ด€๊ณ„ ์ •์˜ */ export interface TableRelationship extends TimestampFields { relationship_id?: number; relationship_name?: string; from_table_name?: string; from_column_name?: string; to_table_name?: string; to_column_name?: string; relationship_type?: string; connection_type?: string; company_code?: CompanyCode; settings?: unknown; // JSON is_active?: ActiveStatus; diagram_id?: number; } /** * ๋ฐ์ดํ„ฐ ๊ด€๊ณ„ ๋ธŒ๋ฆฟ์ง€ */ export interface DataRelationshipBridge extends TimestampFields { bridge_id?: number; relationship_id?: number; from_table_name: string; from_column_name: string; to_table_name: string; to_column_name: string; connection_type: string; company_code: CompanyCode; is_active?: ActiveStatus; bridge_data?: unknown; // JSON from_key_value?: string; from_record_id?: string; to_key_value?: string; to_record_id?: string; } // ===== ์ปฌ๋Ÿผ ์›นํƒ€์ž… ์„ค์ • ===== /** * ์ปฌ๋Ÿผ ์›นํƒ€์ž… ์„ค์ • */ export interface ColumnWebTypeSetting { tableName: string; columnName: string; webType: DynamicWebType; detailSettings?: Record; codeCategory?: string; referenceTable?: string; referenceColumn?: string; displayColumn?: string; companyCode?: CompanyCode; } // ===== API ์‘๋‹ต ํƒ€์ž…๋“ค ===== /** * ํ…Œ์ด๋ธ” ๋ชฉ๋ก ์‘๋‹ต */ export interface TableListResponse extends BaseApiResponse {} /** * ์ปฌ๋Ÿผ ๋ชฉ๋ก ์‘๋‹ต */ export interface ColumnListResponse extends BaseApiResponse {} /** * ์ปฌ๋Ÿผ ํƒ€์ž… ์ •๋ณด ์‘๋‹ต (๋ฐฑ์—”๋“œ ํ˜ธํ™˜) */ export interface ColumnTypeInfoResponse extends BaseApiResponse {} /** * ์ปฌ๋Ÿผ ์„ค์ • ์‘๋‹ต */ export interface ColumnSettingsResponse extends BaseApiResponse {} /** * ์›นํƒ€์ž… ํ‘œ์ค€ ๋ชฉ๋ก ์‘๋‹ต */ export interface WebTypeStandardListResponse extends BaseApiResponse {} /** * ์›นํƒ€์ž… ์ •์˜ ๋ชฉ๋ก ์‘๋‹ต */ export interface WebTypeDefinitionListResponse extends BaseApiResponse {} /** * ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์กฐํšŒ ์‘๋‹ต */ export interface TableDataResponse extends PaginatedResponse> {} // ===== ์›นํƒ€์ž… ์˜ต์…˜ ์ƒ์ˆ˜ ===== /** * ์›นํƒ€์ž… ์˜ต์…˜ (๊ธฐ์กด ํ˜ธํ™˜์„ฑ ์œ ์ง€) */ export const WEB_TYPE_OPTIONS = [ { value: "text", label: "text", description: "์ผ๋ฐ˜ ํ…์ŠคํŠธ ์ž…๋ ฅ" }, { value: "number", label: "number", description: "์ˆซ์ž ์ž…๋ ฅ" }, { value: "decimal", label: "decimal", description: "์†Œ์ˆ˜ ์ž…๋ ฅ" }, { value: "date", label: "date", description: "๋‚ ์งœ ์„ ํƒ๊ธฐ" }, { value: "datetime", label: "datetime", description: "๋‚ ์งœ์‹œ๊ฐ„ ์„ ํƒ๊ธฐ" }, { value: "code", label: "code", description: "์ฝ”๋“œ ์„ ํƒ (๊ณตํ†ต์ฝ”๋“œ ์ง€์ •)" }, { value: "entity", label: "entity", description: "์—”ํ‹ฐํ‹ฐ ์ฐธ์กฐ (์ฐธ์กฐํ…Œ์ด๋ธ” ์ง€์ •)" }, { value: "textarea", label: "textarea", description: "์—ฌ๋Ÿฌ ์ค„ ํ…์ŠคํŠธ" }, { value: "select", label: "select", description: "๋“œ๋กญ๋‹ค์šด ์„ ํƒ" }, { value: "dropdown", label: "dropdown", description: "๋“œ๋กญ๋‹ค์šด ์„ ํƒ" }, { value: "checkbox", label: "checkbox", description: "์ฒดํฌ๋ฐ•์Šค" }, { value: "boolean", label: "boolean", description: "์ฐธ/๊ฑฐ์ง“" }, { value: "radio", label: "radio", description: "๋ผ๋””์˜ค ๋ฒ„ํŠผ" }, { value: "file", label: "file", description: "ํŒŒ์ผ ์—…๋กœ๋“œ" }, { value: "email", label: "email", description: "์ด๋ฉ”์ผ ์ž…๋ ฅ" }, { value: "tel", label: "tel", description: "์ „ํ™”๋ฒˆํ˜ธ ์ž…๋ ฅ" }, { value: "url", label: "url", description: "URL ์ž…๋ ฅ" }, ] as const; /** * ์›นํƒ€์ž… (๊ธฐ์กด ํ˜ธํ™˜์„ฑ) */ export type WebType = (typeof WEB_TYPE_OPTIONS)[number]["value"]; // ===== ๋ณ€ํ™˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค ===== /** * WebTypeStandard๋ฅผ WebTypeDefinition์œผ๋กœ ๋ณ€ํ™˜ */ export const mapWebTypeStandardToDefinition = (standard: WebTypeStandard): WebTypeDefinition => ({ webType: standard.web_type, typeName: standard.type_name, typeNameEng: standard.type_name_eng || undefined, description: standard.description || undefined, category: standard.category || "input", defaultConfig: (standard.default_config as Record) || {}, validationRules: (standard.validation_rules as Record) || undefined, defaultStyle: (standard.default_style as Record) || undefined, inputProperties: (standard.input_properties as Record) || undefined, componentName: standard.component_name || undefined, configPanel: standard.config_panel || undefined, sortOrder: standard.sort_order || 0, isActive: standard.is_active === "Y", }); /** * ColumnTypeInfo๋ฅผ UnifiedColumnInfo๋กœ ๋ณ€ํ™˜ */ export const mapColumnTypeInfoToUnified = (columnInfo: ColumnTypeInfo): UnifiedColumnInfo => ({ tableName: columnInfo.tableName || "", columnName: columnInfo.columnName, displayName: columnInfo.displayName, dataType: columnInfo.dataType, dbType: columnInfo.dbType, webType: columnInfo.webType, inputType: columnInfo.inputType || "direct", detailSettings: columnInfo.detailSettings ? JSON.parse(columnInfo.detailSettings) : undefined, description: columnInfo.description, isNullable: columnInfo.isNullable === "Y", isPrimaryKey: columnInfo.isPrimaryKey, defaultValue: columnInfo.defaultValue, maxLength: columnInfo.maxLength, numericPrecision: columnInfo.numericPrecision, numericScale: columnInfo.numericScale, isVisible: columnInfo.isVisible, displayOrder: columnInfo.displayOrder, codeCategory: columnInfo.codeCategory, codeValue: columnInfo.codeValue, referenceTable: columnInfo.referenceTable, referenceColumn: columnInfo.referenceColumn, displayColumn: columnInfo.displayColumn, }); /** * UnifiedColumnInfo๋ฅผ ColumnTypeInfo๋กœ ๋ณ€ํ™˜ */ export const mapUnifiedToColumnTypeInfo = (unified: UnifiedColumnInfo): ColumnTypeInfo => ({ tableName: unified.tableName, columnName: unified.columnName, displayName: unified.displayName, dataType: unified.dataType, dbType: unified.dbType, webType: unified.webType, inputType: unified.inputType, detailSettings: unified.detailSettings ? JSON.stringify(unified.detailSettings) : "{}", description: unified.description || "", isNullable: unified.isNullable ? "Y" : "N", isPrimaryKey: unified.isPrimaryKey, defaultValue: unified.defaultValue, maxLength: unified.maxLength, numericPrecision: unified.numericPrecision, numericScale: unified.numericScale, isVisible: unified.isVisible, displayOrder: unified.displayOrder, codeCategory: unified.codeCategory, codeValue: unified.codeValue, referenceTable: unified.referenceTable, referenceColumn: unified.referenceColumn, displayColumn: unified.displayColumn, }); // ===== ํƒ€์ž… ๊ฐ€๋“œ ํ•จ์ˆ˜๋“ค ===== /** * ์›นํƒ€์ž…์ด ์ฐธ์กฐ ํƒ€์ž…์ธ์ง€ ํ™•์ธ */ export const isReferenceWebType = (webType: string): boolean => { return ["code", "entity"].includes(webType); }; /** * ์›นํƒ€์ž…์ด ์ˆซ์ž ํƒ€์ž…์ธ์ง€ ํ™•์ธ */ export const isNumericWebType = (webType: string): boolean => { return ["number", "decimal"].includes(webType); }; /** * ์›นํƒ€์ž…์ด ๋‚ ์งœ ํƒ€์ž…์ธ์ง€ ํ™•์ธ */ export const isDateWebType = (webType: string): boolean => { return ["date", "datetime"].includes(webType); }; /** * ์›นํƒ€์ž…์ด ์„ ํƒ ํƒ€์ž…์ธ์ง€ ํ™•์ธ */ export const isSelectWebType = (webType: string): boolean => { return ["select", "dropdown", "radio", "checkbox", "boolean"].includes(webType); }; /** * ์ปฌ๋Ÿผ์ด ํ•„์ˆ˜ ํ•„๋“œ์ธ์ง€ ํ™•์ธ */ export const isRequiredColumn = (column: UnifiedColumnInfo): boolean => { return !column.isNullable || column.isPrimaryKey; }; /** * ์ปฌ๋Ÿผ์ด ์‹œ์Šคํ…œ ์ปฌ๋Ÿผ์ธ์ง€ ํ™•์ธ */ export const isSystemColumn = (columnName: string): boolean => { const systemColumns = [ "created_date", "updated_date", "created_by", "updated_by", "is_active", "company_code", "version", "id", ]; return systemColumns.includes(columnName.toLowerCase()); };