142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
package validation
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// ValidationConfig holds configuration for duplicate validation
|
|
type ValidationConfig struct {
|
|
TableName string
|
|
IDColumn string
|
|
StatusColumn string
|
|
DateColumn string
|
|
ActiveStatuses []string
|
|
AdditionalFields map[string]interface{}
|
|
}
|
|
|
|
// DuplicateValidator provides methods for validating duplicate entries
|
|
type DuplicateValidator struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// NewDuplicateValidator creates a new instance of DuplicateValidator
|
|
func NewDuplicateValidator(db *sql.DB) *DuplicateValidator {
|
|
return &DuplicateValidator{db: db}
|
|
}
|
|
|
|
// ValidateDuplicate checks for duplicate entries based on the provided configuration
|
|
func (dv *DuplicateValidator) ValidateDuplicate(ctx context.Context, config ValidationConfig, identifier interface{}) error {
|
|
query := fmt.Sprintf(`
|
|
SELECT COUNT(*)
|
|
FROM %s
|
|
WHERE %s = $1
|
|
AND %s = ANY($2)
|
|
AND DATE(%s) = CURRENT_DATE
|
|
`, config.TableName, config.IDColumn, config.StatusColumn, config.DateColumn)
|
|
|
|
var count int
|
|
err := dv.db.QueryRowContext(ctx, query, identifier, config.ActiveStatuses).Scan(&count)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check duplicate: %w", err)
|
|
}
|
|
|
|
if count > 0 {
|
|
return fmt.Errorf("data with ID %v already exists with active status today", identifier)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ValidateDuplicateWithCustomFields checks for duplicates with additional custom fields
|
|
func (dv *DuplicateValidator) ValidateDuplicateWithCustomFields(ctx context.Context, config ValidationConfig, fields map[string]interface{}) error {
|
|
whereClause := fmt.Sprintf("%s = ANY($1) AND DATE(%s) = CURRENT_DATE", config.StatusColumn, config.DateColumn)
|
|
args := []interface{}{config.ActiveStatuses}
|
|
argIndex := 2
|
|
|
|
// Add additional field conditions
|
|
for fieldName, fieldValue := range config.AdditionalFields {
|
|
whereClause += fmt.Sprintf(" AND %s = $%d", fieldName, argIndex)
|
|
args = append(args, fieldValue)
|
|
argIndex++
|
|
}
|
|
|
|
// Add dynamic fields
|
|
for fieldName, fieldValue := range fields {
|
|
whereClause += fmt.Sprintf(" AND %s = $%d", fieldName, argIndex)
|
|
args = append(args, fieldValue)
|
|
argIndex++
|
|
}
|
|
|
|
query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", config.TableName, whereClause)
|
|
|
|
var count int
|
|
err := dv.db.QueryRowContext(ctx, query, args...).Scan(&count)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check duplicate with custom fields: %w", err)
|
|
}
|
|
|
|
if count > 0 {
|
|
return fmt.Errorf("duplicate entry found with the specified criteria")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ValidateOncePerDay ensures only one submission per day for a given identifier
|
|
func (dv *DuplicateValidator) ValidateOncePerDay(ctx context.Context, tableName, idColumn, dateColumn string, identifier interface{}) error {
|
|
query := fmt.Sprintf(`
|
|
SELECT COUNT(*)
|
|
FROM %s
|
|
WHERE %s = $1
|
|
AND DATE(%s) = CURRENT_DATE
|
|
`, tableName, idColumn, dateColumn)
|
|
|
|
var count int
|
|
err := dv.db.QueryRowContext(ctx, query, identifier).Scan(&count)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check daily submission: %w", err)
|
|
}
|
|
|
|
if count > 0 {
|
|
return fmt.Errorf("only one submission allowed per day for ID %v", identifier)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetLastSubmissionTime returns the last submission time for a given identifier
|
|
func (dv *DuplicateValidator) GetLastSubmissionTime(ctx context.Context, tableName, idColumn, dateColumn string, identifier interface{}) (*time.Time, error) {
|
|
query := fmt.Sprintf(`
|
|
SELECT %s
|
|
FROM %s
|
|
WHERE %s = $1
|
|
ORDER BY %s DESC
|
|
LIMIT 1
|
|
`, dateColumn, tableName, idColumn, dateColumn)
|
|
|
|
var lastTime time.Time
|
|
err := dv.db.QueryRowContext(ctx, query, identifier).Scan(&lastTime)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil // No previous submission
|
|
}
|
|
return nil, fmt.Errorf("failed to get last submission time: %w", err)
|
|
}
|
|
|
|
return &lastTime, nil
|
|
}
|
|
|
|
// DefaultRetribusiConfig returns default configuration for retribusi validation
|
|
func DefaultRetribusiConfig() ValidationConfig {
|
|
return ValidationConfig{
|
|
TableName: "data_retribusi",
|
|
IDColumn: "id",
|
|
StatusColumn: "status",
|
|
DateColumn: "date_created",
|
|
ActiveStatuses: []string{"active", "draft"},
|
|
}
|
|
}
|