SqlQueryManager ve ListFormWizard düzenlemeleri

This commit is contained in:
Sedat Öztürk 2026-05-01 13:20:40 +03:00
parent f3a922a5a8
commit 7bb154c936
6 changed files with 190 additions and 113 deletions

View file

@ -28,10 +28,7 @@ public class ListFormWizardAppService(
IRepository<PermissionDefinitionRecord, Guid> repoPerm, IRepository<PermissionDefinitionRecord, Guid> repoPerm,
IRepository<PermissionGroupDefinitionRecord, Guid> repoPermGroup, IRepository<PermissionGroupDefinitionRecord, Guid> repoPermGroup,
IRepository<Menu, Guid> repoMenu, IRepository<Menu, Guid> repoMenu,
IIdentityRoleRepository roleRepository,
IIdentityUserRepository userRepository,
IPermissionGrantRepository permissionGrantRepository, IPermissionGrantRepository permissionGrantRepository,
ILookupNormalizer LookupNormalizer,
IConfiguration configuration, IConfiguration configuration,
LanguageTextAppService languageTextAppService LanguageTextAppService languageTextAppService
) : PlatformAppService(), IListFormWizardAppService ) : PlatformAppService(), IListFormWizardAppService
@ -44,10 +41,7 @@ public class ListFormWizardAppService(
private readonly IRepository<PermissionDefinitionRecord, Guid> repoPerm = repoPerm; private readonly IRepository<PermissionDefinitionRecord, Guid> repoPerm = repoPerm;
private readonly IRepository<PermissionGroupDefinitionRecord, Guid> repoPermGroup = repoPermGroup; private readonly IRepository<PermissionGroupDefinitionRecord, Guid> repoPermGroup = repoPermGroup;
private readonly IRepository<Menu, Guid> repoMenu = repoMenu; private readonly IRepository<Menu, Guid> repoMenu = repoMenu;
private readonly IIdentityRoleRepository roleRepository = roleRepository;
private readonly IIdentityUserRepository userRepository = userRepository;
private readonly IPermissionGrantRepository permissionGrantRepository = permissionGrantRepository; private readonly IPermissionGrantRepository permissionGrantRepository = permissionGrantRepository;
private readonly ILookupNormalizer lookupNormalizer = LookupNormalizer;
private readonly IConfiguration _configuration = configuration; private readonly IConfiguration _configuration = configuration;
private readonly LanguageTextAppService _languageTextAppService = languageTextAppService; private readonly LanguageTextAppService _languageTextAppService = languageTextAppService;
private readonly string cultureNameDefault = PlatformConsts.DefaultLanguage; private readonly string cultureNameDefault = PlatformConsts.DefaultLanguage;
@ -101,21 +95,23 @@ public class ListFormWizardAppService(
var permNote = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermNote(wizardName)) ?? var permNote = existingPerms.FirstOrDefault(a => a.Name == WizardConsts.PermNote(wizardName)) ??
await repoPerm.InsertAsync(new PermissionDefinitionRecord(Guid.NewGuid(), groupName, WizardConsts.PermNote(wizardName), permRead.Name, WizardConsts.LangKeyNote, true, MultiTenancySides.Both), autoSave: false); await repoPerm.InsertAsync(new PermissionDefinitionRecord(Guid.NewGuid(), groupName, WizardConsts.PermNote(wizardName), permRead.Name, WizardConsts.LangKeyNote, true, MultiTenancySides.Both), autoSave: false);
// Permission Grants - Bulk Insert // Permission Grants - Bulk Insert (only missing ones)
var adminUserName = PlatformConsts.AbpIdentity.User.AdminEmailDefaultValue; var existingGrants = await permissionGrantRepository.GetListAsync("R", PlatformConsts.AbpIdentity.User.AdminRoleName);
var adminUser = await userRepository.FindByNormalizedUserNameAsync(lookupNormalizer.NormalizeName(adminUserName)); var existingGrantNames = existingGrants.Select(g => g.Name).ToHashSet();
var adminRole = await roleRepository.FindByNormalizedNameAsync(lookupNormalizer.NormalizeName(PlatformConsts.AbpIdentity.User.AdminRoleName));
await permissionGrantRepository.InsertManyAsync( var grantsToInsert = new[]
[ {
new PermissionGrant(Guid.NewGuid(), permRead.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), permRead.Name, permCreate.Name, permUpdate.Name,
new PermissionGrant(Guid.NewGuid(), permCreate.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), permDelete.Name, permExport.Name, permImport.Name, permNote.Name
new PermissionGrant(Guid.NewGuid(), permUpdate.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), }
new PermissionGrant(Guid.NewGuid(), permDelete.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), .Where(name => !existingGrantNames.Contains(name))
new PermissionGrant(Guid.NewGuid(), permExport.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), .Select(name => new PermissionGrant(Guid.NewGuid(), name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName))
new PermissionGrant(Guid.NewGuid(), permImport.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName), .ToList();
new PermissionGrant(Guid.NewGuid(), permNote.Name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName),
], autoSave: false); if (grantsToInsert.Count > 0)
{
await permissionGrantRepository.InsertManyAsync(grantsToInsert, autoSave: false);
}
//Menu Parent //Menu Parent
var menuQueryable = await repoMenu.GetQueryableAsync(); var menuQueryable = await repoMenu.GetQueryableAsync();
@ -185,44 +181,68 @@ public class ListFormWizardAppService(
}) })
.ToList(); .ToList();
//ListForm //ListForm - varsa sil, yeniden ekle
var listForm = await repoListForm.InsertAsync(new ListForm var listFormQueryable = await repoListForm.GetQueryableAsync();
var existingListForm = await AsyncExecuter.FirstOrDefaultAsync(listFormQueryable.Where(a => a.ListFormCode == input.ListFormCode));
var listFormFieldQueryable = await repoListFormField.GetQueryableAsync();
var existingListFormFields = await AsyncExecuter.ToListAsync(
listFormFieldQueryable.Where(a => a.ListFormCode == input.ListFormCode));
if (existingListFormFields.Count > 0)
{ {
ListFormType = ListFormTypeEnum.List, await repoListFormField.DeleteManyAsync(existingListFormFields, autoSave: true);
PageSize = 10, }
ExportJson = WizardConsts.DefaultExportJson,
IsSubForm = false, void ApplyListFormValues(ListForm lf)
ShowNote = true, {
LayoutJson = WizardConsts.DefaultLayoutJson(), lf.ListFormType = ListFormTypeEnum.List;
CultureName = LanguageCodes.En, lf.PageSize = 10;
ListFormCode = input.ListFormCode, lf.ExportJson = WizardConsts.DefaultExportJson;
Name = nameLangKey, lf.IsSubForm = false;
Title = titleLangKey, lf.ShowNote = true;
Description = descLangKey, lf.LayoutJson = WizardConsts.DefaultLayoutJson();
DataSourceCode = input.DataSourceCode, lf.CultureName = LanguageCodes.En;
IsTenant = input.IsTenant, lf.ListFormCode = input.ListFormCode;
IsBranch = input.IsBranch, lf.Name = nameLangKey;
IsOrganizationUnit = input.IsOrganizationUnit, lf.Title = titleLangKey;
SelectCommandType = input.SelectCommandType, lf.Description = descLangKey;
SelectCommand = input.SelectCommand, lf.DataSourceCode = input.DataSourceCode;
KeyFieldName = input.KeyFieldName, lf.IsTenant = input.IsTenant;
KeyFieldDbSourceType = input.KeyFieldDbSourceType, lf.IsBranch = input.IsBranch;
DefaultFilter = WizardConsts.DefaultFilterJson, lf.IsOrganizationUnit = input.IsOrganizationUnit;
SortMode = GridOptions.SortModeSingle, lf.SelectCommandType = input.SelectCommandType;
FilterRowJson = WizardConsts.DefaultFilterRowJson, lf.SelectCommand = input.SelectCommand;
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson, lf.KeyFieldName = input.KeyFieldName;
SearchPanelJson = WizardConsts.DefaultSearchPanelJson, lf.KeyFieldDbSourceType = input.KeyFieldDbSourceType;
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), lf.DefaultFilter = WizardConsts.DefaultFilterJson;
SelectionJson = WizardConsts.DefaultSelectionSingleJson, lf.SortMode = GridOptions.SortModeSingle;
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), lf.FilterRowJson = WizardConsts.DefaultFilterRowJson;
PermissionJson = WizardConsts.DefaultPermissionJson(code), lf.HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson;
DeleteCommand = WizardConsts.DefaultDeleteCommand(input.SelectCommand), lf.SearchPanelJson = WizardConsts.DefaultSearchPanelJson;
DeleteFieldsDefaultValueJson = WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType), lf.GroupPanelJson = JsonSerializer.Serialize(new { Visible = false });
InsertFieldsDefaultValueJson = WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType), lf.SelectionJson = WizardConsts.DefaultSelectionSingleJson;
PagerOptionJson = WizardConsts.DefaultPagerOptionJson, lf.ColumnOptionJson = WizardConsts.DefaultColumnOptionJson();
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), lf.PermissionJson = WizardConsts.DefaultPermissionJson(code);
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, lf.DeleteCommand = WizardConsts.DefaultDeleteCommand(input.SelectCommand);
}, autoSave: true); lf.DeleteFieldsDefaultValueJson = WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType);
lf.InsertFieldsDefaultValueJson = WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType);
lf.PagerOptionJson = WizardConsts.DefaultPagerOptionJson;
lf.EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail);
lf.EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null;
}
ListForm listForm;
if (existingListForm != null)
{
ApplyListFormValues(existingListForm);
listForm = await repoListForm.UpdateAsync(existingListForm, autoSave: true);
}
else
{
var newListForm = new ListForm();
ApplyListFormValues(newListForm);
listForm = await repoListForm.InsertAsync(newListForm, autoSave: true);
}
// ListFormField - each item in each group becomes a visible field record // ListFormField - each item in each group becomes a visible field record
var fieldOrder = 0; var fieldOrder = 0;

