Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,4 @@ docs/development/notes/*
!docs/development/notes/template-notes.md
/notes/
.pai
.theory/
2 changes: 1 addition & 1 deletion .release-please-manifest.premain.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.4.0"
".": "1.4.1-rc"
}
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [1.4.1-rc](https://github.com/theory-cloud/TableTheory/compare/v1.4.0...v1.4.1-rc) (2026-02-24)


### Bug Fixes

* unblock legacy naming and lambda KMS config ([897ea3c](https://github.com/theory-cloud/TableTheory/commit/897ea3cd37bff7bc795facc91a3b0451a693d817))

## [1.4.0](https://github.com/theory-cloud/TableTheory/compare/v1.3.0...v1.4.0) (2026-02-14)


Expand Down
704 changes: 352 additions & 352 deletions contract-tests/runners/ts/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contract-tests/runners/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"test:contract:p0": "tsx test/contract.p0.test.ts"
},
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.758.0"
"@aws-sdk/client-dynamodb": "^3.996.0"
},
"devDependencies": {
"tsx": "^4.20.5",
Expand Down
1 change: 1 addition & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func NewLambdaOptimized() (*LambdaDB, error)

- **Returns**: `*LambdaDB` pointer or error.
- **Best Practice**: Call this in your `init()` function or global variable declaration.
- **Encryption**: If any registered model includes `theorydb:"encrypted"`, set `KMS_KEY_ARN` (or `TABLETHEORY_KMS_KEY_ARN`) in your Lambda environment.

### `LambdaInit`

Expand Down
17 changes: 17 additions & 0 deletions docs/struct-definition-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ type User struct {

By default, TableTheory uses your field name (or the configured naming convention) as the DynamoDB attribute name.

TableTheory supports three attribute naming conventions:

- `camelCase` (default)
- `snake_case` (opt-in)
- `pascalCase` (opt-in; useful for legacy tables that use `ID`, `SK`, `GSI1PK`, etc)

To select a convention for a model, add a marker field (commonly a blank identifier) with a `naming:` tag:

```go
type LegacyUser struct {
_ struct{} `theorydb:"naming:pascalCase"`

ID string `theorydb:"pk"`
SK string `theorydb:"sk"`
}
```

To override the DynamoDB attribute name explicitly, use:

- `theorydb:"attr:<attributeName>"`
Expand Down
4 changes: 2 additions & 2 deletions hgm-infra/evidence/hgm-rubric-report.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://hgm.pai.dev/schemas/hgm-rubric-report.schema.json",
"schemaVersion": 1,
"timestamp": "2026-01-29T18:09:53Z",
"timestamp": "2026-02-24T00:37:04Z",
"pack": {
"version": "816465a1618d",
"digest": "896aed16549928f21626fb4effe9bb6236fc60292a8f50bae8ce77e873ac775b"
Expand All @@ -16,5 +16,5 @@
"fail": 0,
"blocked": 0
},
"results": [{"id":"QUA-1","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/QUA-1-output.log"},{"id":"QUA-2","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/QUA-2-output.log"},{"id":"QUA-3","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/QUA-3-output.log"},{"id":"QUA-4","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/QUA-4-output.log"},{"id":"QUA-5","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/QUA-5-output.log"},{"id":"CON-1","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/CON-1-output.log"},{"id":"CON-2","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/CON-2-output.log"},{"id":"CON-3","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/CON-3-output.log"},{"id":"COM-1","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-1-output.log"},{"id":"COM-2","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-2-output.log"},{"id":"COM-3","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-3-output.log"},{"id":"COM-4","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-4-output.log"},{"id":"COM-5","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-5-output.log"},{"id":"COM-6","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-6-output.log"},{"id":"COM-7","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-7-output.log"},{"id":"COM-8","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/COM-8-output.log"},{"id":"SEC-1","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-1-output.log"},{"id":"SEC-2","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-2-output.log"},{"id":"SEC-3","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-3-output.log"},{"id":"SEC-4","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-4-output.log"},{"id":"SEC-5","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-5-output.log"},{"id":"SEC-6","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-6-output.log"},{"id":"SEC-7","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-7-output.log"},{"id":"SEC-8","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-8-output.log"},{"id":"SEC-9","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/SEC-9-output.log"},{"id":"CMP-1","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-controls-matrix.md"},{"id":"CMP-2","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-evidence-plan.md"},{"id":"CMP-3","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-threat-model.md"},{"id":"MAI-1","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/MAI-1-output.log"},{"id":"MAI-2","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/MAI-2-output.log"},{"id":"MAI-3","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/MAI-3-output.log"},{"id":"DOC-1","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-threat-model.md"},{"id":"DOC-2","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-evidence-plan.md"},{"id":"DOC-3","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/planning/theorydb-10of10-rubric.md"},{"id":"DOC-4","category":"Docs","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/DOC-4-output.log"},{"id":"DOC-5","category":"Docs","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/hypergenium/TableTheory/hgm-infra/evidence/DOC-5-output.log"}]
"results": [{"id":"QUA-1","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/QUA-1-output.log"},{"id":"QUA-2","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/QUA-2-output.log"},{"id":"QUA-3","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/QUA-3-output.log"},{"id":"QUA-4","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/QUA-4-output.log"},{"id":"QUA-5","category":"Quality","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/QUA-5-output.log"},{"id":"CON-1","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/CON-1-output.log"},{"id":"CON-2","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/CON-2-output.log"},{"id":"CON-3","category":"Consistency","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/CON-3-output.log"},{"id":"COM-1","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-1-output.log"},{"id":"COM-2","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-2-output.log"},{"id":"COM-3","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-3-output.log"},{"id":"COM-4","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-4-output.log"},{"id":"COM-5","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-5-output.log"},{"id":"COM-6","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-6-output.log"},{"id":"COM-7","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-7-output.log"},{"id":"COM-8","category":"Completeness","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/COM-8-output.log"},{"id":"SEC-1","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-1-output.log"},{"id":"SEC-2","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-2-output.log"},{"id":"SEC-3","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-3-output.log"},{"id":"SEC-4","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-4-output.log"},{"id":"SEC-5","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-5-output.log"},{"id":"SEC-6","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-6-output.log"},{"id":"SEC-7","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-7-output.log"},{"id":"SEC-8","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-8-output.log"},{"id":"SEC-9","category":"Security","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/SEC-9-output.log"},{"id":"CMP-1","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-controls-matrix.md"},{"id":"CMP-2","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-evidence-plan.md"},{"id":"CMP-3","category":"Compliance","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-threat-model.md"},{"id":"MAI-1","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/MAI-1-output.log"},{"id":"MAI-2","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/MAI-2-output.log"},{"id":"MAI-3","category":"Maintainability","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/MAI-3-output.log"},{"id":"DOC-1","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-threat-model.md"},{"id":"DOC-2","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-evidence-plan.md"},{"id":"DOC-3","category":"Docs","status":"PASS","message":"File exists","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/planning/theorydb-10of10-rubric.md"},{"id":"DOC-4","category":"Docs","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/DOC-4-output.log"},{"id":"DOC-5","category":"Docs","status":"PASS","message":"Command succeeded","evidencePath":"/home/aron/ai-workspace/codebases/theory.cloud/TableTheory/hgm-infra/evidence/DOC-5-output.log"}]
}
8 changes: 8 additions & 0 deletions internal/theorydb/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func createLambdaDB() (*LambdaDB, error) {

cfg := session.Config{
Region: getRegion(),
KMSKeyARN: getKMSKeyARN(),
MaxRetries: 3,
DefaultRCU: 5,
DefaultWCU: 5,
Expand Down Expand Up @@ -343,6 +344,13 @@ func getRegion() string {
return "us-east-1"
}

func getKMSKeyARN() string {
if keyARN := os.Getenv("TABLETHEORY_KMS_KEY_ARN"); keyARN != "" {
return keyARN
}
return os.Getenv("KMS_KEY_ARN")
}

// GetRemainingTimeMillis returns milliseconds until Lambda timeout
func GetRemainingTimeMillis(ctx context.Context) int64 {
deadline, ok := ctx.Deadline()
Expand Down
26 changes: 26 additions & 0 deletions internal/theorydb/lambda_cov6_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,32 @@ func TestNewLambdaOptimized_WarmStartReturnsGlobal_COV6(t *testing.T) {
require.Same(t, globalLambdaDB, got)
}

func TestNewLambdaOptimized_ReadsKMSKeyARNFromEnv_COV6(t *testing.T) {
t.Cleanup(func() {
globalLambdaDB = nil
lambdaOnce = sync.Once{}
})

globalLambdaDB = nil
lambdaOnce = sync.Once{}

t.Setenv("AWS_LAMBDA_FUNCTION_NAME", "test-function")
t.Setenv("AWS_REGION", "us-east-1")
t.Setenv("KMS_KEY_ARN", "arn:aws:kms:us-east-1:111111111111:key/test")

stubSessionConfigLoad(t, func(context.Context, ...func(*config.LoadOptions) error) (aws.Config, error) {
return minimalAWSConfig(nil), nil
})

got, err := NewLambdaOptimized()
require.NoError(t, err)
require.NotNil(t, got)
require.NotNil(t, got.db)
require.NotNil(t, got.db.session)
require.NotNil(t, got.db.session.Config())
require.Equal(t, "arn:aws:kms:us-east-1:111111111111:key/test", got.db.session.Config().KMSKeyARN)
}

func TestLambdaDB_WithLambdaTimeout_NoDeadlineReturnsSame_COV6(t *testing.T) {
ldb := &LambdaDB{db: &DB{}}
require.Same(t, ldb, ldb.WithLambdaTimeout(context.Background()))
Expand Down
2 changes: 2 additions & 0 deletions pkg/dms/dms.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ func namingConventionString(c naming.Convention) string {
switch c {
case naming.SnakeCase:
return "snake_case"
case naming.PascalCase:
return "pascalCase"
case naming.CamelCase:
fallthrough
default:
Expand Down
4 changes: 4 additions & 0 deletions pkg/model/cov6_registry_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ func TestDetectNamingConvention_COV6(t *testing.T) {
type camel struct {
_ string `theorydb:"naming:camelCase"`
}
type pascal struct {
_ string `theorydb:"naming:pascalCase"`
}
type none struct {
Field string
}

require.Equal(t, naming.SnakeCase, detectNamingConvention(reflect.TypeOf(snake{})))
require.Equal(t, naming.CamelCase, detectNamingConvention(reflect.TypeOf(camel{})))
require.Equal(t, naming.PascalCase, detectNamingConvention(reflect.TypeOf(pascal{})))
require.Equal(t, naming.CamelCase, detectNamingConvention(reflect.TypeOf(none{})))
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/model/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,8 @@ func detectNamingConvention(modelType reflect.Type) naming.Convention {
return naming.SnakeCase
case "camel_case", "camelCase":
return naming.CamelCase
case "pascal_case", "pascalCase":
return naming.PascalCase
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/model/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,31 @@ func TestRegisterCustomAttributeModel(t *testing.T) {
assert.Equal(t, usernameField, metadata.FieldsByDBName["username"])
}

func TestRegisterPascalCaseNamingConvention_AllowsAcronymsAndGSIs(t *testing.T) {
registry := model.NewRegistry()

type PascalCaseUser struct {
_ struct{} `theorydb:"naming:pascalCase"`

ID string `theorydb:"pk"`
SK string `theorydb:"sk"`

GSI1PK string `theorydb:"index:gsi1,pk"`
GSI1SK string `theorydb:"index:gsi1,sk"`
}

err := registry.Register(&PascalCaseUser{})
require.NoError(t, err)

metadata, err := registry.GetMetadata(&PascalCaseUser{})
require.NoError(t, err)

require.Equal(t, "ID", metadata.Fields["ID"].DBName)
require.Equal(t, "SK", metadata.Fields["SK"].DBName)
require.Equal(t, "GSI1PK", metadata.Fields["GSI1PK"].DBName)
require.Equal(t, "GSI1SK", metadata.Fields["GSI1SK"].DBName)
}

func TestRegisterInvalidModel(t *testing.T) {
registry := model.NewRegistry()

Expand Down
Loading
Loading