Overview
Mutations provide a type-safe API for modifying data. All mutations include:
- Three-stage validation (schema → types → constraints)
- Automatic safety guards (e.g., UPDATE/DELETE requires WHERE clause)
- Rich error messages with suggestions
- Debug mode support
Insert
Insert()
Starts a new INSERT operation.
func (e *Engine) Insert(entity string) InsertMutation
Entity name to insert into (e.g., “User”, “Post”)
Set()
Adds a field value to insert.
func (ib *InsertBuilder) Set(field string, value interface{}) InsertMutation
Value to insert (string, int, float64, bool, time.Time, uuid, etc.)
Execute()
Validates and executes the INSERT operation.
func (ib *InsertBuilder) Execute(ctx context.Context) (*InsertResult, error)
Result containing the inserted record
InsertResult fields:
Primary key of the inserted record
Full inserted record (from RETURNING *)
Number of rows inserted (always 1)
Examples:
import (
"context"
"log"
"github.com/chameleon-db/chameleondb/chameleon/pkg/engine"
"github.com/google/uuid"
)
// Basic insert
result, err := eng.Insert("User").
Set("id", uuid.New().String()).
Set("email", "ana@mail.com").
Set("name", "Ana Garcia").
Execute(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("User created with ID: %v\n", result.ID)
// Access full record
fmt.Printf("Email: %s\n", result.Record["email"])
fmt.Printf("Created at: %v\n", result.Record["created_at"])
With debug:
result, err := eng.Insert("Post").
Set("id", uuid.New().String()).
Set("title", "My First Post").
Set("content", "Hello, World!").
Set("published", false).
Set("author_id", authorID).
Debug().
Execute(ctx)
// Output:
// [ENTITY] INSERT INTO Post
// [SQL] INSERT INTO posts (author_id, content, id, published, title) VALUES ($1, $2, $3, $4, $5) RETURNING *
// [VALUES] [<uuid> "Hello, World!" <uuid> false "My First Post"]
Update
Update()
Starts a new UPDATE operation.
func (e *Engine) Update(entity string) UpdateMutation
Entity name to update (e.g., “User”, “Post”)
Set()
Adds a field to update.
func (ub *UpdateBuilder) Set(field string, value interface{}) UpdateMutation
Filter()
Adds a WHERE condition (required for safety).
func (ub *UpdateBuilder) Filter(field string, operator string, value interface{}) UpdateMutation
Comparison operator: "eq", "neq", "gt", "gte", "lt", "lte", "like"
Execute()
Validates and executes the UPDATE operation.
func (ub *UpdateBuilder) Execute(ctx context.Context) (*UpdateResult, error)
Result containing updated records
UpdateResult fields:
All updated records (from RETURNING *)
Examples:
// Update by ID
result, err := eng.Update("User").
Filter("id", "eq", userID).
Set("name", "Ana María Garcia").
Execute(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Updated %d user(s)\n", result.Affected)
// Update multiple fields
eng.Update("Post").
Filter("id", "eq", postID).
Set("title", "Updated Title").
Set("published", true).
Set("updated_at", time.Now()).
Execute(ctx)
// Update multiple rows
result, _ := eng.Update("Post").
Filter("author_id", "eq", authorID).
Filter("published", "eq", false).
Set("published", true).
Execute(ctx)
fmt.Printf("Published %d posts\n", result.Affected)
// Access updated records
for _, record := range result.Records {
fmt.Printf("Updated post: %s\n", record["title"])
}
Safety guard:
// This will FAIL (no Filter called)
result, err := eng.Update("User").
Set("status", "active").
Execute(ctx)
// Error: UPDATE without filters is blocked
Delete
Delete()
Starts a new DELETE operation.
func (e *Engine) Delete(entity string) DeleteMutation
Entity name to delete from (e.g., “User”, “Post”)
Filter()
Adds a WHERE condition (required for safety).
func (db *DeleteBuilder) Filter(field string, operator string, value interface{}) DeleteMutation
Execute()
Validates and executes the DELETE operation.
func (db *DeleteBuilder) Execute(ctx context.Context) (*DeleteResult, error)
Result containing number of deleted rows
DeleteResult fields:
Examples:
// Delete by ID
result, err := eng.Delete("Post").
Filter("id", "eq", postID).
Execute(ctx)
if err != nil {
log.Fatal(err)
}
if result.Affected == 0 {
fmt.Println("Post not found")
} else {
fmt.Printf("Deleted %d post(s)\n", result.Affected)
}
// Delete multiple rows
result, _ := eng.Delete("Post").
Filter("author_id", "eq", authorID).
Filter("published", "eq", false).
Execute(ctx)
fmt.Printf("Deleted %d draft posts\n", result.Affected)
// Delete with comparison
eng.Delete("User").
Filter("last_login", "lt", "2023-01-01").
Execute(ctx)
Safety guard:
// This will FAIL (no Filter called)
result, err := eng.Delete("Post").
Execute(ctx)
// Error: DELETE without filters is blocked
Debug Mode
Debug()
Enables SQL debug output for the mutation.
func (ib *InsertBuilder) Debug() InsertMutation
func (ub *UpdateBuilder) Debug() UpdateMutation
func (db *DeleteBuilder) Debug() DeleteMutation
Examples:
// Insert with debug
eng.Insert("User").
Set("email", "test@mail.com").
Set("name", "Test User").
Debug().
Execute(ctx)
// Output:
// [ENTITY] INSERT INTO User
// [SQL] INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *
// [VALUES] ["test@mail.com" "Test User"]
// [TRACE] INSERT on User: 3.2ms, 1 row
// Update with debug
eng.Update("Post").
Filter("id", "eq", postID).
Set("published", true).
Debug().
Execute(ctx)
// Output:
// [SQL] UPDATE Post
// UPDATE posts SET published = $1 WHERE id = $2 RETURNING *
// [VALUES] [true <uuid>]
// [TRACE] UPDATE on Post: 2.1ms, 1 row
Validation
All mutations go through a three-stage validation pipeline:
1. Schema Validation
Verifies entity and field names exist in the schema.
eng.Insert("UnknownEntity").
Set("field", "value").
Execute(ctx)
// Error: UnknownEntityError: Entity 'UnknownEntity' not found in schema
// Available entities: [User, Post, Comment]
2. Type Validation
Verifies value types match field definitions.
eng.Insert("User").
Set("age", "not a number").
Execute(ctx)
// Error: TypeMismatchError: Field 'age'
// Expected type: int
// Received type: string (value: "not a number")
// Suggestion: Use an integer value
3. Constraint Validation
Verifies database constraints (executed at database level).
eng.Insert("User").
Set("email", "existing@mail.com").
Execute(ctx)
// Error: UniqueConstraintError: Field 'email' must be unique
// Value: existing@mail.com
// Conflict: User(id=123) already has this value
// Suggestion: Use a different value or update the existing record
Complete Examples
package main
import (
"context"
"fmt"
"log"
"github.com/chameleon-db/chameleondb/chameleon/pkg/engine"
"github.com/google/uuid"
)
func main() {
ctx := context.Background()
eng, _ := engine.NewEngine()
defer eng.Close()
// ... connect to database ...
// 1. Create user
userResult, err := eng.Insert("User").
Set("id", uuid.New().String()).
Set("email", "author@mail.com").
Set("name", "John Doe").
Execute(ctx)
if err != nil {
log.Fatal(err)
}
userID := userResult.ID
fmt.Printf("Created user: %v\n", userID)
// 2. Create posts for user
for i := 1; i <= 3; i++ {
postResult, err := eng.Insert("Post").
Set("id", uuid.New().String()).
Set("title", fmt.Sprintf("Post #%d", i)).
Set("content", "Content here...").
Set("author_id", userID).
Set("published", i == 1). // Only first post published
Execute(ctx)
if err != nil {
log.Printf("Failed to create post: %v", err)
continue
}
fmt.Printf("Created post: %v\n", postResult.ID)
}
// 3. Publish all drafts
updateResult, _ := eng.Update("Post").
Filter("author_id", "eq", userID).
Filter("published", "eq", false).
Set("published", true).
Execute(ctx)
fmt.Printf("Published %d posts\n", updateResult.Affected)
}
Conditional Updates
func incrementViewCount(eng *engine.Engine, postID string) error {
// Get current count
result, err := eng.Query("Post").
Select("views").
Filter("id", "eq", postID).
Execute(context.Background())
if err != nil || result.IsEmpty() {
return fmt.Errorf("post not found")
}
currentViews := result.Rows[0].Int("views")
// Update with new count
_, err = eng.Update("Post").
Filter("id", "eq", postID).
Set("views", currentViews+1).
Execute(context.Background())
return err
}
Batch Operations
func createUsers(eng *engine.Engine, users []map[string]string) error {
ctx := context.Background()
for _, userData := range users {
_, err := eng.Insert("User").
Set("id", uuid.New().String()).
Set("email", userData["email"]).
Set("name", userData["name"]).
Execute(ctx)
if err != nil {
return fmt.Errorf("failed to create user %s: %w",
userData["email"], err)
}
}
return nil
}
See Also