X3K56A54LNNXODOH6MK22NTSEUQ54BUEZ3EL6ANKXYNL4RROL73QC NAZQZRYQTXWVE2VFY65ONSD6O3EUMNRHARCDVH2D2HKM3YH4RGUAC IFVRAERTCCDICNTYTG3TX2WASB6RXQQEJWWXQMQZJSQDQ3HLE5OQC DORZF5HSV672ZP5HUDYB3J6TBH5O2LMXJE4HPSE7H5SOGZQBDCXQC 7NS27QXZMVTZBK4VPMYL5IKGSTTAWR6NDG5SOVITNX44VNIRZPMAC OGLLBQQYE5KICDMI6EX7ZI4TZT5RB7UFHH7O2DUOZ44QQXVL5YAAC OCRETPZZPDCUSOPYRH5MVRATJ37TRFGVSIMOI4IV755HFXXOVHEAC package toolsimport ("testing")func TestValidateShortID(t *testing.T) {tests := []struct {name stringid stringfieldName stringwantErr bool}{{"valid 12-char ID", "abc123XYZ789", "test_id", false},{"valid with underscore", "abc_123_XYZ_", "test_id", false},{"valid with dash", "abc-123-XYZ-", "test_id", false},{"empty string", "", "test_id", true},{"too short", "abc123", "test_id", true},{"too long", "abc123XYZ789toolong", "test_id", true},{"invalid chars", "abc@123#XYZ$", "test_id", true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateShortID(tt.id, tt.fieldName)if (err != nil) != tt.wantErr {t.Errorf("ValidateShortID() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateLongID(t *testing.T) {tests := []struct {name stringid stringfieldName stringwantErr bool}{{"valid 21-char ID", "abc123XYZ789abc123XYZ", "test_id", false}, // exactly 21 chars{"valid with underscore", "abc_123_XYZ_789_abc_X", "test_id", false}, // exactly 21 chars{"empty string", "", "test_id", true},{"too short", "abc123XYZ789", "test_id", true}, // 12 chars{"too long", "abc123XYZ789abc123XYZ789ex", "test_id", true}, // 24 chars{"invalid chars", "abc@123#XYZ$789%abc^XY", "test_id", true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateLongID(tt.id, tt.fieldName)if (err != nil) != tt.wantErr {t.Errorf("ValidateLongID() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateStringLength(t *testing.T) {tests := []struct {name stringvalue stringfield stringmaxLen intwantErr bool}{{"within limit", "hello", "test", 10, false},{"at limit", "1234567890", "test", 10, false},{"empty string", "", "test", 10, false},{"over limit", "12345678901", "test", 10, true},{"zero max", "a", "test", 0, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateStringLength(tt.value, tt.field, tt.maxLen)if (err != nil) != tt.wantErr {t.Errorf("ValidateStringLength() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateRange(t *testing.T) {t.Run("int range", func(t *testing.T) {tests := []struct {name stringvalue intmin intmax intwantErr bool}{{"within range", 50, 0, 100, false},{"at min", 0, 0, 100, false},{"at max", 100, 0, 100, false},{"below min", -1, 0, 100, true},{"above max", 101, 0, 100, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateRange(tt.value, "test", tt.min, tt.max)if (err != nil) != tt.wantErr {t.Errorf("ValidateRange() error = %v, wantErr %v", err, tt.wantErr)}})}})t.Run("float64 range", func(t *testing.T) {tests := []struct {name stringvalue float64min float64max float64wantErr bool}{{"within range", 45.5, -90.0, 90.0, false},{"at min", -90.0, -90.0, 90.0, false},{"at max", 90.0, -90.0, 90.0, false},{"below min", -90.1, -90.0, 90.0, true},{"above max", 90.1, -90.0, 90.0, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateRange(tt.value, "test", tt.min, tt.max)if (err != nil) != tt.wantErr {t.Errorf("ValidateRange() error = %v, wantErr %v", err, tt.wantErr)}})}})}func TestValidatePositive(t *testing.T) {tests := []struct {name stringvalue intwantErr bool}{{"positive", 1, false},{"large positive", 1000000, false},{"zero", 0, true},{"negative", -1, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidatePositive(tt.value, "test")if (err != nil) != tt.wantErr {t.Errorf("ValidatePositive() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateSampleRate(t *testing.T) {tests := []struct {name stringrate intwantErr bool}{{"valid low", 1000, false},{"valid typical", 48000, false},{"valid high", 250000, false},{"valid max", 500000, false},{"too low", 999, true},{"too high", 500001, true},{"zero", 0, true},{"negative", -1000, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateSampleRate(tt.rate)if (err != nil) != tt.wantErr {t.Errorf("ValidateSampleRate() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateHash(t *testing.T) {tests := []struct {name stringhash stringwantErr bool}{{"valid hash", "0123456789abcdef", false},{"valid all letters", "abcdefabcdefabcd", false},{"valid all numbers", "1234567890123456", false},{"too short", "0123456789abcde", true},{"too long", "0123456789abcdef0", true},{"invalid chars", "ghijklmnopqrstuv", true},{"uppercase", "ABCDEF1234567890", true},{"mixed case", "aBcDeF1234567890", true},{"empty", "", true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateHash(tt.hash, "test_hash")if (err != nil) != tt.wantErr {t.Errorf("ValidateHash() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateFrequencyRange(t *testing.T) {low := func(v float64) *float64 { return &v }high := func(v float64) *float64 { return &v }tests := []struct {name stringfreqLow *float64freqHigh *float64wantErr bool}{{"both nil", nil, nil, false},{"valid range", low(100.0), high(1000.0), false},{"valid low only", low(100.0), nil, false},{"valid high only", nil, high(1000.0), false},{"at bounds", low(0.0), high(299999.0), false},{"low negative", low(-1.0), high(1000.0), true},{"high too high", low(100.0), high(300000.0), true},{"low equals high", low(500.0), high(500.0), true},{"low greater than high", low(1000.0), high(100.0), true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateFrequencyRange(tt.freqLow, tt.freqHigh)if (err != nil) != tt.wantErr {t.Errorf("ValidateFrequencyRange() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateCertainty(t *testing.T) {val := func(v float64) *float64 { return &v }tests := []struct {name stringcertainty *float64wantErr bool}{{"nil", nil, false},{"zero", val(0.0), false},{"mid range", val(50.0), false},{"100", val(100.0), false},{"negative", val(-0.1), true},{"over 100", val(100.1), true},{"much over", val(200.0), true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateCertainty(tt.certainty)if (err != nil) != tt.wantErr {t.Errorf("ValidateCertainty() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateTimezone(t *testing.T) {tests := []struct {name stringtz stringwantErr bool}{{"valid Auckland", "Pacific/Auckland", false},{"valid UTC", "UTC", false},{"valid America/New_York", "America/New_York", false},{"valid Europe/London", "Europe/London", false},{"invalid", "Invalid/Timezone", true},{"garbage", "not-a-timezone", true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateTimezone(tt.tz)if (err != nil) != tt.wantErr {t.Errorf("ValidateTimezone() error = %v, wantErr %v", err, tt.wantErr)}})}}func TestValidateNonNegative(t *testing.T) {tests := []struct {name stringvalue intwantErr bool}{{"positive", 1, false},{"zero", 0, false},{"negative", -1, true},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {err := ValidateNonNegative(tt.value, "test")if (err != nil) != tt.wantErr {t.Errorf("ValidateNonNegative() error = %v, wantErr %v", err, tt.wantErr)}})}}
package toolsimport ("database/sql""fmt""regexp""time")// ID length constants matching nanoid generationconst (ShortIDLen = 12 // dataset, location, cluster, pattern, species, filter, call_typeLongIDLen = 21 // file, selection, label, label_subtype)// Sample rate reasonable bounds for audio recordingconst (MinSampleRate = 1000 // 1 kHz - below this is unlikely to be real audioMaxSampleRate = 500000 // 500 kHz - well above bat detectors (~250kHz))// Max string lengths from schemaconst (MaxNameLen = 140 // location.name, cluster.nameMaxDatasetNameLen = 255 // dataset.nameMaxDescriptionLen = 255 // all description fieldsMaxPathLen = 255 // cluster.pathMaxFileNameLen = 255 // file.file_nameMaxTimezoneLen = 40 // location.timezone_idHashLen = 16 // xxh64_hash)// ID format regex - alphanumeric characters (nanoid uses A-Za-z0-9_)var shortIDRegex = regexp.MustCompile(`^[A-Za-z0-9_-]{12}$`)var longIDRegex = regexp.MustCompile(`^[A-Za-z0-9_-]{21}$`)var hashRegex = regexp.MustCompile(`^[0-9a-f]{16}$`)// ValidateShortID validates 12-character nanoid formatfunc ValidateShortID(id, fieldName string) error {if id == "" {return fmt.Errorf("%s cannot be empty", fieldName)}if len(id) != ShortIDLen {return fmt.Errorf("%s must be exactly %d characters (got %d)", fieldName, ShortIDLen, len(id))}if !shortIDRegex.MatchString(id) {return fmt.Errorf("%s has invalid format (expected alphanumeric nanoid)", fieldName)}return nil}// ValidateLongID validates 21-character nanoid formatfunc ValidateLongID(id, fieldName string) error {if id == "" {return fmt.Errorf("%s cannot be empty", fieldName)}if len(id) != LongIDLen {return fmt.Errorf("%s must be exactly %d characters (got %d)", fieldName, LongIDLen, len(id))}if !longIDRegex.MatchString(id) {return fmt.Errorf("%s has invalid format (expected alphanumeric nanoid)", fieldName)}return nil}// ValidateOptionalShortID validates short ID if provided (non-empty)func ValidateOptionalShortID(id *string, fieldName string) error {if id == nil || *id == "" {return nil}return ValidateShortID(*id, fieldName)}// ValidateOptionalLongID validates long ID if provided (non-empty)func ValidateOptionalLongID(id *string, fieldName string) error {if id == nil || *id == "" {return nil}return ValidateLongID(*id, fieldName)}// ValidateStringLength validates string length constraintfunc ValidateStringLength(value, fieldName string, maxLen int) error {if len(value) > maxLen {return fmt.Errorf("%s must be %d characters or less (got %d)", fieldName, maxLen, len(value))}return nil}// ValidateOptionalStringLength validates string length if providedfunc ValidateOptionalStringLength(value *string, fieldName string, maxLen int) error {if value == nil || *value == "" {return nil}return ValidateStringLength(*value, fieldName, maxLen)}// ValidateRange validates numeric range constraint (inclusive)func ValidateRange[T int | float64](value T, fieldName string, min, max T) error {if value < min || value > max {return fmt.Errorf("%s must be between %v and %v (got %v)", fieldName, min, max, value)}return nil}// ValidatePositive validates positive number (> 0)func ValidatePositive[T int | float64](value T, fieldName string) error {if value <= 0 {return fmt.Errorf("%s must be positive (got %v)", fieldName, value)}return nil}// ValidateNonNegative validates non-negative number (>= 0)func ValidateNonNegative[T int | float64](value T, fieldName string) error {if value < 0 {return fmt.Errorf("%s must be non-negative (got %v)", fieldName, value)}return nil}// ValidateSampleRate validates audio sample rate is in reasonable rangefunc ValidateSampleRate(rate int) error {return ValidateRange(rate, "sample_rate", MinSampleRate, MaxSampleRate)}// ValidateTimezone validates IANA timezone IDfunc ValidateTimezone(tzID string) error {if _, err := time.LoadLocation(tzID); err != nil {return fmt.Errorf("invalid timezone_id '%s': %w", tzID, err)}return nil}// ValidateHash validates XXH64 hash format (16 hex characters)func ValidateHash(hash, fieldName string) error {if len(hash) != HashLen {return fmt.Errorf("%s must be exactly %d characters (got %d)", fieldName, HashLen, len(hash))}if !hashRegex.MatchString(hash) {return fmt.Errorf("%s has invalid format (expected 16 hex characters)", fieldName)}return nil}// ValidateFrequencyRange validates frequency bounds for selectionsfunc ValidateFrequencyRange(freqLow, freqHigh *float64) error {if freqLow == nil && freqHigh == nil {return nil}// Schema limit is 300000 Hzconst maxFreq = 300000.0if freqLow != nil {if *freqLow < 0 {return fmt.Errorf("freq_low must be non-negative (got %v)", *freqLow)}if *freqLow >= maxFreq {return fmt.Errorf("freq_low must be less than %v Hz (got %v)", maxFreq, *freqLow)}}if freqHigh != nil {if *freqHigh < 0 {return fmt.Errorf("freq_high must be non-negative (got %v)", *freqHigh)}if *freqHigh >= maxFreq {return fmt.Errorf("freq_high must be less than %v Hz (got %v)", maxFreq, *freqHigh)}}// If both provided, low must be less than highif freqLow != nil && freqHigh != nil && *freqLow >= *freqHigh {return fmt.Errorf("freq_low (%v) must be less than freq_high (%v)", *freqLow, *freqHigh)}return nil}// ValidateCertainty validates certainty percentage (0-100)func ValidateCertainty(certainty *float64) error {if certainty == nil {return nil}if *certainty < 0 || *certainty > 100 {return fmt.Errorf("certainty must be between 0 and 100 (got %v)", *certainty)}return nil}// EntityExists checks if an entity exists in the databasefunc EntityExists(db *sql.DB, table, id string) (bool, error) {var exists boolquery := fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM %s WHERE id = ?)", table)err := db.QueryRow(query, id).Scan(&exists)return exists, err}// EntityExistsAndActive checks if an entity exists and is activefunc EntityExistsAndActive(db *sql.DB, table, id string) (bool, error) {var exists boolquery := fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM %s WHERE id = ? AND active = true)", table)err := db.QueryRow(query, id).Scan(&exists)return exists, err}// GetEntityActiveStatus returns whether an entity is active (and exists)// Returns: (exists, active, error)func GetEntityActiveStatus(db *sql.DB, table, id string) (bool, bool, error) {var exists boolvar active boolquery := fmt.Sprintf("SELECT EXISTS(SELECT 1 FROM %s WHERE id = ?), COALESCE((SELECT active FROM %s WHERE id = ?), false)", table, table)err := db.QueryRow(query, id, id).Scan(&exists, &active)return exists, active, err}
if input.RecordSeconds != nil && *input.RecordSeconds <= 0 {return output, fmt.Errorf("record_seconds must be greater than 0: %d", *input.RecordSeconds)
if input.RecordSeconds != nil {if err := ValidatePositive(*input.RecordSeconds, "record_seconds"); err != nil {return output, err}
if input.SleepSeconds != nil && *input.SleepSeconds < 0 {return output, fmt.Errorf("sleep_seconds must be greater than or equal to 0: %d", *input.SleepSeconds)
if input.SleepSeconds != nil {if err := ValidateNonNegative(*input.SleepSeconds, "sleep_seconds"); err != nil {return output, err}
// Verify pattern existsvar exists boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ?)", patternID).Scan(&exists)
// Verify pattern exists and check active statusvar exists, active boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ?), COALESCE((SELECT active FROM cyclic_recording_pattern WHERE id = ?), false)",patternID, patternID,).Scan(&exists, &active)
if input.Description != nil && len(*input.Description) > 255 {return fmt.Errorf("description must be 255 characters or less (got %d)", len(*input.Description))
if err := ValidateOptionalStringLength(input.Description, "description", MaxDescriptionLen); err != nil {return err
if input.Latitude != nil && (*input.Latitude < -90 || *input.Latitude > 90) {return fmt.Errorf("latitude must be between -90 and 90 (got %f)", *input.Latitude)
if input.Latitude != nil {if err := ValidateRange(*input.Latitude, "latitude", -90.0, 90.0); err != nil {return err}
if input.Longitude != nil && (*input.Longitude < -180 || *input.Longitude > 180) {return fmt.Errorf("longitude must be between -180 and 180 (got %f)", *input.Longitude)
if input.Longitude != nil {if err := ValidateRange(*input.Longitude, "longitude", -180.0, 180.0); err != nil {return err}
return output, fmt.Errorf("dataset '%s' (ID: %s) is not active", datasetName, *input.DatasetID)
return output, fmt.Errorf("dataset (ID: %s) is not active", *input.DatasetID)}// Check for existing location with same name in dataset (UNIQUE constraint)var existingID stringerr = tx.QueryRowContext(ctx,"SELECT id FROM location WHERE dataset_id = ? AND name = ? AND active = true",*input.DatasetID, *input.Name,).Scan(&existingID)if err == nil {// Location with this name already exists in dataset - return existing (consistent duplicate handling)var location db.Locationerr = tx.QueryRowContext(ctx,"SELECT id, dataset_id, name, latitude, longitude, description, created_at, last_modified, active, timezone_id FROM location WHERE id = ?",existingID,).Scan(&location.ID, &location.DatasetID, &location.Name, &location.Latitude, &location.Longitude,&location.Description, &location.CreatedAt, &location.LastModified, &location.Active, &location.TimezoneID)if err != nil {return output, fmt.Errorf("failed to fetch existing location: %w", err)}if err = tx.Commit(); err != nil {return output, fmt.Errorf("failed to commit transaction: %w", err)}output.Location = locationoutput.Message = fmt.Sprintf("Location '%s' already exists in dataset (ID: %s) - returning existing location", location.Name, location.ID)return output, nil
output.Message = fmt.Sprintf("Successfully created location '%s' with ID %s in dataset '%s' (%.6f, %.6f, %s)",location.Name, location.ID, datasetName, location.Latitude, location.Longitude, location.TimezoneID)
output.Message = fmt.Sprintf("Successfully created location '%s' with ID %s (%.6f, %.6f, %s)",location.Name, location.ID, location.Latitude, location.Longitude, location.TimezoneID)
// Verify location existsvar exists boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM location WHERE id = ?)", locationID).Scan(&exists)
// Verify location exists and check active statusvar exists, active boolvar currentDatasetID stringerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM location WHERE id = ?), COALESCE((SELECT active FROM location WHERE id = ?), false), COALESCE((SELECT dataset_id FROM location WHERE id = ?), '')",locationID, locationID, locationID,).Scan(&exists, &active, ¤tDatasetID)
var datasetExists boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?)", *input.DatasetID).Scan(&datasetExists)
var datasetExists, datasetActive boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false)",*input.DatasetID, *input.DatasetID,).Scan(&datasetExists, &datasetActive)
// Validate ID formats first (fast fail before DB queries)if err := ValidateShortID(input.DatasetID, "dataset_id"); err != nil {return err}if err := ValidateShortID(input.LocationID, "location_id"); err != nil {return err}if err := ValidateShortID(input.ClusterID, "cluster_id"); err != nil {return err}
Type *string `json:"type,omitempty" jsonschema:"Dataset type: 'organise'/'test'/'train' (defaults to 'organise' on create)"`
Type *string `json:"type,omitempty" jsonschema:"Dataset type: 'structured'/'unstructured'/'test'/'train' (defaults to 'structured' on create)"`
if len(*input.Name) > 255 {return output, fmt.Errorf("name must be 255 characters or less (got %d)", len(*input.Name))
if err := ValidateStringLength(*input.Name, "name", MaxDatasetNameLen); err != nil {return output, err
if input.Description != nil && len(*input.Description) > 255 {return output, fmt.Errorf("description must be 255 characters or less (got %d)", len(*input.Description))
if err := ValidateOptionalStringLength(input.Description, "description", MaxDescriptionLen); err != nil {return output, err
// Check for existing dataset with same name (UNIQUE constraint)var existingID stringerr = tx.QueryRowContext(ctx,"SELECT id FROM dataset WHERE name = ? AND active = true",*input.Name,).Scan(&existingID)if err == nil {// Dataset with this name already exists - return existing (consistent duplicate handling)var dataset db.Dataseterr = tx.QueryRowContext(ctx,"SELECT id, name, description, created_at, last_modified, active, type FROM dataset WHERE id = ?",existingID,).Scan(&dataset.ID, &dataset.Name, &dataset.Description, &dataset.CreatedAt, &dataset.LastModified, &dataset.Active, &dataset.Type)if err != nil {return output, fmt.Errorf("failed to fetch existing dataset: %w", err)}if err = tx.Commit(); err != nil {return output, fmt.Errorf("failed to commit transaction: %w", err)}output.Dataset = datasetoutput.Message = fmt.Sprintf("Dataset with name '%s' already exists (ID: %s) - returning existing dataset", dataset.Name, dataset.ID)return output, nil}
if input.Name != nil && len(*input.Name) > 255 {return output, fmt.Errorf("name must be 255 characters or less (got %d)", len(*input.Name))
if err := ValidateOptionalStringLength(input.Name, "name", MaxDatasetNameLen); err != nil {return output, err
if input.Description != nil && len(*input.Description) > 255 {return output, fmt.Errorf("description must be 255 characters or less (got %d)", len(*input.Description))
if err := ValidateOptionalStringLength(input.Description, "description", MaxDescriptionLen); err != nil {return output, err
// Verify dataset existsvar exists boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?)", datasetID).Scan(&exists)
// Verify dataset exists and check active statusvar exists, active boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false)", datasetID, datasetID).Scan(&exists, &active)
if input.Name != nil && len(*input.Name) > 140 {return fmt.Errorf("name must be 140 characters or less (got %d)", len(*input.Name))
if err := ValidateOptionalStringLength(input.Name, "name", MaxNameLen); err != nil {return err}if err := ValidateOptionalStringLength(input.Description, "description", MaxDescriptionLen); err != nil {return err
if input.Description != nil && len(*input.Description) > 255 {return fmt.Errorf("description must be 255 characters or less (got %d)", len(*input.Description))
if err := ValidateOptionalStringLength(input.Path, "path", MaxPathLen); err != nil {return err
if input.SampleRate != nil && *input.SampleRate <= 0 {return fmt.Errorf("sample_rate must be positive (got %d)", *input.SampleRate)
if input.SampleRate != nil {if err := ValidatePositive(*input.SampleRate, "sample_rate"); err != nil {return err}// Also check reasonable boundsif err := ValidateSampleRate(*input.SampleRate); err != nil {return err}
"SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), active, name FROM dataset WHERE id = ?",*input.DatasetID, *input.DatasetID,
"SELECT EXISTS(SELECT 1 FROM dataset WHERE id = ?), COALESCE((SELECT active FROM dataset WHERE id = ?), false), COALESCE((SELECT name FROM dataset WHERE id = ?), '')",*input.DatasetID, *input.DatasetID, *input.DatasetID,
"SELECT EXISTS(SELECT 1 FROM location WHERE id = ?), active, name, dataset_id FROM location WHERE id = ?",*input.LocationID, *input.LocationID,
"SELECT EXISTS(SELECT 1 FROM location WHERE id = ?), COALESCE((SELECT active FROM location WHERE id = ?), false), COALESCE((SELECT name FROM location WHERE id = ?), ''), COALESCE((SELECT dataset_id FROM location WHERE id = ?), '')",*input.LocationID, *input.LocationID, *input.LocationID, *input.LocationID,
"SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ?), active FROM cyclic_recording_pattern WHERE id = ?",
"SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ?), COALESCE((SELECT active FROM cyclic_recording_pattern WHERE id = ?), false)",
// Check for existing cluster with same name in location (UNIQUE constraint)var existingID stringerr = tx.QueryRowContext(ctx,"SELECT id FROM cluster WHERE location_id = ? AND name = ? AND active = true",*input.LocationID, *input.Name,).Scan(&existingID)if err == nil {// Cluster with this name already exists in location - return existing (consistent duplicate handling)var cluster db.Clustererr = tx.QueryRowContext(ctx,"SELECT id, dataset_id, location_id, name, description, created_at, last_modified, active, cyclic_recording_pattern_id, sample_rate FROM cluster WHERE id = ?",existingID,).Scan(&cluster.ID, &cluster.DatasetID, &cluster.LocationID, &cluster.Name, &cluster.Description,&cluster.CreatedAt, &cluster.LastModified, &cluster.Active, &cluster.CyclicRecordingPatternID, &cluster.SampleRate)if err != nil {return output, fmt.Errorf("failed to fetch existing cluster: %w", err)}if err = tx.Commit(); err != nil {return output, fmt.Errorf("failed to commit transaction: %w", err)}output.Cluster = clusteroutput.Message = fmt.Sprintf("Cluster '%s' already exists in location '%s' (ID: %s) - returning existing cluster", cluster.Name, locationName, cluster.ID)return output, nil}
// Verify cluster existsvar exists boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM cluster WHERE id = ?)", clusterID).Scan(&exists)
// Verify cluster exists and check active statusvar exists, active boolerr = database.QueryRow("SELECT EXISTS(SELECT 1 FROM cluster WHERE id = ?), COALESCE((SELECT active FROM cluster WHERE id = ?), false)",clusterID, clusterID,).Scan(&exists, &active)
"SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ? AND active = true)",trimmedPatternID,).Scan(&patternExists)
"SELECT EXISTS(SELECT 1 FROM cyclic_recording_pattern WHERE id = ?), COALESCE((SELECT active FROM cyclic_recording_pattern WHERE id = ?), false)",trimmedPatternID, trimmedPatternID,).Scan(&patternExists, &patternActive)
return output, fmt.Errorf("cyclic recording pattern not found or not active: %s", trimmedPatternID)
return output, fmt.Errorf("cyclic recording pattern not found: %s", trimmedPatternID)}if !patternActive {return output, fmt.Errorf("cyclic recording pattern '%s' is not active", trimmedPatternID)
### Application-Level Validation**tools/validation.go** provides application-level guardrails for all write operations:**ID Format Validation:**- Short IDs (12 chars): dataset, location, cluster, pattern, species, filter- Long IDs (21 chars): file, selection, label- Validates alphanumeric format (nanoid compatible)
**Numeric Bounds:**- Sample rate: 1,000 - 500,000 Hz (reasonable audio range)- Latitude: -90 to 90 degrees- Longitude: -180 to 180 degrees- Frequency: 0 to 300,000 Hz (for ML selections)- Certainty: 0 to 100 percent**String Length Validation:**- Names: max 140 characters (location, cluster)- Dataset names: max 255 characters- Descriptions: max 255 characters- Paths: max 255 characters- Timezone IDs: max 40 characters**Entity Validation:**- Existence checks before foreign key references- Active status validation (cannot update inactive entities)- Hierarchy consistency (location must belong to dataset, cluster to location)**Duplicate Handling:**- Pattern: Returns existing if same record_s/sleep_s- Dataset: Returns existing if same name- Location: Returns existing if same name in dataset- Cluster: Returns existing if same name in location