View file

@ -203,6 +203,11 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
HeaderFilterJson = DefaultHeaderFilterJson, HeaderFilterJson = DefaultHeaderFilterJson,
SearchPanelJson = DefaultSearchPanelJson, SearchPanelJson = DefaultSearchPanelJson,
GroupPanelJson = DefaultGroupPanelJson, GroupPanelJson = DefaultGroupPanelJson,
SelectionJson = JsonSerializer.Serialize(new SelectionDto
{
Mode = GridOptions.SelectionAllModeAllPages,
AllowSelectAll = true
}),
ColumnOptionJson = DefaultColumnOptionJson(), ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(AbpIdentity.Permissions.Create, listFormName, AbpIdentity.Permissions.Update, AbpIdentity.Permissions.Delete, AbpIdentity.Permissions.Export, AbpIdentity.Permissions.Import, AbpIdentity.Permissions.Note), PermissionJson = DefaultPermissionJson(AbpIdentity.Permissions.Create, listFormName, AbpIdentity.Permissions.Update, AbpIdentity.Permissions.Delete, AbpIdentity.Permissions.Export, AbpIdentity.Permissions.Import, AbpIdentity.Permissions.Note),
PagerOptionJson = DefaultPagerOptionJson, PagerOptionJson = DefaultPagerOptionJson,

