Table.Columns/Constraints/Indexes/Relationships are Go maps, and every writer, reader, diff, inspector, and merge code path that iterated them directly was subject to Go's randomized map order, so identical input could produce different output (or a different in-report violation/diff order) on every run. Most visibly this showed up as bun/gorm `unique:` struct tags changing order across consecutive `make models` runs with no source change. Fixed by sorting map iteration (by Sequence then Name, or alphabetically for string-keyed maps) everywhere the order affects generated output or first-match tie-break logic, across the bun, gorm, sqlite, dbml, drawdb, pgsql, prisma, graphql, typeorm, drizzle, and dctx writers; the dctx, prisma, and typeorm readers; the shared models.GetPrimaryKey/ GetForeignKeys helpers; pkg/diff, pkg/inspector, and pkg/merge; and the TUI column/relationship pickers in pkg/ui.
644 lines
19 KiB
Go
644 lines
19 KiB
Go
package pgsql
|
|
|
|
import (
|
|
"bytes"
|
|
"embed"
|
|
"fmt"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
|
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
|
)
|
|
|
|
//go:embed templates/*.tmpl
|
|
var templateFS embed.FS
|
|
|
|
// TemplateExecutor manages and executes SQL templates
|
|
type TemplateExecutor struct {
|
|
templates *template.Template
|
|
}
|
|
|
|
// NewTemplateExecutor creates a new template executor.
|
|
// flattenSchema controls whether schema.table identifiers use dot or underscore separation.
|
|
func NewTemplateExecutor(flattenSchema bool) (*TemplateExecutor, error) {
|
|
// Create template with custom functions
|
|
funcMap := make(template.FuncMap)
|
|
for k, v := range TemplateFunctions() {
|
|
funcMap[k] = v
|
|
}
|
|
|
|
// qual_table returns a quoted, schema-qualified identifier.
|
|
// With flatten=false: "schema"."table" (or unquoted equivalents).
|
|
// With flatten=true: "schema_table".
|
|
funcMap["qual_table"] = func(schema, name string) string {
|
|
if schema == "" {
|
|
return quoteIdent(name)
|
|
}
|
|
if flattenSchema {
|
|
return quoteIdent(schema + "_" + name)
|
|
}
|
|
return quoteIdent(schema) + "." + quoteIdent(name)
|
|
}
|
|
|
|
// qual_table_raw is the same as qual_table but without identifier quoting.
|
|
funcMap["qual_table_raw"] = func(schema, name string) string {
|
|
if schema == "" {
|
|
return name
|
|
}
|
|
if flattenSchema {
|
|
return schema + "_" + name
|
|
}
|
|
return schema + "." + name
|
|
}
|
|
|
|
tmpl, err := template.New("").Funcs(funcMap).ParseFS(templateFS, "templates/*.tmpl")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse templates: %w", err)
|
|
}
|
|
|
|
return &TemplateExecutor{
|
|
templates: tmpl,
|
|
}, nil
|
|
}
|
|
|
|
// Template data structures
|
|
|
|
// CreateTableData contains data for create table template
|
|
type CreateTableData struct {
|
|
SchemaName string
|
|
TableName string
|
|
Columns []ColumnData
|
|
}
|
|
|
|
// ColumnData represents column information
|
|
type ColumnData struct {
|
|
Name string
|
|
Type string
|
|
Default string
|
|
NotNull bool
|
|
}
|
|
|
|
// AddColumnData contains data for add column template
|
|
type AddColumnData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
ColumnType string
|
|
Default string
|
|
NotNull bool
|
|
}
|
|
|
|
// AlterColumnTypeData contains data for alter column type template
|
|
type AlterColumnTypeData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
NewType string
|
|
UsingExpr string
|
|
}
|
|
|
|
type AlterColumnTypeWithCheckData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
NewType string
|
|
EquivalentTypes string
|
|
UsingExpr string
|
|
}
|
|
|
|
// AlterColumnDefaultData contains data for alter column default template
|
|
type AlterColumnDefaultData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
SetDefault bool
|
|
DefaultValue string
|
|
}
|
|
|
|
// CreatePrimaryKeyData contains data for create primary key template
|
|
type CreatePrimaryKeyData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
Columns string
|
|
}
|
|
|
|
// CreateIndexData contains data for create index template
|
|
type CreateIndexData struct {
|
|
SchemaName string
|
|
TableName string
|
|
IndexName string
|
|
IndexType string
|
|
Columns string
|
|
Unique bool
|
|
}
|
|
|
|
// CreateForeignKeyData contains data for create foreign key template
|
|
type CreateForeignKeyData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
SourceColumns string
|
|
TargetSchema string
|
|
TargetTable string
|
|
TargetColumns string
|
|
OnDelete string
|
|
OnUpdate string
|
|
}
|
|
|
|
// DropConstraintData contains data for drop constraint template
|
|
type DropConstraintData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
}
|
|
|
|
// DropIndexData contains data for drop index template
|
|
type DropIndexData struct {
|
|
SchemaName string
|
|
IndexName string
|
|
}
|
|
|
|
// CommentTableData contains data for table comment template
|
|
type CommentTableData struct {
|
|
SchemaName string
|
|
TableName string
|
|
Comment string
|
|
}
|
|
|
|
// CommentColumnData contains data for column comment template
|
|
type CommentColumnData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
Comment string
|
|
}
|
|
|
|
// AuditTablesData contains data for audit tables template
|
|
type AuditTablesData struct {
|
|
AuditSchema string
|
|
}
|
|
|
|
// AuditColumnData represents a column in audit template
|
|
type AuditColumnData struct {
|
|
Name string
|
|
OldValue string
|
|
NewValue string
|
|
}
|
|
|
|
// AuditFunctionData contains data for audit function template
|
|
type AuditFunctionData struct {
|
|
SchemaName string
|
|
FunctionName string
|
|
TableName string
|
|
TablePrefix string
|
|
PrimaryKey string
|
|
AuditSchema string
|
|
UserFunction string
|
|
AuditInsert bool
|
|
AuditUpdate bool
|
|
AuditDelete bool
|
|
UpdateCondition string
|
|
UpdateColumns []AuditColumnData
|
|
DeleteColumns []AuditColumnData
|
|
}
|
|
|
|
// AuditTriggerData contains data for audit trigger template
|
|
type AuditTriggerData struct {
|
|
SchemaName string
|
|
TableName string
|
|
TriggerName string
|
|
FunctionName string
|
|
Events string
|
|
}
|
|
|
|
// CreateUniqueConstraintData contains data for create unique constraint template
|
|
type CreateUniqueConstraintData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
Columns string
|
|
}
|
|
|
|
// CreateCheckConstraintData contains data for create check constraint template
|
|
type CreateCheckConstraintData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
Expression string
|
|
}
|
|
|
|
// CreateForeignKeyWithCheckData contains data for create foreign key with existence check template
|
|
type CreateForeignKeyWithCheckData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
SourceColumns string
|
|
TargetSchema string
|
|
TargetTable string
|
|
TargetColumns string
|
|
OnDelete string
|
|
OnUpdate string
|
|
Deferrable bool
|
|
}
|
|
|
|
// SetSequenceValueData contains data for set sequence value template
|
|
type SetSequenceValueData struct {
|
|
SchemaName string
|
|
TableName string
|
|
SequenceName string
|
|
ColumnName string
|
|
}
|
|
|
|
// CreateSequenceData contains data for create sequence template
|
|
type CreateSequenceData struct {
|
|
SchemaName string
|
|
SequenceName string
|
|
Increment int
|
|
MinValue int64
|
|
MaxValue int64
|
|
StartValue int64
|
|
CacheSize int
|
|
}
|
|
|
|
// AddColumnWithCheckData contains data for add column with existence check template
|
|
type AddColumnWithCheckData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ColumnName string
|
|
ColumnDefinition string
|
|
}
|
|
|
|
// CreatePrimaryKeyWithAutoGenCheckData contains data for primary key with auto-generated key check template
|
|
type CreatePrimaryKeyWithAutoGenCheckData struct {
|
|
SchemaName string
|
|
TableName string
|
|
ConstraintName string
|
|
AutoGenNames string // Comma-separated list of names like "'name1', 'name2'"
|
|
Columns string
|
|
ColumnNames string // Comma-separated list of quoted column names like "'id', 'tenant_id'"
|
|
}
|
|
|
|
// Execute methods for each template
|
|
|
|
// ExecuteCreateTable executes the create table template
|
|
func (te *TemplateExecutor) ExecuteCreateTable(data CreateTableData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_table.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_table template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAddColumn executes the add column template
|
|
func (te *TemplateExecutor) ExecuteAddColumn(data AddColumnData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "add_column.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute add_column template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAlterColumnType executes the alter column type template
|
|
func (te *TemplateExecutor) ExecuteAlterColumnType(data AlterColumnTypeData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "alter_column_type.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute alter_column_type template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func (te *TemplateExecutor) ExecuteAlterColumnTypeWithCheck(data AlterColumnTypeWithCheckData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "alter_column_type_with_check.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute alter_column_type_with_check template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAlterColumnDefault executes the alter column default template
|
|
func (te *TemplateExecutor) ExecuteAlterColumnDefault(data AlterColumnDefaultData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "alter_column_default.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute alter_column_default template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreatePrimaryKey executes the create primary key template
|
|
func (te *TemplateExecutor) ExecuteCreatePrimaryKey(data CreatePrimaryKeyData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_primary_key.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_primary_key template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateIndex executes the create index template
|
|
func (te *TemplateExecutor) ExecuteCreateIndex(data CreateIndexData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_index.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_index template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateForeignKey executes the create foreign key template
|
|
func (te *TemplateExecutor) ExecuteCreateForeignKey(data CreateForeignKeyData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_foreign_key.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_foreign_key template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteDropConstraint executes the drop constraint template
|
|
func (te *TemplateExecutor) ExecuteDropConstraint(data DropConstraintData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "drop_constraint.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute drop_constraint template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteDropIndex executes the drop index template
|
|
func (te *TemplateExecutor) ExecuteDropIndex(data DropIndexData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "drop_index.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute drop_index template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCommentTable executes the table comment template
|
|
func (te *TemplateExecutor) ExecuteCommentTable(data CommentTableData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "comment_table.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute comment_table template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCommentColumn executes the column comment template
|
|
func (te *TemplateExecutor) ExecuteCommentColumn(data CommentColumnData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "comment_column.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute comment_column template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAuditTables executes the audit tables template
|
|
func (te *TemplateExecutor) ExecuteAuditTables(data AuditTablesData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "audit_tables.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute audit_tables template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAuditFunction executes the audit function template
|
|
func (te *TemplateExecutor) ExecuteAuditFunction(data AuditFunctionData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "audit_function.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute audit_function template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAuditTrigger executes the audit trigger template
|
|
func (te *TemplateExecutor) ExecuteAuditTrigger(data AuditTriggerData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "audit_trigger.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute audit_trigger template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateUniqueConstraint executes the create unique constraint template
|
|
func (te *TemplateExecutor) ExecuteCreateUniqueConstraint(data CreateUniqueConstraintData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_unique_constraint.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_unique_constraint template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateCheckConstraint executes the create check constraint template
|
|
func (te *TemplateExecutor) ExecuteCreateCheckConstraint(data CreateCheckConstraintData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_check_constraint.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_check_constraint template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateForeignKeyWithCheck executes the create foreign key with check template
|
|
func (te *TemplateExecutor) ExecuteCreateForeignKeyWithCheck(data CreateForeignKeyWithCheckData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_foreign_key_with_check.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_foreign_key_with_check template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteSetSequenceValue executes the set sequence value template
|
|
func (te *TemplateExecutor) ExecuteSetSequenceValue(data SetSequenceValueData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "set_sequence_value.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute set_sequence_value template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreateSequence executes the create sequence template
|
|
func (te *TemplateExecutor) ExecuteCreateSequence(data CreateSequenceData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_sequence.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_sequence template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteAddColumnWithCheck executes the add column with check template
|
|
func (te *TemplateExecutor) ExecuteAddColumnWithCheck(data AddColumnWithCheckData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "add_column_with_check.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute add_column_with_check template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ExecuteCreatePrimaryKeyWithAutoGenCheck executes the create primary key with auto-generated key check template
|
|
func (te *TemplateExecutor) ExecuteCreatePrimaryKeyWithAutoGenCheck(data CreatePrimaryKeyWithAutoGenCheckData) (string, error) {
|
|
var buf bytes.Buffer
|
|
err := te.templates.ExecuteTemplate(&buf, "create_primary_key_with_autogen_check.tmpl", data)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to execute create_primary_key_with_autogen_check template: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// Helper functions to build template data from models
|
|
|
|
// BuildCreateTableData builds CreateTableData from a models.Table
|
|
func BuildCreateTableData(schemaName string, table *models.Table) CreateTableData {
|
|
columns := make([]ColumnData, 0, len(table.Columns))
|
|
|
|
// Get sorted columns
|
|
sortedCols := getSortedColumns(table.Columns)
|
|
for _, col := range sortedCols {
|
|
colData := ColumnData{
|
|
Name: col.Name,
|
|
Type: col.Type,
|
|
NotNull: col.NotNull,
|
|
}
|
|
if col.Default != nil {
|
|
if value, ok := col.Default.(string); ok {
|
|
colData.Default = writers.QuoteDefaultValue(value, col.Type)
|
|
} else {
|
|
colData.Default = fmt.Sprintf("%v", col.Default)
|
|
}
|
|
}
|
|
columns = append(columns, colData)
|
|
}
|
|
|
|
return CreateTableData{
|
|
SchemaName: schemaName,
|
|
TableName: table.Name,
|
|
Columns: columns,
|
|
}
|
|
}
|
|
|
|
// BuildAuditFunctionData builds AuditFunctionData from table and config
|
|
func BuildAuditFunctionData(
|
|
schemaName string,
|
|
table *models.Table,
|
|
pk *models.Column,
|
|
config *TableAuditConfig,
|
|
auditSchema string,
|
|
userFunction string,
|
|
) AuditFunctionData {
|
|
funcName := fmt.Sprintf("tf_audit_%s", table.Name)
|
|
|
|
// Build list of audited columns
|
|
auditedColumns := make([]*models.Column, 0)
|
|
for _, col := range sortColumns(table.Columns) {
|
|
if col.Name == pk.Name {
|
|
continue
|
|
}
|
|
|
|
excluded := false
|
|
for _, excl := range config.ExcludedColumns {
|
|
if strings.EqualFold(col.Name, excl) {
|
|
excluded = true
|
|
break
|
|
}
|
|
}
|
|
if excluded {
|
|
continue
|
|
}
|
|
|
|
auditedColumns = append(auditedColumns, col)
|
|
}
|
|
|
|
// Build update condition
|
|
updateComparisons := make([]string, 0)
|
|
for _, col := range auditedColumns {
|
|
updateComparisons = append(updateComparisons,
|
|
fmt.Sprintf("old.%s IS DISTINCT FROM new.%s", col.Name, col.Name))
|
|
}
|
|
updateCondition := strings.Join(updateComparisons, " OR ")
|
|
|
|
// Build update columns data
|
|
updateColumns := make([]AuditColumnData, 0)
|
|
for _, col := range auditedColumns {
|
|
isEncrypted := false
|
|
for _, enc := range config.EncryptedColumns {
|
|
if strings.EqualFold(col.Name, enc) {
|
|
isEncrypted = true
|
|
break
|
|
}
|
|
}
|
|
|
|
oldValue := fmt.Sprintf("old.%s::text", col.Name)
|
|
newValue := fmt.Sprintf("new.%s::text", col.Name)
|
|
|
|
if isEncrypted {
|
|
oldValue = "'****************'"
|
|
newValue = "'****************'"
|
|
}
|
|
|
|
updateColumns = append(updateColumns, AuditColumnData{
|
|
Name: col.Name,
|
|
OldValue: oldValue,
|
|
NewValue: newValue,
|
|
})
|
|
}
|
|
|
|
// Build delete columns data (same as update but only old values)
|
|
deleteColumns := make([]AuditColumnData, 0)
|
|
for _, col := range auditedColumns {
|
|
isEncrypted := false
|
|
for _, enc := range config.EncryptedColumns {
|
|
if strings.EqualFold(col.Name, enc) {
|
|
isEncrypted = true
|
|
break
|
|
}
|
|
}
|
|
|
|
oldValue := fmt.Sprintf("old.%s::text", col.Name)
|
|
if isEncrypted {
|
|
oldValue = "'****************'"
|
|
}
|
|
|
|
deleteColumns = append(deleteColumns, AuditColumnData{
|
|
Name: col.Name,
|
|
OldValue: oldValue,
|
|
})
|
|
}
|
|
|
|
tablePrefix := "NULL"
|
|
if config.TablePrefix != "" {
|
|
tablePrefix = fmt.Sprintf("'%s'", config.TablePrefix)
|
|
}
|
|
|
|
return AuditFunctionData{
|
|
SchemaName: schemaName,
|
|
FunctionName: funcName,
|
|
TableName: table.Name,
|
|
TablePrefix: tablePrefix,
|
|
PrimaryKey: pk.Name,
|
|
AuditSchema: auditSchema,
|
|
UserFunction: userFunction,
|
|
AuditInsert: config.AuditInsert,
|
|
AuditUpdate: config.AuditUpdate,
|
|
AuditDelete: config.AuditDelete,
|
|
UpdateCondition: updateCondition,
|
|
UpdateColumns: updateColumns,
|
|
DeleteColumns: deleteColumns,
|
|
}
|
|
}
|