Skip to content

Struct Tags

Dynorm uses struct tags to configure entity behavior, indexing, and relationships.

dynorm Tags

Primary Key

Tag Description Example
pk Partition key dynorm:"pk"
sk Sort key dynorm:"sk"
type Entity struct {
    ID string `dynorm:"pk"` // Partition key
}

type CompositeKeyEntity struct {
    PK string `dynorm:"pk"` // Partition key
    SK string `dynorm:"sk"` // Sort key
}

Global Secondary Indexes (GSI)

Tag Description Example
gsi:IndexName GSI partition key dynorm:"gsi:ByEmail"
gsi:IndexName:sk GSI sort key dynorm:"gsi:ByEmail:sk"
type User struct {
    dynorm.Entity

    Email    string `dynorm:"gsi:ByEmail"`           // GSI partition key
    Username string `dynorm:"gsi:ByUsername"`        // Another GSI
    Status   string `dynorm:"gsi:ByStatusDate"`      // GSI PK
    Date     string `dynorm:"gsi:ByStatusDate:sk"`   // GSI SK
}

Local Secondary Indexes (LSI)

Tag Description Example
lsi:IndexName LSI sort key dynorm:"lsi:ByDate"
type Order struct {
    dynorm.Entity

    UserID    string    `dynorm:"pk"`           // Same PK as table
    OrderDate time.Time `dynorm:"lsi:ByDate"`   // LSI sort key
}

Special Attributes

Tag Description Example
version Optimistic locking version dynorm:"version"
ttl Time-to-live attribute dynorm:"ttl"
createdAt Creation timestamp dynorm:"createdAt"
updatedAt Update timestamp dynorm:"updatedAt"
deletedAt Soft delete timestamp dynorm:"deletedAt"
type Document struct {
    dynorm.Entity

    Content   string
    Version   int       `dynorm:"version"`  // Optimistic locking
    ExpiresAt time.Time `dynorm:"ttl"`      // Auto-expire after this time
}

Entity Tags

Soft Deletes

Tag Description Example
soft_deletes:"true" Enable soft deletes On embedded Entity
type Post struct {
    dynorm.Entity `soft_deletes:"true"` // Enable soft deletes

    Title   string
    Content string
}

Repository Tags

Table Name

Tag Description Example
table:"name" Custom table name table:"custom_users"
// Auto-derived table name: User → users
type UserRepository struct {
    dynorm.Repository[User]
}

// Custom table name
type StaffRepository struct {
    dynorm.Repository[User] `table:"staff_members"`
}

Relationship Tags

HasOne

type User struct {
    dynorm.Entity

    // Format: hasOne:RelatedEntity,ForeignKeyField
    Profile HasOne[*ProfileRepository] `dynorm:"hasOne:Profile,UserID"`
}

HasMany

type User struct {
    dynorm.Entity

    // Format: hasMany:RelatedEntity,ForeignKeyField
    Posts HasMany[*PostRepository] `dynorm:"hasMany:Post,AuthorID"`
}

BelongsTo

type Post struct {
    dynorm.Entity

    AuthorID string

    // Format: belongsTo:RelatedEntity,ForeignKeyField
    Author BelongsTo[*UserRepository] `dynorm:"belongsTo:User,AuthorID"`
}

BelongsToMany

type User struct {
    dynorm.Entity

    // Format: belongsToMany:RelatedEntity
    Roles BelongsToMany[*RoleRepository] `dynorm:"belongsToMany:Role"`
}

HasManyThrough

type Country struct {
    dynorm.Entity

    // Format: hasManyThrough:FinalEntity,ThroughEntity,FirstFK,SecondFK
    Posts HasManyThrough[*PostRepository, *UserRepository] `dynorm:"hasManyThrough:Post,User,CountryID,AuthorID"`
}

MorphOne

type User struct {
    dynorm.Entity

    // Format: morphOne:RelatedEntity,MorphName
    Avatar MorphOne[*ImageRepository] `dynorm:"morphOne:Image,imageable"`
}

MorphMany

type Post struct {
    dynorm.Entity

    // Format: morphMany:RelatedEntity,MorphName
    Comments MorphMany[*CommentRepository] `dynorm:"morphMany:Comment,commentable"`
}

MorphToMany

type Post struct {
    dynorm.Entity

    // Format: morphToMany:RelatedEntity,MorphName
    Tags MorphToMany[*TagRepository] `dynorm:"morphToMany:Tag,taggable"`
}

MorphedByMany

type Tag struct {
    dynorm.Entity

    // Format: morphedByMany:MorphName
    Taggables MorphedByMany[any] `dynorm:"morphedByMany:taggable"`
}

Tag Reference Table

Category Tag Format Description
Keys pk dynorm:"pk" Partition key
sk dynorm:"sk" Sort key
GSI gsi:Name dynorm:"gsi:ByEmail" GSI partition key
gsi:Name:sk dynorm:"gsi:ByEmail:sk" GSI sort key
LSI lsi:Name dynorm:"lsi:ByDate" LSI sort key
Special version dynorm:"version" Optimistic locking
ttl dynorm:"ttl" Time-to-live
createdAt dynorm:"createdAt" Creation timestamp
updatedAt dynorm:"updatedAt" Update timestamp
deletedAt dynorm:"deletedAt" Soft delete timestamp
Entity soft_deletes soft_deletes:"true" Enable soft deletes
Repository table table:"name" Custom table name
Relationships hasOne hasOne:Entity,FK One-to-one
hasMany hasMany:Entity,FK One-to-many
belongsTo belongsTo:Entity,FK Inverse relationship
belongsToMany belongsToMany:Entity Many-to-many
hasManyThrough hasManyThrough:E,T,FK1,FK2 Through relationship
morphOne morphOne:Entity,name Polymorphic one
morphMany morphMany:Entity,name Polymorphic many
morphToMany morphToMany:Entity,name Polymorphic M:M
morphedByMany morphedByMany:name Inverse polymorphic

Complete Example

type User struct {
    dynorm.Entity `soft_deletes:"true"`

    // Indexed fields
    Email    string `dynorm:"gsi:ByEmail"`
    Username string `dynorm:"gsi:ByUsername"`
    Status   string `dynorm:"gsi:ByStatusCreated"`
    // CreatedAt from Entity is GSI sort key

    // Profile fields
    FirstName string
    LastName  string

    // Optimistic locking
    Version int `dynorm:"version"`

    // Relationships
    Profile HasOne[*ProfileRepository]    `dynorm:"hasOne:Profile,UserID"`
    Posts   HasMany[*PostRepository]      `dynorm:"hasMany:Post,AuthorID"`
    Roles   BelongsToMany[*RoleRepository] `dynorm:"belongsToMany:Role"`
    Tags    MorphToMany[*TagRepository]   `dynorm:"morphToMany:Tag,taggable"`
}

type UserRepository struct {
    dynorm.Repository[User] // Table: users
}

Next Steps