View file

@ -49,4 +49,28 @@ WITH INIT;'
EXEC sp_executesql @SQL; EXEC sp_executesql @SQL;
END END
GO GO
IF OBJECT_ID(N'[dbo].[Adm_T_Deparment]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Adm_T_Deparment]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
[CreatorId] uniqueidentifier NULL,
[LastModificationTime] datetime2 NULL,
[LastModifierId] uniqueidentifier NULL,
[IsDeleted] bit NOT NULL DEFAULT 0,
[DeletionTime] datetime2 NULL,
[DeleterId] uniqueidentifier NULL,
[TenantId] uniqueidentifier NULL,
[BranchId] uniqueidentifier NOT NULL,
[Name] nvarchar(64) NOT NULL,
[ParentId] uniqueidentifier NULL,
CONSTRAINT [PK_Adm_T_Deparment] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

View file

@ -166,6 +166,10 @@ const Wizard = () => {
const selectableColumns = cols.filter((c) => !isAuditColumn(c.columnName)) const selectableColumns = cols.filter((c) => !isAuditColumn(c.columnName))
setSelectedColumns(new Set(selectableColumns.map((c) => c.columnName))) setSelectedColumns(new Set(selectableColumns.map((c) => c.columnName)))
setEditingGroups([]) setEditingGroups([])
// Auto-check isTenant / isBranch based on column presence
const colNames = new Set(cols.map((c) => c.columnName.toLowerCase()))
formikRef.current?.setFieldValue('isTenant', colNames.has('tenantid'))
formikRef.current?.setFieldValue('isBranch', colNames.has('branchid'))
// Auto-select first column as key field // Auto-select first column as key field
if (cols.length > 0) { if (cols.length > 0) {
const first = cols[0] const first = cols[0]

View file

@ -155,7 +155,7 @@ END;
( (
SELECT SELECT
c.column_id, c.column_id,
' ' + QUOTENAME(c.name) + ' ' + ' ' + QUOTENAME(c.name) + ' ' +
CASE CASE
WHEN t.name IN ('varchar', 'char', 'varbinary', 'binary') THEN WHEN t.name IN ('varchar', 'char', 'varbinary', 'binary') THEN
t.name + '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END + ')' t.name + '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(10)) END + ')'
@ -183,29 +183,30 @@ END;
pk AS pk AS
( (
SELECT SELECT
' CONSTRAINT ' + QUOTENAME(k.name) + ' PRIMARY KEY ' + ' CONSTRAINT ' + QUOTENAME(k.name) + ' PRIMARY KEY ' +
CASE WHEN i.type = 1 THEN 'CLUSTERED' ELSE 'NONCLUSTERED' END + CASE WHEN i.type = 1 THEN 'CLUSTERED' ELSE 'NONCLUSTERED' END +
' (' + CHAR(13) + CHAR(10) + ' (' + CHAR(13) + CHAR(10) +
STUFF( (
( SELECT ' ' + QUOTENAME(c.name) + CASE WHEN ic.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END + CHAR(13) + CHAR(10)
SELECT ', ' + QUOTENAME(c.name) + CASE WHEN ic.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END FROM sys.index_columns ic
FROM sys.index_columns ic INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.object_id = i.object_id
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id
AND ic.index_id = i.index_id AND ic.is_included_column = 0
AND ic.is_included_column = 0 ORDER BY ic.key_ordinal
ORDER BY ic.key_ordinal FOR XML PATH(''), TYPE
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') +
).value('.', 'NVARCHAR(MAX)') ' )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]' AS line
,1,2,'') + ')' AS line
FROM sys.key_constraints k FROM sys.key_constraints k
INNER JOIN sys.indexes i ON k.parent_object_id = i.object_id AND k.unique_index_id = i.index_id INNER JOIN sys.indexes i ON k.parent_object_id = i.object_id AND k.unique_index_id = i.index_id
WHERE k.parent_object_id = @ObjectId WHERE k.parent_object_id = @ObjectId
AND k.type = 'PK' AND k.type = 'PK'
) )
SELECT SELECT
'CREATE TABLE ${fullName}' + CHAR(13) + CHAR(10) + 'IF OBJECT_ID(N''${escapedFullName}'', ''U'') IS NULL' + CHAR(13) + CHAR(10) +
'(' + CHAR(13) + CHAR(10) + 'BEGIN' + CHAR(13) + CHAR(10) +
' CREATE TABLE ${fullName}' + CHAR(13) + CHAR(10) +
' (' + CHAR(13) + CHAR(10) +
STUFF( STUFF(
( (
SELECT ',' + CHAR(13) + CHAR(10) + line SELECT ',' + CHAR(13) + CHAR(10) + line
@ -220,7 +221,7 @@ SELECT
FROM pk FROM pk
), ),
'' ''
) + CHAR(13) + CHAR(10) + ');' AS Script;` ) + CHAR(13) + CHAR(10) + ' ) ON [PRIMARY]' + CHAR(13) + CHAR(10) + 'END' + CHAR(13) + CHAR(10) + 'GO' AS Script;`
} }
const getTableCreateScript = async (schemaName: string, tableName: string): Promise<string> => { const getTableCreateScript = async (schemaName: string, tableName: string): Promise<string> => {

View file

@ -245,7 +245,7 @@ function colToSqlLine(col: ColumnDefinition, addComma = true): string {
} }
const nullPart = col.isNullable ? 'NULL' : 'NOT NULL' const nullPart = col.isNullable ? 'NULL' : 'NOT NULL'
const defaultPart = col.defaultValue ? ` DEFAULT ${col.defaultValue}` : '' const defaultPart = col.defaultValue ? ` DEFAULT ${col.defaultValue}` : ''
return ` [${col.columnName}] ${typeSql} ${nullPart}${defaultPart}${addComma ? ',' : ''}` return ` [${col.columnName}] ${typeSql} ${nullPart}${defaultPart}${addComma ? ',' : ''}`
} }
function generateCreateTableSql( function generateCreateTableSql(
@ -256,10 +256,57 @@ function generateCreateTableSql(
): string { ): string {
const tableName = settings.tableName || 'NewTable' const tableName = settings.tableName || 'NewTable'
const fullTableName = `[dbo].[${tableName}]` const fullTableName = `[dbo].[${tableName}]`
const escapedFullTableName = fullTableName.replace(/'/g, "''")
const userCols = columns.filter((c) => c.columnName.trim()) const userCols = columns.filter((c) => c.columnName.trim())
const allBodyCols = userCols const bodyLines = userCols.map((c) => colToSqlLine(c, false))
const bodyLines = allBodyCols.map((c, i) => colToSqlLine(c, i < allBodyCols.length - 1))
// Inline PRIMARY KEY constraint inside CREATE TABLE
const pkIndex = indexes.find((idx) => idx.indexType === 'PrimaryKey' && idx.columns.length > 0)
const pkConstraintLines: string[] = []
if (pkIndex) {
const clustered = pkIndex.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
const colsSql = pkIndex.columns.map((c) => ` [${c.columnName}] ${c.order}`).join(',\n')
pkConstraintLines.push(
` CONSTRAINT [${pkIndex.indexName}] PRIMARY KEY ${clustered}`,
` (`,
colsSql,
` )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]`,
)
}
// Build all column + pk lines with commas
const allInnerLines: string[] = []
for (let i = 0; i < bodyLines.length; i++) {
allInnerLines.push(bodyLines[i] + ',')
}
if (pkConstraintLines.length > 0) {
for (let i = 0; i < pkConstraintLines.length; i++) {
allInnerLines.push(pkConstraintLines[i])
}
} else if (allInnerLines.length > 0) {
// Remove trailing comma from last column if no PK
allInnerLines[allInnerLines.length - 1] = allInnerLines[allInnerLines.length - 1].replace(/,$/, '')
}
// Non-PK index lines (UNIQUE, regular INDEX) — outside CREATE TABLE
const extraIndexLines: string[] = []
for (const idx of indexes) {
if (idx.columns.length === 0 || idx.indexType === 'PrimaryKey') continue
const clustered = idx.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
const colsSql = idx.columns.map((c) => `[${c.columnName}] ${c.order}`).join(', ')
extraIndexLines.push('')
if (idx.indexType === 'UniqueKey') {
extraIndexLines.push(`-- 🔒 Unique Key: [${idx.indexName}]`)
extraIndexLines.push(`ALTER TABLE ${fullTableName}`)
extraIndexLines.push(` ADD CONSTRAINT [${idx.indexName}] UNIQUE ${clustered} (${colsSql});`)
} else {
extraIndexLines.push(`-- 📋 Index: [${idx.indexName}]`)
extraIndexLines.push(
`CREATE ${idx.isClustered ? 'CLUSTERED ' : ''}INDEX [${idx.indexName}] ON ${fullTableName} (${colsSql});`,
)
}
}
// FK constraint lines // FK constraint lines
const fkLines: string[] = [] const fkLines: string[] = []
@ -291,42 +338,18 @@ function generateCreateTableSql(
fkLines.push(` ON UPDATE ${cascadeUpdate};`) fkLines.push(` ON UPDATE ${cascadeUpdate};`)
} }
// Index / Key SQL lines
const indexLines: string[] = []
for (const idx of indexes) {
if (idx.columns.length === 0) continue
const clustered = idx.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
const colsSql = idx.columns.map((c) => `[${c.columnName}] ${c.order}`).join(', ')
indexLines.push('')
if (idx.indexType === 'PrimaryKey') {
indexLines.push(`-- 🔑 Primary Key: [${idx.indexName}]`)
indexLines.push(`ALTER TABLE ${fullTableName}`)
indexLines.push(` ADD CONSTRAINT [${idx.indexName}] PRIMARY KEY ${clustered} (${colsSql});`)
} else if (idx.indexType === 'UniqueKey') {
indexLines.push(`-- 🔒 Unique Key: [${idx.indexName}]`)
indexLines.push(`ALTER TABLE ${fullTableName}`)
indexLines.push(` ADD CONSTRAINT [${idx.indexName}] UNIQUE ${clustered} (${colsSql});`)
} else {
indexLines.push(`-- 📋 Index: [${idx.indexName}]`)
indexLines.push(
`CREATE ${idx.isClustered ? 'CLUSTERED ' : ''}INDEX [${idx.indexName}] ON ${fullTableName} (${colsSql});`,
)
}
}
const lines: string[] = [ const lines: string[] = [
`/* ── Table: ${fullTableName} ── */`, `IF OBJECT_ID(N'${escapedFullTableName}', 'U') IS NULL`,
...(settings.entityName ? [`/* Entity Name: ${settings.entityName} */`] : []), `BEGIN`,
'', ` CREATE TABLE ${fullTableName}`,
`CREATE TABLE ${fullTableName}`, ` (`,
`(`, ...allInnerLines,
...bodyLines, ` ) ON [PRIMARY]`,
`);`, `END`,
...indexLines, `GO`,
...(fkLines.length > 0 ? ['/* Foreign Key Constraints */'] : []), ...extraIndexLines,
...(fkLines.length > 0 ? ['', '/* Foreign Key Constraints */'] : []),
...fkLines, ...fkLines,
'',
`/* Verify: SELECT TOP 10 * FROM ${fullTableName}; */`,
] ]
return lines.join('\n') return lines.join('\n')