|
1 | 1 | import betterSqlite3 from 'better-sqlite3'; |
2 | | -import { IAdminForthDataSourceConnector, IAdminForthSingleFilter, IAdminForthAndOrFilter, AdminForthResource, AdminForthResourceColumn } from '../types/Back.js'; |
| 2 | +import { IAdminForthDataSourceConnector, IAdminForthSingleFilter, IAdminForthAndOrFilter, AdminForthResource, AdminForthResourceColumn, AdminForthConfig } from '../types/Back.js'; |
3 | 3 | import AdminForthBaseConnector from './baseConnector.js'; |
4 | 4 | import dayjs from 'dayjs'; |
5 | 5 | import { AdminForthDataTypes, AdminForthFilterOperators, AdminForthSortDirections } from '../types/Common.js'; |
@@ -37,11 +37,35 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData |
37 | 37 | sampleValue: sampleRow[col.name], |
38 | 38 | })); |
39 | 39 | } |
| 40 | + |
| 41 | + async hasSQLiteCascadeFk(resource: AdminForthResource, config: AdminForthConfig): Promise<boolean> { |
| 42 | + const cascadeColumn = resource.columns?.find(c => c.foreignResource?.onDelete === 'cascade'); |
| 43 | + if (!cascadeColumn) return false; |
| 44 | + |
| 45 | + const parentResource = config.resources.find(r => r.resourceId === cascadeColumn.foreignResource.resourceId); |
| 46 | + if (!parentResource) return false; |
| 47 | + |
| 48 | + const fkStmt = this.client.prepare(`PRAGMA foreign_key_list(${resource.table})`); |
| 49 | + const fkRows = await fkStmt.all(); |
| 50 | + const fkMap: { [colName: string]: boolean } = {}; |
| 51 | + fkRows.forEach(fk => { fkMap[fk.from] = fk.on_delete?.toUpperCase() === 'CASCADE'; }); |
| 52 | + |
| 53 | + const hasCascadeOnTable = fkMap[cascadeColumn.name] || false; |
| 54 | + const isUploadPluginInstalled = resource.plugins?.some(p => p.className === "UploadPlugin"); |
| 55 | + |
| 56 | + if (hasCascadeOnTable && isUploadPluginInstalled) { |
| 57 | + afLogger.warn(`Table "${resource.table}" has ON DELETE CASCADE and UploadPlugin installed, which may conflict with adminForth cascade deletion`); |
| 58 | + } |
| 59 | + |
| 60 | + return hasCascadeOnTable; |
| 61 | + } |
| 62 | + |
| 63 | + async discoverFields(resource: AdminForthResource, config: AdminForthConfig): Promise<{[key: string]: AdminForthResourceColumn}> { |
40 | 64 |
|
41 | | - async discoverFields(resource: AdminForthResource): Promise<{[key: string]: AdminForthResourceColumn}> { |
42 | 65 | const tableName = resource.table; |
43 | 66 | const stmt = this.client.prepare(`PRAGMA table_info(${tableName})`); |
44 | | - const rows = await stmt.all(); |
| 67 | + const rows = await stmt.all(); |
| 68 | + await this.hasSQLiteCascadeFk(resource, config); |
45 | 69 | const fieldTypes = {}; |
46 | 70 | rows.forEach((row) => { |
47 | 71 | const field: any = {}; |
@@ -86,6 +110,7 @@ class SQLiteConnector extends AdminForthBaseConnector implements IAdminForthData |
86 | 110 | field._baseTypeDebug = baseType; |
87 | 111 | field.required = row.notnull == 1; |
88 | 112 | field.primaryKey = row.pk == 1; |
| 113 | + |
89 | 114 | field.default = row.dflt_value; |
90 | 115 | fieldTypes[row.name] = field |
91 | 116 | }); |
|
0 commit comments