|
2 | 2 | * @vitest-environment node |
3 | 3 | */ |
4 | 4 |
|
5 | | -import { folder as folderTable } from '@sim/db/schema' |
| 5 | +import { folder as folderTable, tableViews, userTableDefinitions } from '@sim/db/schema' |
6 | 6 | import { sha256Hex } from '@sim/security/hash' |
7 | 7 | import { |
8 | 8 | dbChainMockFns, |
@@ -1211,6 +1211,127 @@ describe('copyForkResourceContent', () => { |
1211 | 1211 | }) |
1212 | 1212 | }) |
1213 | 1213 |
|
| 1214 | +describe('copyForkResourceContainers table views', () => { |
| 1215 | + it('copies saved views and seeds a default for a legacy table', async () => { |
| 1216 | + const now = new Date('2026-08-19T00:00:00.000Z') |
| 1217 | + const definitions = [ |
| 1218 | + { |
| 1219 | + id: 'table-with-view', |
| 1220 | + workspaceId: 'src-ws', |
| 1221 | + folderId: null, |
| 1222 | + name: 'Configured table', |
| 1223 | + description: null, |
| 1224 | + schema: { columns: [{ id: 'col-name', name: 'Name', type: 'string' }] }, |
| 1225 | + metadata: { columnOrder: ['col-name'] }, |
| 1226 | + maxRows: 10000, |
| 1227 | + rowCount: 1, |
| 1228 | + rowsVersion: 1, |
| 1229 | + schemaLocked: false, |
| 1230 | + insertLocked: false, |
| 1231 | + updateLocked: false, |
| 1232 | + deleteLocked: false, |
| 1233 | + archivedAt: null, |
| 1234 | + createdBy: 'source-user', |
| 1235 | + createdAt: now, |
| 1236 | + updatedAt: now, |
| 1237 | + }, |
| 1238 | + { |
| 1239 | + id: 'legacy-table', |
| 1240 | + workspaceId: 'src-ws', |
| 1241 | + folderId: null, |
| 1242 | + name: 'Legacy table', |
| 1243 | + description: null, |
| 1244 | + schema: { columns: [{ id: 'col-email', name: 'Email', type: 'string' }] }, |
| 1245 | + metadata: { columnOrder: ['col-email'] }, |
| 1246 | + maxRows: 10000, |
| 1247 | + rowCount: 0, |
| 1248 | + rowsVersion: 0, |
| 1249 | + schemaLocked: false, |
| 1250 | + insertLocked: false, |
| 1251 | + updateLocked: false, |
| 1252 | + deleteLocked: false, |
| 1253 | + archivedAt: null, |
| 1254 | + createdBy: 'source-user', |
| 1255 | + createdAt: now, |
| 1256 | + updatedAt: now, |
| 1257 | + }, |
| 1258 | + ] |
| 1259 | + const sourceViews = [ |
| 1260 | + { |
| 1261 | + id: 'source-view', |
| 1262 | + tableId: 'table-with-view', |
| 1263 | + workspaceId: 'src-ws', |
| 1264 | + name: 'My view', |
| 1265 | + config: { hiddenColumns: ['col-name'] }, |
| 1266 | + isDefault: true, |
| 1267 | + createdBy: 'source-user', |
| 1268 | + createdAt: now, |
| 1269 | + updatedAt: now, |
| 1270 | + }, |
| 1271 | + ] |
| 1272 | + const inserted = new Map<unknown, Array<Record<string, unknown>>>() |
| 1273 | + const tx = { |
| 1274 | + select: () => ({ |
| 1275 | + from: (table: unknown) => ({ |
| 1276 | + where: () => |
| 1277 | + Promise.resolve( |
| 1278 | + table === userTableDefinitions ? definitions : table === tableViews ? sourceViews : [] |
| 1279 | + ), |
| 1280 | + }), |
| 1281 | + }), |
| 1282 | + insert: (table: unknown) => ({ |
| 1283 | + values: (values: Array<Record<string, unknown>>) => { |
| 1284 | + inserted.set(table, values) |
| 1285 | + return Promise.resolve() |
| 1286 | + }, |
| 1287 | + }), |
| 1288 | + } |
| 1289 | + |
| 1290 | + const result = await copyForkResourceContainers({ |
| 1291 | + tx: tx as unknown as DbOrTx, |
| 1292 | + sourceWorkspaceId: 'src-ws', |
| 1293 | + childWorkspaceId: 'child-ws', |
| 1294 | + userId: 'user-1', |
| 1295 | + now, |
| 1296 | + selection: { |
| 1297 | + customTools: [], |
| 1298 | + skills: [], |
| 1299 | + mcpServers: [], |
| 1300 | + workflowMcpServers: [], |
| 1301 | + tables: definitions.map((definition) => definition.id), |
| 1302 | + knowledgeBases: [], |
| 1303 | + }, |
| 1304 | + workflowIdMap: new Map(), |
| 1305 | + documentMappingContext: { edgeChildWorkspaceId: 'child-ws', sourceIsParent: true }, |
| 1306 | + }) |
| 1307 | + |
| 1308 | + const copiedTableId = result.idMap.get('table')?.get('table-with-view') |
| 1309 | + const legacyTableId = result.idMap.get('table')?.get('legacy-table') |
| 1310 | + const copiedViews = inserted.get(tableViews) |
| 1311 | + expect(copiedViews).toEqual( |
| 1312 | + expect.arrayContaining([ |
| 1313 | + expect.objectContaining({ |
| 1314 | + tableId: copiedTableId, |
| 1315 | + workspaceId: 'child-ws', |
| 1316 | + name: 'My view', |
| 1317 | + config: { hiddenColumns: ['col-name'] }, |
| 1318 | + isDefault: true, |
| 1319 | + createdBy: 'user-1', |
| 1320 | + }), |
| 1321 | + expect.objectContaining({ |
| 1322 | + tableId: legacyTableId, |
| 1323 | + workspaceId: 'child-ws', |
| 1324 | + name: 'Default', |
| 1325 | + config: { columnOrder: ['col-email'] }, |
| 1326 | + isDefault: true, |
| 1327 | + createdBy: 'user-1', |
| 1328 | + }), |
| 1329 | + ]) |
| 1330 | + ) |
| 1331 | + expect(copiedViews?.find((view) => view.name === 'My view')?.id).not.toBe('source-view') |
| 1332 | + }) |
| 1333 | +}) |
| 1334 | + |
1214 | 1335 | describe('copyForkResourceContainers custom-tool code env rewrite', () => { |
1215 | 1336 | function makeContainerTx(rows: Array<Record<string, unknown>>) { |
1216 | 1337 | const inserted: Array<Record<string, unknown>> = [] |
|
0 commit comments