({
model,
provider,
table,
services,
options,
defaultSchema,
}: {
table: IntrospectedTable;
model: Model;
oldModel: Model;
provider: IntrospectionProvider;
services: ZModelServices;
options: PullOptions;
defaultSchema: string;
})
| 110 | }; |
| 111 | |
| 112 | export function syncTable({ |
| 113 | model, |
| 114 | provider, |
| 115 | table, |
| 116 | services, |
| 117 | options, |
| 118 | defaultSchema, |
| 119 | }: { |
| 120 | table: IntrospectedTable; |
| 121 | model: Model; |
| 122 | oldModel: Model; |
| 123 | provider: IntrospectionProvider; |
| 124 | services: ZModelServices; |
| 125 | options: PullOptions; |
| 126 | defaultSchema: string; |
| 127 | }) { |
| 128 | const idAttribute = getAttributeRef('@id', services); |
| 129 | const modelIdAttribute = getAttributeRef('@@id', services); |
| 130 | const uniqueAttribute = getAttributeRef('@unique', services); |
| 131 | const modelUniqueAttribute = getAttributeRef('@@unique', services); |
| 132 | const fieldMapAttribute = getAttributeRef('@map', services); |
| 133 | const tableMapAttribute = getAttributeRef('@@map', services); |
| 134 | const modelindexAttribute = getAttributeRef('@@index', services); |
| 135 | |
| 136 | const relations: Relation[] = []; |
| 137 | const { name, modified } = resolveNameCasing(options.modelCasing, table.name); |
| 138 | const multiPk = table.columns.filter((c) => c.pk).length > 1; |
| 139 | |
| 140 | const modelFactory = new DataModelFactory().setName(name).setIsView(table.type === 'view'); |
| 141 | modelFactory.setContainer(model); |
| 142 | |
| 143 | if (modified || options.alwaysMap) { |
| 144 | modelFactory.addAttribute((builder) => |
| 145 | builder.setDecl(tableMapAttribute).addArg((argBuilder) => argBuilder.StringLiteral.setValue(table.name)), |
| 146 | ); |
| 147 | } |
| 148 | // Group FK columns by constraint name to handle composite foreign keys. |
| 149 | // Each FK constraint (identified by fk_name) may span multiple columns. |
| 150 | const fkGroups = new Map<string, typeof table.columns>(); |
| 151 | table.columns.forEach((column) => { |
| 152 | if (column.foreign_key_table && column.foreign_key_name) { |
| 153 | const group = fkGroups.get(column.foreign_key_name) ?? []; |
| 154 | group.push(column); |
| 155 | fkGroups.set(column.foreign_key_name, group); |
| 156 | } |
| 157 | }); |
| 158 | |
| 159 | for (const [fkName, fkColumns] of fkGroups) { |
| 160 | const firstCol = fkColumns[0]!; |
| 161 | // For single-column FKs, check if the column is the table's single-column PK (one-to-one) |
| 162 | const isSingleColumnPk = fkColumns.length === 1 && !multiPk && firstCol.pk; |
| 163 | // A single-column FK with unique constraint means one-to-one on the opposite side |
| 164 | const isUniqueRelation = (fkColumns.length === 1 && firstCol.unique) || isSingleColumnPk; |
| 165 | relations.push({ |
| 166 | schema: table.schema, |
| 167 | table: table.name, |
| 168 | columns: fkColumns.map((c) => c.name), |
| 169 | type: 'one', |
no test coverage detected