Skip to content

Commit 6651878

Browse files
authored
fix: align persistence layer with instrument_code/dimension schema changes (#1218)
- Remove overdraft_limit and overdraft_rate from Save() update map as overdraft is now product-type behavior, not mutable domain state - Fix test DDL table name from "accounts" (plural) to "account" (singular) to match CurrentAccountEntity.TableName(); tests were silently passing against the public schema's AutoMigrate table instead of the tenant schema - Add product_type_code and product_type_version columns to test DDL to match current schema after 20260220000001 migration - Remove stale balance/available_balance/balance_updated_at columns from test DDL to match 20260108000001_remove_balance_columns migration - Add TestSave_InstrumentCodeAndDimensionRoundTrip and TestSave_InstrumentCodePersistedOnEntity to verify instrument_code and dimension columns are correctly persisted and retrieved Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent 40949e4 commit 6651878

3 files changed

Lines changed: 62 additions & 20 deletions

File tree

services/current-account/adapters/persistence/org_scoped_account_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ func setupOrgScopedTestDB(t *testing.T) (*gorm.DB, *Repository, context.Context,
2626
err := db.Exec(fmt.Sprintf("CREATE SCHEMA IF NOT EXISTS %s", pq.QuoteIdentifier(schemaName))).Error
2727
require.NoError(t, err)
2828

29-
// Create the accounts table in tenant schema with org_party_id column
30-
err = db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.accounts (
29+
// Create the account table in tenant schema (matches CurrentAccountEntity.TableName() = "account")
30+
err = db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.account (
3131
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
3232
account_id VARCHAR(100) NOT NULL UNIQUE,
3333
account_identification VARCHAR(34) NOT NULL UNIQUE,
@@ -37,11 +37,10 @@ func setupOrgScopedTestDB(t *testing.T) (*gorm.DB, *Repository, context.Context,
3737
status VARCHAR(20) NOT NULL DEFAULT 'active',
3838
party_id UUID NOT NULL,
3939
org_party_id UUID NULL,
40-
balance BIGINT NOT NULL DEFAULT 0,
41-
available_balance BIGINT NOT NULL DEFAULT 0,
4240
overdraft_limit BIGINT NOT NULL DEFAULT 0,
4341
overdraft_rate NUMERIC(5,4) NOT NULL DEFAULT 0,
44-
balance_updated_at TIMESTAMP WITH TIME ZONE,
42+
product_type_code VARCHAR(50) NULL,
43+
product_type_version INT NULL,
4544
opened_at TIMESTAMP WITH TIME ZONE,
4645
closed_at TIMESTAMP WITH TIME ZONE,
4746
freeze_reason VARCHAR(1000),

services/current-account/adapters/persistence/repository.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,12 @@ func (r *Repository) Save(ctx context.Context, account domain.CurrentAccount) er
221221
updateResult := tx.Model(&CurrentAccountEntity{}).
222222
Where("account_identification = ? AND version = ?", entity.AccountIdentification, originalVersion).
223223
Updates(map[string]interface{}{
224-
"status": entity.Status,
225-
"freeze_reason": entity.FreezeReason,
226-
"status_history": entity.StatusHistory,
227-
"overdraft_limit": entity.OverdraftLimit,
228-
"overdraft_rate": entity.OverdraftRate,
229-
"version": entity.Version,
230-
"updated_at": entity.UpdatedAt,
231-
"updated_by": entity.UpdatedBy,
224+
"status": entity.Status,
225+
"freeze_reason": entity.FreezeReason,
226+
"status_history": entity.StatusHistory,
227+
"version": entity.Version,
228+
"updated_at": entity.UpdatedAt,
229+
"updated_by": entity.UpdatedBy,
232230
})
233231

234232
if updateResult.Error != nil {

services/current-account/adapters/persistence/repository_test.go

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ func setupTestDB(t *testing.T) (*gorm.DB, context.Context, func()) {
3232
err := db.Exec(fmt.Sprintf("CREATE SCHEMA IF NOT EXISTS %s", pq.QuoteIdentifier(schemaName))).Error
3333
require.NoError(t, err)
3434

35-
// Create the accounts table in the tenant schema (matching CurrentAccountEntity.TableName())
36-
err = db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.accounts (
35+
// Create the account table in the tenant schema (matches CurrentAccountEntity.TableName() = "account")
36+
err = db.Exec(fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.account (
3737
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
3838
account_id VARCHAR(100) NOT NULL UNIQUE,
3939
account_identification VARCHAR(34) NOT NULL UNIQUE,
@@ -43,11 +43,10 @@ func setupTestDB(t *testing.T) (*gorm.DB, context.Context, func()) {
4343
status VARCHAR(20) NOT NULL DEFAULT 'active',
4444
party_id UUID NOT NULL,
4545
org_party_id UUID NULL,
46-
balance BIGINT NOT NULL DEFAULT 0,
47-
available_balance BIGINT NOT NULL DEFAULT 0,
4846
overdraft_limit BIGINT NOT NULL DEFAULT 0,
4947
overdraft_rate NUMERIC(5,4) NOT NULL DEFAULT 0,
50-
balance_updated_at TIMESTAMP WITH TIME ZONE,
48+
product_type_code VARCHAR(50) NULL,
49+
product_type_version INT NULL,
5150
opened_at TIMESTAMP WITH TIME ZONE,
5251
closed_at TIMESTAMP WITH TIME ZONE,
5352
freeze_reason VARCHAR(1000),
@@ -344,6 +343,52 @@ func TestOptimisticLocking(t *testing.T) {
344343
}
345344
}
346345

346+
func TestSave_InstrumentCodeAndDimensionRoundTrip(t *testing.T) {
347+
db, ctx, cleanup := setupTestDB(t)
348+
defer cleanup()
349+
350+
repo := NewRepository(db)
351+
partyID := uuid.New().String()
352+
accountID := "ACC-" + uuid.New().String()[:8]
353+
iban := "GB82WEST12345698765432"
354+
355+
account, err := domain.NewCurrentAccount(accountID, iban, partyID, "EUR")
356+
require.NoError(t, err)
357+
358+
err = repo.Save(ctx, account)
359+
require.NoError(t, err)
360+
361+
retrieved, err := repo.FindByID(ctx, accountID)
362+
require.NoError(t, err)
363+
364+
assert.Equal(t, "EUR", retrieved.InstrumentCode(), "InstrumentCode should round-trip correctly")
365+
assert.Equal(t, "CURRENCY", retrieved.Dimension(), "Dimension should round-trip correctly")
366+
}
367+
368+
func TestSave_InstrumentCodePersistedOnEntity(t *testing.T) {
369+
db, ctx, cleanup := setupTestDB(t)
370+
defer cleanup()
371+
372+
repo := NewRepository(db)
373+
partyID := uuid.New().String()
374+
accountID := "ACC-" + uuid.New().String()[:8]
375+
iban := "GB82WEST12345698765432"
376+
377+
account, err := domain.NewCurrentAccount(accountID, iban, partyID, "GBP")
378+
require.NoError(t, err)
379+
380+
err = repo.Save(ctx, account)
381+
require.NoError(t, err)
382+
383+
// Read raw entity to verify column values in DB
384+
var entity CurrentAccountEntity
385+
err = db.Where("account_id = ?", accountID).First(&entity).Error
386+
require.NoError(t, err)
387+
388+
assert.Equal(t, "GBP", entity.InstrumentCode, "instrument_code column should be persisted")
389+
assert.Equal(t, "CURRENCY", entity.Dimension, "dimension column should be persisted")
390+
}
391+
347392
// Defensive tests for toDomain error handling per ADR-008
348393

349394
func TestToDomain_InvalidCurrency_ReturnsError(t *testing.T) {
@@ -579,9 +624,9 @@ func TestSave_UpdatePreservesCreatedByButUpdatesUpdatedBy(t *testing.T) {
579624
// - Redis key prefixing per organization
580625
// - Kafka header propagation
581626
//
582-
// The entity now uses unqualified table name "accounts" which allows
627+
// The entity uses unqualified table name "account" which allows
583628
// PostgreSQL's search_path mechanism to route queries to organization-specific
584-
// schemas (e.g., org_acme_bank.accounts, org_motive_corp.accounts).
629+
// schemas (e.g., org_acme_bank.account, org_motive_corp.account).
585630
//
586631
// See: shared/platform/db/gorm_organization_scope.go for the implementation
587632
// See: shared/platform/db/gorm_organization_scope_test.go for unit tests

0 commit comments

Comments
 (0)