[{"data":1,"prerenderedAt":8339},["ShallowReactive",2],{"search-sections-edamame":3,"nav-edamame":888,"content-tree-edamame":931,"footer-resources":950,"content-/v1.0.3/reference/api":3703,"surround-/v1.0.3/reference/api":8337},[4,10,14,20,25,30,35,41,46,51,56,61,64,69,74,79,84,89,94,99,104,108,113,118,123,127,132,137,142,147,152,157,162,167,172,177,182,187,192,197,202,207,212,217,221,225,230,234,239,244,249,254,259,264,269,273,277,281,286,291,296,301,306,311,316,321,326,331,336,341,346,351,356,361,366,371,376,381,386,391,396,401,406,411,416,421,426,431,436,441,444,449,454,459,463,467,472,477,482,487,492,497,502,507,512,517,522,526,531,535,540,545,550,555,560,565,570,575,580,585,590,594,598,603,607,612,617,622,627,632,636,641,646,651,656,661,665,669,675,680,685,690,695,700,705,709,714,719,724,729,734,739,744,748,753,758,763,768,773,778,783,787,792,796,800,805,809,813,817,821,825,829,834,839,844,849,854,859,864,869,874,879,884],{"id":5,"title":6,"titles":7,"content":8,"level":9},"/v1.0.3/overview","Overview",[],"Statement-driven query exec for Go applications",1,{"id":11,"title":6,"titles":12,"content":13,"level":9},"/v1.0.3/overview#overview",[],"Database operations in Go often mean choosing between raw SQL and heavy ORMs. Edamame offers a third path: a statement-driven query exec that stays out of your way while providing type-safe, declarative query definitions. // Define your model\ntype User struct {\n    ID    int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name  string `db:\"name\" type:\"text\"`\n    Age   *int   `db:\"age\" type:\"integer\"`\n}\n\n// Define statements as package-level variables\nvar (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    DeleteByID = edamame.NewDeleteStatement(\"delete-by-id\", \"Delete user by ID\", edamame.DeleteSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    Adults = edamame.NewQueryStatement(\"adults\", \"Find users over a minimum age\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        },\n        OrderBy: []edamame.OrderBySpec{\n            {Field: \"name\", Direction: \"asc\"},\n        },\n    })\n)\n\n// Create a exec and execute\nexec, err := edamame.New[User](db, \"users\", renderer)\n\nusers, err := exec.ExecQuery(ctx, QueryAll, nil)\nuser, err := exec.ExecSelect(ctx, SelectByID, map[string]any{\"id\": 123})\ninserted, err := exec.ExecInsert(ctx, &user)\ndeleted, err := exec.ExecDelete(ctx, DeleteByID, map[string]any{\"id\": 123})\nadults, err := exec.ExecQuery(ctx, Adults, map[string]any{\"min_age\": 18}) Type-safe, injection-protected, declarative.",{"id":15,"title":16,"titles":17,"content":18,"level":19},"/v1.0.3/overview#architecture","Architecture",[6],"┌─────────────────────────────────────────────────────────────┐\n│                         Edamame                             │\n│                                                             │\n│  ┌─────────────────────────────────────────────────────┐    │\n│  │                   Executor[T]                        │    │\n│  │                                                     │    │\n│  │  ┌───────────────────────────────────────────────┐  │    │\n│  │  │              Statement Types                   │  │    │\n│  │  │                                                │  │    │\n│  │  │  QueryStatement  SelectStatement               │  │    │\n│  │  │  UpdateStatement DeleteStatement               │  │    │\n│  │  │  AggregateStatement                            │  │    │\n│  │  └────────────────────┬───────────────────────────┘  │    │\n│  │                       │                              │    │\n│  │                 ┌─────▼─────┐                        │    │\n│  │                 │    Soy    │                        │    │\n│  │                 │ (Builder) │                        │    │\n│  │                 └─────┬─────┘                        │    │\n│  │                       │                              │    │\n│  └───────────────────────┼──────────────────────────────┘    │\n│                          │                                   │\n│                    ┌─────▼─────┐                             │\n│                    │   sqlx    │                             │\n│                    │    DB     │                             │\n│                    └───────────┘                             │\n└─────────────────────────────────────────────────────────────┘ Edamame provides typed statements over soy's query builder. Each statement type encapsulates a declarative spec that maps to a parameterized SQL builder.",2,{"id":21,"title":22,"titles":23,"content":24,"level":19},"/v1.0.3/overview#philosophy","Philosophy",[6],"Edamame bridges two worlds: the declarative simplicity of specs and the type safety of Go generics. Define what you want, get SQL that's validated at build time and parameterized at runtime. // Define statements as package-level variables\nvar ActiveByRole = edamame.NewQueryStatement(\"active-by-role\", \"Find active users by role\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"active\", Operator: \"=\", Param: \"active\"},\n        {Field: \"role\", Operator: \"=\", Param: \"role\"},\n    },\n})\n\n// In your API handler\nusers, err := exec.ExecQuery(ctx, ActiveByRole, map[string]any{\n    \"active\": true,\n    \"role\":   \"admin\",\n}) Typed statements, compile-time safety, no magic strings.",{"id":26,"title":27,"titles":28,"content":29,"level":19},"/v1.0.3/overview#statement-types","Statement Types",[6],"Edamame provides five statement types for different operations: Statement TypeDescriptionQueryStatementMulti-record retrieval with filteringSelectStatementSingle-record retrievalUpdateStatementTargeted updates with SET/WHEREDeleteStatementConditional deletion with WHEREAggregateStatementCOUNT, SUM, AVG, MIN, MAX operations Each statement type accepts a spec that defines the query behavior: QuerySpec - Filtering, sorting, pagination, grouping, locking SelectSpec - Single-record filtering with optional locking UpdateSpec - SET clauses and WHERE conditions DeleteSpec - WHERE conditions for targeted deletion AggregateSpec - Field to aggregate and optional filtering",{"id":31,"title":32,"titles":33,"content":34,"level":19},"/v1.0.3/overview#priorities","Priorities",[6],"",{"id":36,"title":37,"titles":38,"content":39,"level":40},"/v1.0.3/overview#type-safety","Type Safety",[6,32],"Fields, operators, and params are validated at query build time. No runtime SQL injection, no magic strings. // Spec-based: field names validated against model metadata\nvar Adults = edamame.NewQueryStatement(\"adults\", \"Find adults\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n    },\n})\n\n// Execution: params bound safely via sqlx\nusers, err := exec.ExecQuery(ctx, Adults, map[string]any{\n    \"min_age\": 18,  // Parameterized, never interpolated\n})",3,{"id":42,"title":43,"titles":44,"content":45,"level":40},"/v1.0.3/overview#compile-time-guarantees","Compile-Time Guarantees",[6,32],"Statements are typed. Pass a QueryStatement to ExecQuery, a SelectStatement to ExecSelect. The compiler catches mismatches. // Compiler ensures correct statement types\nusers, err := exec.ExecQuery(ctx, QueryAll, nil)       // QueryStatement\nuser, err := exec.ExecSelect(ctx, SelectByID, params)  // SelectStatement\ncount, err := exec.ExecAggregate(ctx, CountAll, nil)   // AggregateStatement",{"id":47,"title":48,"titles":49,"content":50,"level":40},"/v1.0.3/overview#security","Security",[6,32],"All SQL generation flows through soy's validated builder: Field names validated against model metadataOperators validated against allowlistAll values bound as parameters, never interpolatedNo raw SQL construction from user input",{"id":52,"title":53,"titles":54,"content":55,"level":40},"/v1.0.3/overview#performance","Performance",[6,32],"Lazy initialization - Builders created on demandMinimal allocations - Spec-to-builder conversion is lightweightBatch operations - Insert, update, delete batches in single transactions html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"id":57,"title":58,"titles":59,"content":60,"level":9},"/v1.0.3/learn/quickstart","Quickstart",[],"Get started with edamame in minutes",{"id":62,"title":58,"titles":63,"content":34,"level":9},"/v1.0.3/learn/quickstart#quickstart",[],{"id":65,"title":66,"titles":67,"content":68,"level":19},"/v1.0.3/learn/quickstart#requirements","Requirements",[58],"Go 1.24 or later.",{"id":70,"title":71,"titles":72,"content":73,"level":19},"/v1.0.3/learn/quickstart#installation","Installation",[58],"go get github.com/zoobz-io/edamame",{"id":75,"title":76,"titles":77,"content":78,"level":19},"/v1.0.3/learn/quickstart#basic-usage","Basic Usage",[58],"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    \"github.com/jmoiron/sqlx\"\n    _ \"github.com/lib/pq\" // or mariadb, sqlite3, mssql driver\n    \"github.com/zoobz-io/astql/pkg/postgres\" // or mariadb, sqlite, mssql\n    \"github.com/zoobz-io/edamame\"\n)\n\n// Define your model with struct tags\ntype User struct {\n    ID    int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name  string `db:\"name\" type:\"text\"`\n    Age   *int   `db:\"age\" type:\"integer\"`\n}\n\n// Define statements as package-level variables\nvar (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    CountAll = edamame.NewAggregateStatement(\"count-all\", \"Count all users\", edamame.AggCount, edamame.AggregateSpec{})\n)\n\nfunc main() {\n    // Connect to database (PostgreSQL shown; MariaDB, SQLite, SQL Server also supported)\n    db, err := sqlx.Connect(\"postgres\", \"postgres://user:pass@localhost/mydb?sslmode=disable\")\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Create exec\n    exec, err := edamame.New[User](db, \"users\", postgres.New())\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    ctx := context.Background()\n\n    // Query all users\n    users, err := exec.ExecQuery(ctx, QueryAll, nil)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Found %d users\\n\", len(users))\n\n    // Select user by ID\n    user, err := exec.ExecSelect(ctx, SelectByID, map[string]any{\"id\": 1})\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"User: %s\\n\", user.Name)\n\n    // Insert a new user\n    age := 25\n    newUser := &User{\n        Email: \"alice@example.com\",\n        Name:  \"Alice\",\n        Age:   &age,\n    }\n    inserted, err := exec.ExecInsert(ctx, newUser)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Inserted user ID: %d\\n\", inserted.ID)\n\n    // Count users\n    count, err := exec.ExecAggregate(ctx, CountAll, nil)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Total users: %.0f\\n\", count)\n}",{"id":80,"title":81,"titles":82,"content":83,"level":19},"/v1.0.3/learn/quickstart#whats-happening","What's Happening",[58],"New[User](db, \"users\", postgres.New()) creates a exec for the User type bound to the \"users\" table with the PostgreSQL rendererStatements are defined as package-level variables with unique names and descriptionsExecQuery returns all records matching the statement's specExecSelect returns a single record (or error if not found)ExecInsert inserts a record and returns it with generated fields (like ID)ExecAggregate runs an aggregate function and returns the result",{"id":85,"title":86,"titles":87,"content":88,"level":19},"/v1.0.3/learn/quickstart#defining-custom-statements","Defining Custom Statements",[58],"// Define statements for your domain\nvar (\n    // Query for active adult users\n    ActiveAdults = edamame.NewQueryStatement(\"active-adults\", \"Find active users above minimum age\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"active\", Operator: \"=\", Param: \"active\"},\n            {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        },\n        OrderBy: []edamame.OrderBySpec{\n            {Field: \"name\", Direction: \"asc\"},\n        },\n    })\n\n    // Update user name\n    UpdateName = edamame.NewUpdateStatement(\"update-name\", \"Update user name by ID\", edamame.UpdateSpec{\n        Set:   map[string]string{\"name\": \"new_name\"},\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    // Delete inactive users\n    DeleteInactive = edamame.NewDeleteStatement(\"delete-inactive\", \"Delete inactive users\", edamame.DeleteSpec{\n        Where: []edamame.ConditionSpec{{Field: \"active\", Operator: \"=\", Param: \"active\"}},\n    })\n\n    // Sum of ages\n    SumAges = edamame.NewAggregateStatement(\"sum-ages\", \"Sum all user ages\", edamame.AggSum, edamame.AggregateSpec{\n        Field: \"age\",\n    })\n)\n\n// Use the statements\nusers, err := exec.ExecQuery(ctx, ActiveAdults, map[string]any{\n    \"active\":  true,\n    \"min_age\": 18,\n})\n\naffected, err := exec.ExecUpdate(ctx, UpdateName, map[string]any{\n    \"id\":       123,\n    \"new_name\": \"New Name\",\n})\n\ndeleted, err := exec.ExecDelete(ctx, DeleteInactive, map[string]any{\n    \"active\": false,\n})\n\ntotal, err := exec.ExecAggregate(ctx, SumAges, nil)",{"id":90,"title":91,"titles":92,"content":93,"level":19},"/v1.0.3/learn/quickstart#statement-parameters","Statement Parameters",[58],"Statements automatically derive their parameters from the spec. You can inspect them: // Check statement parameters\nfor _, param := range ActiveAdults.Params() {\n    fmt.Printf(\"Param: %s (type: %s, required: %v)\\n\", param.Name, param.Type, param.Required)\n}\n// Output:\n// Param: active (type: any, required: true)\n// Param: min_age (type: any, required: true)",{"id":95,"title":96,"titles":97,"content":98,"level":19},"/v1.0.3/learn/quickstart#next-steps","Next Steps",[58],"Core Concepts - Understand factories, statements, and specsStatement Guide - Define custom queries, updates, and moreTesting - Test your database operations html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":100,"title":101,"titles":102,"content":103,"level":9},"/v1.0.3/learn/concepts","Core Concepts",[],"Executors, statements, and specs - the building blocks of edamame",{"id":105,"title":101,"titles":106,"content":107,"level":9},"/v1.0.3/learn/concepts#core-concepts",[],"Edamame has three primitives: executors, statements, and specs. Understanding these unlocks the full API.",{"id":109,"title":110,"titles":111,"content":112,"level":19},"/v1.0.3/learn/concepts#executor","Executor",[101],"An executor is the execution context for a single model type. It wraps soy and provides methods to execute typed statements. exec, err := edamame.New[User](db, \"users\", renderer) The executor: Wraps a soy instance for SQL buildingProvides execution methods that accept typed statementsSupports transactions via *Tx method variants",{"id":114,"title":115,"titles":116,"content":117,"level":40},"/v1.0.3/learn/concepts#struct-tags","Struct Tags",[101,110],"Edamame uses struct tags to understand your model: type User struct {\n    ID    int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name  string `db:\"name\" type:\"text\"`\n    Age   *int   `db:\"age\" type:\"integer\"`\n} TagPurposeExampledbColumn namedb:\"user_id\"typeSQL typetype:\"text\", type:\"integer\"constraintsColumn constraintsconstraints:\"primarykey,notnull\"",{"id":119,"title":120,"titles":121,"content":122,"level":19},"/v1.0.3/learn/concepts#statements","Statements",[101],"A statement is a typed, named database operation. Define statements as package-level variables: var (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n) Each statement has: Name - Human-readable identifierDescription - What the statement doesID - Auto-generated UUID for uniquenessSpec - Declarative definition of the operationParams - Required parameters (auto-derived from spec)Tags - Optional metadata for categorization",{"id":124,"title":27,"titles":125,"content":126,"level":40},"/v1.0.3/learn/concepts#statement-types",[101,120],"TypeConstructorReturnsUse CaseQueryStatementNewQueryStatement[]*TMulti-record retrievalSelectStatementNewSelectStatement*TSingle-record retrievalUpdateStatementNewUpdateStatement*TModify and return recordDeleteStatementNewDeleteStatementint64Remove records, return countAggregateStatementNewAggregateStatementfloat64COUNT, SUM, AVG, MIN, MAX",{"id":128,"title":129,"titles":130,"content":131,"level":40},"/v1.0.3/learn/concepts#defining-statements","Defining Statements",[101,120],"// Query statement\nvar ByStatus = edamame.NewQueryStatement(\"by-status\", \"Find users by status\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"status\", Operator: \"=\", Param: \"status\"},\n    },\n}, \"user\", \"filter\") // Optional tags\n\n// Select statement\nvar ByEmail = edamame.NewSelectStatement(\"by-email\", \"Find user by email\", edamame.SelectSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"email\", Operator: \"=\", Param: \"email\"},\n    },\n})\n\n// Update statement\nvar Activate = edamame.NewUpdateStatement(\"activate\", \"Activate a user by ID\", edamame.UpdateSpec{\n    Set: map[string]string{\"active\": \"active\"},\n    Where: []edamame.ConditionSpec{\n        {Field: \"id\", Operator: \"=\", Param: \"id\"},\n    },\n})\n\n// Delete statement\nvar DeleteByID = edamame.NewDeleteStatement(\"delete-by-id\", \"Delete user by ID\", edamame.DeleteSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"id\", Operator: \"=\", Param: \"id\"},\n    },\n})\n\n// Aggregate statement\nvar AvgAge = edamame.NewAggregateStatement(\"avg-age\", \"Average age of all users\", edamame.AggAvg, edamame.AggregateSpec{\n    Field: \"age\",\n})",{"id":133,"title":134,"titles":135,"content":136,"level":40},"/v1.0.3/learn/concepts#statement-metadata","Statement Metadata",[101,120],"Inspect statement properties: fmt.Println(ByStatus.Name())        // \"by-status\"\nfmt.Println(ByStatus.Description()) // \"Find users by status\"\nfmt.Println(ByStatus.ID())          // UUID\nfmt.Println(ByStatus.Tags())        // [\"user\", \"filter\"]\n\nfor _, p := range ByStatus.Params() {\n    fmt.Printf(\"Param: %s (type: %s, required: %v)\\n\", p.Name, p.Type, p.Required)\n}",{"id":138,"title":139,"titles":140,"content":141,"level":19},"/v1.0.3/learn/concepts#specs","Specs",[101],"A spec is a declarative definition of a database operation. Specs are pure data—no SQL strings, no builder calls.",{"id":143,"title":144,"titles":145,"content":146,"level":40},"/v1.0.3/learn/concepts#queryspec","QuerySpec",[101,139],"For multi-record retrieval: spec := edamame.QuerySpec{\n    Fields:     []string{\"id\", \"name\", \"email\"},  // SELECT columns (empty = all)\n    Where:      []edamame.ConditionSpec{...},     // WHERE clauses\n    OrderBy:    []edamame.OrderBySpec{...},       // ORDER BY clauses\n    GroupBy:    []string{\"status\"},               // GROUP BY columns\n    Having:     []edamame.ConditionSpec{...},     // HAVING clauses\n    Limit:      &limit,                           // LIMIT\n    Offset:     &offset,                          // OFFSET\n    Distinct:   true,                             // SELECT DISTINCT\n    ForLocking: \"update\",                         // FOR UPDATE/SHARE\n}",{"id":148,"title":149,"titles":150,"content":151,"level":40},"/v1.0.3/learn/concepts#selectspec","SelectSpec",[101,139],"For single-record retrieval (same structure as QuerySpec): spec := edamame.SelectSpec{\n    Fields:     []string{\"id\", \"name\"},\n    Where:      []edamame.ConditionSpec{...},\n    ForLocking: \"share\",\n}",{"id":153,"title":154,"titles":155,"content":156,"level":40},"/v1.0.3/learn/concepts#updatespec","UpdateSpec",[101,139],"For modifications: spec := edamame.UpdateSpec{\n    Set: map[string]string{\n        \"name\":   \"new_name\",    // field -> param mapping\n        \"status\": \"new_status\",\n    },\n    Where: []edamame.ConditionSpec{...},\n}",{"id":158,"title":159,"titles":160,"content":161,"level":40},"/v1.0.3/learn/concepts#deletespec","DeleteSpec",[101,139],"For deletions: spec := edamame.DeleteSpec{\n    Where: []edamame.ConditionSpec{...},\n}",{"id":163,"title":164,"titles":165,"content":166,"level":40},"/v1.0.3/learn/concepts#aggregatespec","AggregateSpec",[101,139],"For aggregate functions: spec := edamame.AggregateSpec{\n    Field: \"age\",                           // Field to aggregate\n    Where: []edamame.ConditionSpec{...},    // Optional filter\n} Use with AggCount, AggSum, AggAvg, AggMin, or AggMax.",{"id":168,"title":169,"titles":170,"content":171,"level":19},"/v1.0.3/learn/concepts#conditions","Conditions",[101],"Conditions define WHERE clauses. They can be simple or grouped.",{"id":173,"title":174,"titles":175,"content":176,"level":40},"/v1.0.3/learn/concepts#simple-conditions","Simple Conditions",[101,169],"cond := edamame.ConditionSpec{\n    Field:    \"age\",\n    Operator: \">=\",\n    Param:    \"min_age\",\n}",{"id":178,"title":179,"titles":180,"content":181,"level":40},"/v1.0.3/learn/concepts#null-conditions","NULL Conditions",[101,169],"// IS NULL\ncond := edamame.ConditionSpec{\n    Field:    \"deleted_at\",\n    IsNull:   true,\n    Operator: \"IS NULL\",\n}\n\n// IS NOT NULL\ncond := edamame.ConditionSpec{\n    Field:    \"email\",\n    IsNull:   true,\n    Operator: \"IS NOT NULL\",\n}",{"id":183,"title":184,"titles":185,"content":186,"level":40},"/v1.0.3/learn/concepts#grouped-conditions-or","Grouped Conditions (OR)",[101,169],"cond := edamame.ConditionSpec{\n    Logic: \"OR\",\n    Group: []edamame.ConditionSpec{\n        {Field: \"status\", Operator: \"=\", Param: \"status1\"},\n        {Field: \"status\", Operator: \"=\", Param: \"status2\"},\n    },\n}",{"id":188,"title":189,"titles":190,"content":191,"level":40},"/v1.0.3/learn/concepts#supported-operators","Supported Operators",[101,169],"OperatorDescription=Equal!=, \u003C>Not equal\u003C, \u003C=Less than>, >=Greater thanLIKE, ILIKEPattern matchingINValue in listIS NULLNULL checkIS NOT NULLNOT NULL check",{"id":193,"title":194,"titles":195,"content":196,"level":19},"/v1.0.3/learn/concepts#ordering","Ordering",[101],"order := edamame.OrderBySpec{\n    Field:     \"created_at\",\n    Direction: \"desc\",      // \"asc\" or \"desc\"\n    Nulls:     \"last\",      // \"first\" or \"last\" (optional)\n}",{"id":198,"title":199,"titles":200,"content":201,"level":40},"/v1.0.3/learn/concepts#expression-based-ordering","Expression-Based Ordering",[101,194],"For vector similarity or computed distances: order := edamame.OrderBySpec{\n    Field:     \"embedding\",\n    Operator:  \"\u003C->\",           // pgvector distance operator\n    Param:     \"query_vector\",\n    Direction: \"asc\",\n}",{"id":203,"title":204,"titles":205,"content":206,"level":19},"/v1.0.3/learn/concepts#execution","Execution",[101],"Execute statements with params: // Query (multiple records)\nusers, err := exec.ExecQuery(ctx, ByStatus, map[string]any{\n    \"status\": \"active\",\n})\n\n// Select (single record)\nuser, err := exec.ExecSelect(ctx, ByEmail, map[string]any{\n    \"email\": \"alice@example.com\",\n})\n\n// Update\nupdated, err := exec.ExecUpdate(ctx, Activate, map[string]any{\n    \"id\":     123,\n    \"active\": true,\n})\n\n// Delete\ncount, err := exec.ExecDelete(ctx, DeleteByID, map[string]any{\n    \"id\": 123,\n})\n\n// Aggregate\navg, err := exec.ExecAggregate(ctx, AvgAge, nil)\n\n// Insert (no statement needed)\ninserted, err := exec.ExecInsert(ctx, &user)",{"id":208,"title":209,"titles":210,"content":211,"level":40},"/v1.0.3/learn/concepts#transaction-support","Transaction Support",[101,204],"All execution methods have *Tx variants: tx, err := db.BeginTxx(ctx, nil)\n\nuser, err := exec.ExecSelectTx(ctx, tx, SelectByID, params)\n_, err = exec.ExecUpdateTx(ctx, tx, Activate, params)\n\ntx.Commit()",{"id":213,"title":214,"titles":215,"content":216,"level":40},"/v1.0.3/learn/concepts#batch-operations","Batch Operations",[101,204],"// Batch insert\ncount, err := exec.ExecInsertBatch(ctx, users)\n\n// Batch update\ncount, err := exec.ExecUpdateBatch(ctx, Activate, []map[string]any{\n    {\"id\": 1, \"active\": true},\n    {\"id\": 2, \"active\": true},\n}) html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":218,"title":16,"titles":219,"content":220,"level":9},"/v1.0.3/learn/architecture",[],"How edamame works with soy for SQL generation",{"id":222,"title":16,"titles":223,"content":224,"level":9},"/v1.0.3/learn/architecture#architecture",[],"Edamame is a semantic layer over soy. Understanding this relationship helps you use both effectively.",{"id":226,"title":227,"titles":228,"content":229,"level":19},"/v1.0.3/learn/architecture#layer-diagram","Layer Diagram",[16],"┌─────────────────────────────────────────────────────────────┐\n│                      Your Application                       │\n│                                                             │\n│   exec.ExecQuery(ctx, ByStatus, params)                     │\n└─────────────────────────┬───────────────────────────────────┘\n                          │\n┌─────────────────────────▼───────────────────────────────────┐\n│                         Edamame                             │\n│                                                             │\n│  ┌──────────────┐  Typed statements                         │\n│  │ Executor[T]  │  Spec → Builder conversion                │\n│  │              │  Event emission (capitan)                 │\n│  └──────┬───────┘                                           │\n│         │                                                   │\n│  ┌──────▼───────────────────────────────────────────────┐   │\n│  │                  Statement Types                      │   │\n│  │  QueryStatement  SelectStatement  UpdateStatement     │   │\n│  │  DeleteStatement  AggregateStatement                  │   │\n│  └──────────────────────────────────────────────────────┘   │\n└─────────┬───────────────────────────────────────────────────┘\n          │\n┌─────────▼───────────────────────────────────────────────────┐\n│                          Soy                                │\n│                                                             │\n│  Query builder API                                          │\n│  Field validation (via ASTQL)                               │\n│  Parameterized SQL generation                               │\n│  Render() → {SQL, Params}                                   │\n└─────────┬───────────────────────────────────────────────────┘\n          │\n┌─────────▼───────────────────────────────────────────────────┐\n│                          sqlx                               │\n│                                                             │\n│  Connection pooling                                         │\n│  Named parameter binding                                    │\n│  Struct scanning                                            │\n└─────────────────────────────────────────────────────────────┘",{"id":231,"title":232,"titles":233,"content":34,"level":19},"/v1.0.3/learn/architecture#responsibilities","Responsibilities",[16],{"id":235,"title":236,"titles":237,"content":238,"level":40},"/v1.0.3/learn/architecture#edamame","Edamame",[16,232],"Typed statements - Compile-time safe query definitionsSpec-to-builder conversion - Transform declarative specs into soy buildersExecution wrappers - Convenient Exec* methods with paramsEvents - Emit executor lifecycle events via capitan",{"id":240,"title":241,"titles":242,"content":243,"level":40},"/v1.0.3/learn/architecture#soy","Soy",[16,232],"Query building - Fluent API for constructing SQLField validation - Validate field names against model metadataOperator validation - Ensure operators are safe and validSQL generation - Render builders to parameterized SQLExecution - Execute queries via sqlx",{"id":245,"title":246,"titles":247,"content":248,"level":40},"/v1.0.3/learn/architecture#when-to-use-each","When to Use Each",[16,232],"TaskUseDefine named operationsStatement typesExecute named operationsexec.Exec* methodsAd-hoc queriesexec.Soy().Query()...Custom SQL constructionSoy builder API",{"id":250,"title":251,"titles":252,"content":253,"level":19},"/v1.0.3/learn/architecture#spec-to-builder-flow","Spec-to-Builder Flow",[16],"When you call exec.ExecQuery(ctx, ByStatus, params): Extract spec - Statement contains the spec internallyConvert - Spec is converted to a soy builder:\n// QuerySpec → soy.Query[T]\nbuilder := exec.queryFromSpec(stmt.spec)\nRender - Builder generates SQL:\nresult, err := builder.Render()\n// result.SQL = \"SELECT ... FROM users WHERE status = $1\"\n// result.Params = []any{\"active\"}\nExecute - sqlx runs the parameterized query:\nrows, err := db.QueryxContext(ctx, result.SQL, result.Params...)\nScan - Results are scanned into structs",{"id":255,"title":256,"titles":257,"content":258,"level":19},"/v1.0.3/learn/architecture#security-model","Security Model",[16],"SQL injection protection flows through the entire stack: Edamame - Specs are data, not SQL stringsSoy - Field names validated against model metadataSoy - Operators validated against allowlistSoy - All values become bound parameterssqlx - Parameters passed separately from SQL // User input\nparams := map[string]any{\"status\": userInput}\n\n// Never interpolated into SQL\nexec.ExecQuery(ctx, ByStatus, params)\n\n// Becomes:\n// SQL: \"SELECT ... WHERE status = $1\"\n// Args: [userInput]  // Bound separately",{"id":260,"title":261,"titles":262,"content":263,"level":19},"/v1.0.3/learn/architecture#event-integration","Event Integration",[16],"Edamame emits events via capitan for observability: SignalWhenFieldsExecutorCreatedExecutor initializedtable Hook for monitoring: capitan.Hook(edamame.ExecutorCreated, func(ctx context.Context, e *capitan.Event) {\n    table, _ := edamame.KeyTable.From(e)\n    log.Printf(\"Executor created for table: %s\", table)\n})",{"id":265,"title":266,"titles":267,"content":268,"level":19},"/v1.0.3/learn/architecture#direct-soy-access","Direct Soy Access",[16],"For operations not covered by statements, access soy directly: // Get the underlying soy instance\ns := exec.Soy()\n\n// Use soy's fluent API\nusers, err := s.Query().\n    Where(\"age\", \">=\", \"min_age\").\n    Where(\"status\", \"=\", \"status\").\n    OrderBy(\"name\", \"asc\").\n    Limit(10).\n    Exec(ctx, params) This bypasses statement types but still benefits from: Field validationParameterized queriesType-safe results",{"id":270,"title":37,"titles":271,"content":272,"level":19},"/v1.0.3/learn/architecture#type-safety",[16],"Statements provide compile-time guarantees: // Compiler enforces correct statement types\nusers, err := exec.ExecQuery(ctx, QueryAll, nil)       // Must be QueryStatement\nuser, err := exec.ExecSelect(ctx, SelectByID, params)  // Must be SelectStatement\ncount, err := exec.ExecAggregate(ctx, CountAll, nil)   // Must be AggregateStatement\n\n// This won't compile:\n// exec.ExecQuery(ctx, SelectByID, nil)  // SelectStatement not allowed No magic strings, no runtime lookup failures. html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}",{"id":274,"title":120,"titles":275,"content":276,"level":9},"/v1.0.3/guides/statements",[],"Defining and using typed database statements",{"id":278,"title":120,"titles":279,"content":280,"level":9},"/v1.0.3/guides/statements#statements",[],"This guide covers defining typed statements for your database operations.",{"id":282,"title":283,"titles":284,"content":285,"level":19},"/v1.0.3/guides/statements#queries","Queries",[120],"Queries return multiple records. Use for lists, search results, and filtered collections.",{"id":287,"title":288,"titles":289,"content":290,"level":40},"/v1.0.3/guides/statements#basic-query","Basic Query",[120,283],"var ActiveUsers = edamame.NewQueryStatement(\"active-users\", \"Find all active users\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"active\", Operator: \"=\", Param: \"active\"},\n    },\n})\n\n// Usage\nusers, err := exec.ExecQuery(ctx, ActiveUsers, map[string]any{\n    \"active\": true,\n})",{"id":292,"title":293,"titles":294,"content":295,"level":40},"/v1.0.3/guides/statements#with-ordering-and-pagination","With Ordering and Pagination",[120,283],"limit := 20\noffset := 0\n\nvar RecentUsers = edamame.NewQueryStatement(\"recent-users\", \"Get users ordered by creation date\", edamame.QuerySpec{\n    OrderBy: []edamame.OrderBySpec{\n        {Field: \"created_at\", Direction: \"desc\"},\n    },\n    Limit:  &limit,\n    Offset: &offset,\n})",{"id":297,"title":298,"titles":299,"content":300,"level":40},"/v1.0.3/guides/statements#with-field-selection","With Field Selection",[120,283],"var UserNames = edamame.NewQueryStatement(\"user-names\", \"Get user names only\", edamame.QuerySpec{\n    Fields: []string{\"id\", \"name\"},  // Only select these columns\n})",{"id":302,"title":303,"titles":304,"content":305,"level":40},"/v1.0.3/guides/statements#with-grouping","With Grouping",[120,283],"var UsersByRole = edamame.NewQueryStatement(\"users-by-role\", \"Group users by role\", edamame.QuerySpec{\n    Fields:  []string{\"role\", \"COUNT(*) as count\"},\n    GroupBy: []string{\"role\"},\n})",{"id":307,"title":308,"titles":309,"content":310,"level":40},"/v1.0.3/guides/statements#having-with-aggregates","HAVING with Aggregates",[120,283],"Use HavingAgg for aggregate conditions in HAVING clauses: var PopularRoles = edamame.NewQueryStatement(\"popular-roles\", \"Roles with minimum user count\", edamame.QuerySpec{\n    Fields:  []string{\"role\"},\n    GroupBy: []string{\"role\"},\n    HavingAgg: []edamame.HavingAggSpec{\n        {Func: \"count\", Field: \"*\", Operator: \">=\", Param: \"min_count\"},\n    },\n})\n\n// Generates: SELECT role FROM users GROUP BY role HAVING COUNT(*) >= $1 Multiple aggregate conditions: var HighValueRoles = edamame.NewQueryStatement(\"high-value-roles\", \"Roles with high balance and count\", edamame.QuerySpec{\n    Fields:  []string{\"role\"},\n    GroupBy: []string{\"role\"},\n    HavingAgg: []edamame.HavingAggSpec{\n        {Func: \"count\", Field: \"*\", Operator: \">=\", Param: \"min_count\"},\n        {Func: \"sum\", Field: \"balance\", Operator: \">=\", Param: \"min_total\"},\n    },\n})",{"id":312,"title":313,"titles":314,"content":315,"level":40},"/v1.0.3/guides/statements#distinct-on-postgresql","DISTINCT ON (PostgreSQL)",[120,283],"Use DistinctOn for PostgreSQL's DISTINCT ON clause: var LatestPerUser = edamame.NewQueryStatement(\"latest-per-user\", \"Latest record per user\", edamame.QuerySpec{\n    DistinctOn: []string{\"user_id\"},\n    OrderBy: []edamame.OrderBySpec{\n        {Field: \"user_id\", Direction: \"asc\"},\n        {Field: \"created_at\", Direction: \"desc\"},\n    },\n})\n\n// Generates: SELECT DISTINCT ON (user_id) * FROM ... ORDER BY user_id ASC, created_at DESC",{"id":317,"title":318,"titles":319,"content":320,"level":40},"/v1.0.3/guides/statements#complex-conditions","Complex Conditions",[120,283],"var FilteredUsers = edamame.NewQueryStatement(\"filtered-users\", \"Filter users by age and role\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        {Field: \"age\", Operator: \"\u003C=\", Param: \"max_age\"},\n        {\n            Logic: \"OR\",\n            Group: []edamame.ConditionSpec{\n                {Field: \"role\", Operator: \"=\", Param: \"role1\"},\n                {Field: \"role\", Operator: \"=\", Param: \"role2\"},\n            },\n        },\n    },\n})\n\n// Generates: WHERE age >= $1 AND age \u003C= $2 AND (role = $3 OR role = $4)",{"id":322,"title":323,"titles":324,"content":325,"level":40},"/v1.0.3/guides/statements#between-conditions","BETWEEN Conditions",[120,283],"var UsersInAgeRange = edamame.NewQueryStatement(\"users-in-age-range\", \"Users in age range\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"age\", Between: true, LowParam: \"min_age\", HighParam: \"max_age\"},\n    },\n})\n\n// Generates: WHERE age BETWEEN $1 AND $2\n\n// NOT BETWEEN\nvar UsersOutsideRange = edamame.NewQueryStatement(\"users-outside-range\", \"Users outside age range\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"age\", NotBetween: true, LowParam: \"min_age\", HighParam: \"max_age\"},\n    },\n})\n\n// Generates: WHERE age NOT BETWEEN $1 AND $2",{"id":327,"title":328,"titles":329,"content":330,"level":40},"/v1.0.3/guides/statements#field-to-field-comparisons","Field-to-Field Comparisons",[120,283],"Compare two columns directly without parameters: var ModifiedAfterCreated = edamame.NewQueryStatement(\"modified-after-created\", \"Records updated after creation\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"updated_at\", Operator: \">\", RightField: \"created_at\"},\n    },\n})\n\n// Generates: WHERE updated_at > created_at",{"id":332,"title":333,"titles":334,"content":335,"level":40},"/v1.0.3/guides/statements#parameterized-pagination","Parameterized Pagination",[120,283],"Use parameter-driven limits and offsets for flexible pagination: var PaginatedUsers = edamame.NewQueryStatement(\"paginated-users\", \"Paginated user list\", edamame.QuerySpec{\n    LimitParam:  \"page_size\",\n    OffsetParam: \"offset\",\n    OrderBy: []edamame.OrderBySpec{\n        {Field: \"created_at\", Direction: \"desc\"},\n    },\n})\n\n// Usage\nusers, err := exec.ExecQuery(ctx, PaginatedUsers, map[string]any{\n    \"page_size\": 20,\n    \"offset\":    40,  // Page 3\n})",{"id":337,"title":338,"titles":339,"content":340,"level":40},"/v1.0.3/guides/statements#select-expressions","Select Expressions",[120,283],"Add computed columns using SQL functions: var UsersWithComputed = edamame.NewQueryStatement(\"users-with-computed\", \"Users with computed columns\", edamame.QuerySpec{\n    Fields: []string{\"id\", \"name\"},\n    SelectExprs: []edamame.SelectExprSpec{\n        {Func: \"upper\", Field: \"name\", Alias: \"upper_name\"},\n        {Func: \"length\", Field: \"email\", Alias: \"email_length\"},\n        {Func: \"count_star\", Alias: \"total\"},\n        {Func: \"now\", Alias: \"query_time\"},\n    },\n    GroupBy: []string{\"id\", \"name\"},\n}) Available functions include: upper, lower, length, trim, concat, abs, ceil, floor, round, now, current_date, cast, count, sum, avg, min, max, coalesce, nullif.",{"id":342,"title":343,"titles":344,"content":345,"level":40},"/v1.0.3/guides/statements#with-row-locking","With Row Locking",[120,283],"var ForUpdate = edamame.NewQueryStatement(\"for-update\", \"Query with row lock\", edamame.QuerySpec{\n    Where:      []edamame.ConditionSpec{{Field: \"status\", Operator: \"=\", Param: \"status\"}},\n    ForLocking: \"update\",  // FOR UPDATE\n}) Locking options: \"update\", \"no_key_update\", \"share\", \"key_share\"",{"id":347,"title":348,"titles":349,"content":350,"level":19},"/v1.0.3/guides/statements#selects","Selects",[120],"Selects return a single record. Use for lookups by unique identifier.",{"id":352,"title":353,"titles":354,"content":355,"level":40},"/v1.0.3/guides/statements#by-unique-field","By Unique Field",[120,348],"var ByEmail = edamame.NewSelectStatement(\"by-email\", \"Find user by email address\", edamame.SelectSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"email\", Operator: \"=\", Param: \"email\"},\n    },\n})\n\n// Usage - returns error if not found\nuser, err := exec.ExecSelect(ctx, ByEmail, map[string]any{\n    \"email\": \"alice@example.com\",\n})",{"id":357,"title":358,"titles":359,"content":360,"level":40},"/v1.0.3/guides/statements#with-locking","With Locking",[120,348],"var ForShare = edamame.NewSelectStatement(\"for-share\", \"Select with shared lock\", edamame.SelectSpec{\n    Where:      []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    ForLocking: \"share\",  // FOR SHARE\n})",{"id":362,"title":363,"titles":364,"content":365,"level":19},"/v1.0.3/guides/statements#updates","Updates",[120],"Updates modify records and return the updated row.",{"id":367,"title":368,"titles":369,"content":370,"level":40},"/v1.0.3/guides/statements#single-field-update","Single Field Update",[120,363],"var Activate = edamame.NewUpdateStatement(\"activate\", \"Activate a user by ID\", edamame.UpdateSpec{\n    Set: map[string]string{\n        \"active\": \"active\",  // field -> param\n    },\n    Where: []edamame.ConditionSpec{\n        {Field: \"id\", Operator: \"=\", Param: \"id\"},\n    },\n})\n\n// Usage\nupdated, err := exec.ExecUpdate(ctx, Activate, map[string]any{\n    \"id\":     123,\n    \"active\": true,\n})",{"id":372,"title":373,"titles":374,"content":375,"level":40},"/v1.0.3/guides/statements#multi-field-update","Multi-Field Update",[120,363],"var UpdateProfile = edamame.NewUpdateStatement(\"update-profile\", \"Update user profile\", edamame.UpdateSpec{\n    Set: map[string]string{\n        \"name\":  \"new_name\",\n        \"email\": \"new_email\",\n        \"bio\":   \"new_bio\",\n    },\n    Where: []edamame.ConditionSpec{\n        {Field: \"id\", Operator: \"=\", Param: \"id\"},\n    },\n})",{"id":377,"title":378,"titles":379,"content":380,"level":40},"/v1.0.3/guides/statements#batch-updates","Batch Updates",[120,363],"// Execute same update with different params\ncount, err := exec.ExecUpdateBatch(ctx, Activate, []map[string]any{\n    {\"id\": 1, \"active\": true},\n    {\"id\": 2, \"active\": true},\n    {\"id\": 3, \"active\": false},\n})",{"id":382,"title":383,"titles":384,"content":385,"level":19},"/v1.0.3/guides/statements#deletes","Deletes",[120],"Deletes remove records and return the count of deleted rows.",{"id":387,"title":388,"titles":389,"content":390,"level":40},"/v1.0.3/guides/statements#by-single-field","By Single Field",[120,383],"var ByStatus = edamame.NewDeleteStatement(\"by-status\", \"Delete all users with given status\", edamame.DeleteSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"status\", Operator: \"=\", Param: \"status\"},\n    },\n})\n\n// Usage\ncount, err := exec.ExecDelete(ctx, ByStatus, map[string]any{\n    \"status\": \"inactive\",\n})",{"id":392,"title":393,"titles":394,"content":395,"level":40},"/v1.0.3/guides/statements#with-multiple-conditions","With Multiple Conditions",[120,383],"var ExpiredSessions = edamame.NewDeleteStatement(\"expired-sessions\", \"Delete expired sessions\", edamame.DeleteSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"expires_at\", Operator: \"\u003C\", Param: \"now\"},\n        {Field: \"active\", Operator: \"=\", Param: \"active\"},\n    },\n})",{"id":397,"title":398,"titles":399,"content":400,"level":19},"/v1.0.3/guides/statements#aggregates","Aggregates",[120],"Aggregates compute values across records.",{"id":402,"title":403,"titles":404,"content":405,"level":40},"/v1.0.3/guides/statements#count","Count",[120,398],"var CountActive = edamame.NewAggregateStatement(\"count-active\", \"Count active users\", edamame.AggCount, edamame.AggregateSpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"active\", Operator: \"=\", Param: \"active\"},\n    },\n})\n\ncount, err := exec.ExecAggregate(ctx, CountActive, map[string]any{\n    \"active\": true,\n})",{"id":407,"title":408,"titles":409,"content":410,"level":40},"/v1.0.3/guides/statements#sum-avg-min-max","Sum, Avg, Min, Max",[120,398],"// Sum\nvar TotalBalance = edamame.NewAggregateStatement(\"total-balance\", \"Total balance\", edamame.AggSum, edamame.AggregateSpec{\n    Field: \"balance\",\n})\n\n// Average\nvar AvgAge = edamame.NewAggregateStatement(\"avg-age\", \"Average age\", edamame.AggAvg, edamame.AggregateSpec{\n    Field: \"age\",\n})\n\n// Min/Max\nvar Youngest = edamame.NewAggregateStatement(\"youngest\", \"Youngest user\", edamame.AggMin, edamame.AggregateSpec{\n    Field: \"age\",\n})",{"id":412,"title":413,"titles":414,"content":415,"level":19},"/v1.0.3/guides/statements#inserts","Inserts",[120],"Inserts don't use statements - they're driven by struct fields: // Single insert\ninserted, err := exec.ExecInsert(ctx, &user)\n\n// Batch insert\ncount, err := exec.ExecInsertBatch(ctx, users)",{"id":417,"title":418,"titles":419,"content":420,"level":40},"/v1.0.3/guides/statements#with-conflict-handling","With Conflict Handling",[120,413],"For upsert patterns, use the underlying soy API: s := exec.Soy()\n\n// ON CONFLICT DO NOTHING\nresult, err := s.Insert().\n    OnConflictDoNothing(\"email\").\n    Exec(ctx, &user)\n\n// ON CONFLICT DO UPDATE\nresult, err := s.Insert().\n    OnConflict(\"email\").\n    DoUpdate(map[string]string{\"name\": \"name\"}).\n    Exec(ctx, &user)",{"id":422,"title":423,"titles":424,"content":425,"level":19},"/v1.0.3/guides/statements#compound-queries","Compound Queries",[120],"Compound queries combine multiple SELECT statements using set operations.",{"id":427,"title":428,"titles":429,"content":430,"level":40},"/v1.0.3/guides/statements#union","UNION",[120,423],"spec := edamame.CompoundQuerySpec{\n    Base: edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"role\", Operator: \"=\", Param: \"role1\"},\n        },\n    },\n    Operands: []edamame.CompoundOperand{\n        {\n            Operation: \"union\",\n            Query: edamame.QuerySpec{\n                Where: []edamame.ConditionSpec{\n                    {Field: \"role\", Operator: \"=\", Param: \"role2\"},\n                },\n            },\n        },\n    },\n    OrderBy: []edamame.OrderBySpec{\n        {Field: \"name\", Direction: \"asc\"},\n    },\n}\n\nusers, err := exec.ExecCompound(ctx, spec, map[string]any{\n    \"role1\": \"admin\",\n    \"role2\": \"moderator\",\n})",{"id":432,"title":433,"titles":434,"content":435,"level":40},"/v1.0.3/guides/statements#available-operations","Available Operations",[120,423],"OperationDescriptionunionCombine results, remove duplicatesunion_allCombine results, keep duplicatesintersectOnly rows in both queriesintersect_allIntersection with duplicatesexceptRows in first but not secondexcept_allExcept with duplicates",{"id":437,"title":438,"titles":439,"content":440,"level":40},"/v1.0.3/guides/statements#rendering-for-inspection","Rendering for Inspection",[120,423],"sql, err := exec.RenderCompound(spec)\n// SELECT ... WHERE role = $1 UNION SELECT ... WHERE role = $2 ORDER BY name ASC",{"id":442,"title":134,"titles":443,"content":136,"level":19},"/v1.0.3/guides/statements#statement-metadata",[120],{"id":445,"title":446,"titles":447,"content":448,"level":19},"/v1.0.3/guides/statements#tags","Tags",[120],"Statements support optional tags for categorization: var ByRole = edamame.NewQueryStatement(\"by-role\", \"Find users by role\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"role\", Operator: \"=\", Param: \"role\"},\n    },\n}, \"user\", \"filter\", \"security\")  // Tags as variadic args",{"id":450,"title":451,"titles":452,"content":453,"level":19},"/v1.0.3/guides/statements#parameter-derivation","Parameter Derivation",[120],"Params are automatically derived from specs: var Example = edamame.NewQueryStatement(\"example\", \"Example query\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{\n        {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        {Field: \"status\", Operator: \"=\", Param: \"status\"},\n    },\n})\n\n// Params auto-derived:\n// - min_age (required)\n// - status (required)\n\nfor _, p := range Example.Params() {\n    fmt.Printf(\"Param: %s (required: %v)\\n\", p.Name, p.Required)\n} html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}",{"id":455,"title":456,"titles":457,"content":458,"level":9},"/v1.0.3/guides/testing","Testing",[],"Testing strategies for edamame-based applications",{"id":460,"title":456,"titles":461,"content":462,"level":9},"/v1.0.3/guides/testing#testing",[],"Edamame provides testing utilities in the github.com/zoobz-io/edamame/testing package.",{"id":464,"title":465,"titles":466,"content":34,"level":19},"/v1.0.3/guides/testing#test-helpers","Test Helpers",[456],{"id":468,"title":469,"titles":470,"content":471,"level":40},"/v1.0.3/guides/testing#querycapture","QueryCapture",[456,465],"Capture rendered SQL for verification: import (\n    edamametesting \"github.com/zoobz-io/edamame/testing\"\n    \"github.com/zoobz-io/astql/pkg/postgres\"\n)\n\nfunc TestQueryRendering(t *testing.T) {\n    capture := edamametesting.NewQueryCapture()\n\n    exec, _ := edamame.New[User](nil, \"users\", postgres.New())\n\n    // Define a statement\n    var ByStatus = edamame.NewQueryStatement(\"by-status\", \"Find by status\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{{Field: \"status\", Operator: \"=\", Param: \"status\"}},\n    })\n\n    // Get the builder and render\n    q, _ := exec.Query(ByStatus)\n    result, _ := q.Render()\n\n    capture.CaptureQuery(\"by-status\", \"query\", result.SQL, nil)\n\n    // Verify\n    if capture.Count() != 1 {\n        t.Errorf(\"expected 1 query, got %d\", capture.Count())\n    }\n\n    last := capture.Last()\n    if last.Type != \"query\" {\n        t.Errorf(\"expected type 'query', got %q\", last.Type)\n    }\n}",{"id":473,"title":474,"titles":475,"content":476,"level":40},"/v1.0.3/guides/testing#executoreventcapture","ExecutorEventCapture",[456,465],"Capture executor creation events via capitan: func TestExecutorEvents(t *testing.T) {\n    c := capitan.New(capitan.WithSyncMode())\n    defer c.Shutdown()\n\n    capture := edamametesting.NewExecutorEventCapture()\n    c.Hook(edamame.ExecutorCreated, capture.Handler())\n\n    exec, _ := edamame.New[User](nil, \"users\", postgres.New())\n\n    // Verify event captured\n    if capture.Count() != 1 {\n        t.Error(\"expected executor created event\")\n    }\n\n    tables := capture.Tables()\n    if tables[0].Table != \"users\" {\n        t.Errorf(\"expected table 'users', got %q\", tables[0].Table)\n    }\n}",{"id":478,"title":479,"titles":480,"content":481,"level":40},"/v1.0.3/guides/testing#parambuilder","ParamBuilder",[456,465],"Build test parameters fluently: func TestWithParams(t *testing.T) {\n    params := edamametesting.NewParamBuilder().\n        Set(\"id\", 123).\n        Set(\"status\", \"active\").\n        Set(\"limit\", 10).\n        Build()\n\n    var Filtered = edamame.NewQueryStatement(\"filtered\", \"Filtered query\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{{Field: \"status\", Operator: \"=\", Param: \"status\"}},\n    })\n\n    // Use in tests\n    users, err := exec.ExecQuery(ctx, Filtered, params)\n}",{"id":483,"title":484,"titles":485,"content":486,"level":19},"/v1.0.3/guides/testing#unit-testing-without-database","Unit Testing Without Database",[456],"Test statement creation and specs without a database: func TestStatements(t *testing.T) {\n    // nil db is valid for testing statements\n    exec, err := edamame.New[User](nil, \"users\", postgres.New())\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Define statements\n    var QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all\", edamame.QuerySpec{})\n\n    var ByStatus = edamame.NewQueryStatement(\"by-status\", \"Find by status\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"status\", Operator: \"=\", Param: \"status\"},\n        },\n    })\n\n    // Test statement metadata\n    if ByStatus.Name() != \"by-status\" {\n        t.Errorf(\"expected name 'by-status', got %q\", ByStatus.Name())\n    }\n\n    // Test params derived correctly\n    params := ByStatus.Params()\n    if len(params) != 1 || params[0].Name != \"status\" {\n        t.Error(\"expected 1 param named 'status'\")\n    }\n\n    // Test builder creation\n    q, err := exec.Query(ByStatus)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Test rendering\n    result, err := q.Render()\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    if result.SQL == \"\" {\n        t.Error(\"empty SQL rendered\")\n    }\n}",{"id":488,"title":489,"titles":490,"content":491,"level":19},"/v1.0.3/guides/testing#testing-sql-rendering","Testing SQL Rendering",[456],"Verify generated SQL without executing: func TestSQLRendering(t *testing.T) {\n    exec, _ := edamame.New[User](nil, \"users\", postgres.New())\n\n    var Adults = edamame.NewQueryStatement(\"adults\", \"Find adults\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        },\n        OrderBy: []edamame.OrderBySpec{\n            {Field: \"name\", Direction: \"asc\"},\n        },\n    })\n\n    q, _ := exec.Query(Adults)\n    result, err := q.Render()\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Verify SQL structure\n    if !strings.Contains(result.SQL, \"WHERE\") {\n        t.Error(\"SQL missing WHERE clause\")\n    }\n    if !strings.Contains(result.SQL, \"ORDER BY\") {\n        t.Error(\"SQL missing ORDER BY clause\")\n    }\n}",{"id":493,"title":494,"titles":495,"content":496,"level":19},"/v1.0.3/guides/testing#integration-testing-with-testcontainers","Integration Testing with Testcontainers",[456],"For database integration tests, use testcontainers: //go:build integration\n\npackage integration\n\nimport (\n    \"context\"\n    \"testing\"\n\n    \"github.com/testcontainers/testcontainers-go\"\n    \"github.com/testcontainers/testcontainers-go/wait\"\n)\n\nfunc TestWithPostgres(t *testing.T) {\n    ctx := context.Background()\n\n    // Start PostgreSQL container\n    req := testcontainers.ContainerRequest{\n        Image:        \"postgres:16-alpine\",\n        ExposedPorts: []string{\"5432/tcp\"},\n        WaitingFor:   wait.ForLog(\"database system is ready to accept connections\"),\n        Env: map[string]string{\n            \"POSTGRES_USER\":     \"test\",\n            \"POSTGRES_PASSWORD\": \"test\",\n            \"POSTGRES_DB\":       \"testdb\",\n        },\n    }\n\n    container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{\n        ContainerRequest: req,\n        Started:          true,\n    })\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer container.Terminate(ctx)\n\n    // Get connection details\n    host, _ := container.Host(ctx)\n    port, _ := container.MappedPort(ctx, \"5432\")\n\n    // Connect and test\n    dsn := fmt.Sprintf(\"host=%s port=%s user=test password=test dbname=testdb sslmode=disable\", host, port.Port())\n    db, err := sqlx.Connect(\"postgres\", dsn)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Create table\n    db.ExecContext(ctx, `CREATE TABLE users (\n        id SERIAL PRIMARY KEY,\n        email TEXT NOT NULL UNIQUE,\n        name TEXT,\n        age INTEGER\n    )`)\n\n    // Test executor\n    exec, _ := edamame.New[User](db, \"users\", postgres.New())\n\n    age := 25\n    user := &User{Email: \"test@example.com\", Name: \"Test\", Age: &age}\n    inserted, err := exec.ExecInsert(ctx, user)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    if inserted.ID == 0 {\n        t.Error(\"expected non-zero ID\")\n    }\n} Run integration tests: go test -tags=integration ./testing/integration/...",{"id":498,"title":499,"titles":500,"content":501,"level":19},"/v1.0.3/guides/testing#benchmarking","Benchmarking",[456],"The testing/benchmarks package provides performance benchmarks: func BenchmarkQueryBuilding(b *testing.B) {\n    exec, _ := edamame.New[User](nil, \"users\", postgres.New())\n\n    var QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all\", edamame.QuerySpec{})\n\n    b.ResetTimer()\n    b.ReportAllocs()\n\n    for i := 0; i \u003C b.N; i++ {\n        _, _ = exec.Query(QueryAll)\n    }\n} Run benchmarks: go test ./testing/benchmarks/... -bench=. -benchmem",{"id":503,"title":504,"titles":505,"content":506,"level":19},"/v1.0.3/guides/testing#testing-events","Testing Events",[456],"Verify capitan events are emitted correctly: func TestExecutorEmitsCreatedEvent(t *testing.T) {\n    c := capitan.New(capitan.WithSyncMode())\n    defer c.Shutdown()\n\n    capture := edamametesting.NewExecutorEventCapture()\n    c.Hook(edamame.ExecutorCreated, capture.Handler())\n\n    _, _ = edamame.New[User](nil, \"users\", postgres.New())\n\n    if capture.Count() != 1 {\n        t.Errorf(\"expected 1 executor created event, got %d\", capture.Count())\n    }\n\n    tables := capture.Tables()\n    if tables[0].Table != \"users\" {\n        t.Errorf(\"expected table 'users', got %q\", tables[0].Table)\n    }\n}",{"id":508,"title":509,"titles":510,"content":511,"level":19},"/v1.0.3/guides/testing#testing-transaction-behavior","Testing Transaction Behavior",[456],"func TestTransaction(t *testing.T) {\n    // ... setup db and exec ...\n\n    var QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all\", edamame.QuerySpec{})\n    var SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    tx, _ := db.BeginTxx(ctx, nil)\n\n    // Insert in transaction\n    user := &User{Email: \"tx@test.com\", Name: \"TxTest\"}\n    inserted, err := exec.ExecInsertTx(ctx, tx, user)\n    if err != nil {\n        tx.Rollback()\n        t.Fatal(err)\n    }\n\n    // Verify visible in transaction\n    users, _ := exec.ExecQueryTx(ctx, tx, QueryAll, nil)\n    if len(users) != 1 {\n        t.Error(\"expected 1 user in transaction\")\n    }\n\n    // Rollback\n    tx.Rollback()\n\n    // Verify not visible after rollback\n    users, _ = exec.ExecQuery(ctx, QueryAll, nil)\n    if len(users) != 0 {\n        t.Error(\"expected 0 users after rollback\")\n    }\n}",{"id":513,"title":514,"titles":515,"content":516,"level":19},"/v1.0.3/guides/testing#async-event-testing","Async Event Testing",[456],"Use WaitForCount for async event verification: func TestAsyncEvents(t *testing.T) {\n    c := capitan.New()  // async mode\n    defer c.Shutdown()\n\n    capture := edamametesting.NewExecutorEventCapture()\n    c.Hook(edamame.ExecutorCreated, capture.Handler())\n\n    _, _ = edamame.New[User](nil, \"users\", postgres.New())\n\n    // Wait for async event processing\n    if !capture.WaitForCount(1, 500*time.Millisecond) {\n        t.Error(\"timed out waiting for event\")\n    }\n} html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"id":518,"title":519,"titles":520,"content":521,"level":9},"/v1.0.3/cookbook/llm-integration","LLM Integration",[],"Using edamame statements with AI assistants",{"id":523,"title":519,"titles":524,"content":525,"level":9},"/v1.0.3/cookbook/llm-integration#llm-integration",[],"Edamame's typed statements with self-describing metadata make it ideal for AI-assisted database operations.",{"id":527,"title":528,"titles":529,"content":530,"level":19},"/v1.0.3/cookbook/llm-integration#the-pattern","The Pattern",[519],"Define statements with descriptive names and descriptionsCollect statement metadata into a registrySerialize registry as JSON for LLM contextLLM selects statement by name and provides paramsExecute statement with LLM-provided inputs User Query → LLM (with statement metadata) → Statement Name + Params → Edamame → Results",{"id":532,"title":129,"titles":533,"content":534,"level":19},"/v1.0.3/cookbook/llm-integration#defining-statements",[519],"Statements are self-describing with name, description, params, and tags: var (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    ByRole = edamame.NewQueryStatement(\"by-role\", \"Find users by role\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"role\", Operator: \"=\", Param: \"role\"},\n        },\n    }, \"filter\", \"security\")\n\n    ActiveAdults = edamame.NewQueryStatement(\"active-adults\", \"Find active users over 18\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"active\", Operator: \"=\", Param: \"active\"},\n            {Field: \"age\", Operator: \">=\", Param: \"min_age\"},\n        },\n    }, \"filter\")\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select a single user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"id\", Operator: \"=\", Param: \"id\"},\n        },\n    })\n\n    CountAll = edamame.NewAggregateStatement(\"count-all\", \"Count all users\", edamame.AggCount, edamame.AggregateSpec{})\n)",{"id":536,"title":537,"titles":538,"content":539,"level":19},"/v1.0.3/cookbook/llm-integration#building-a-statement-registry","Building a Statement Registry",[519],"Create a registry to collect statements for LLM consumption: type StatementInfo struct {\n    Name        string      `json:\"name\"`\n    Description string      `json:\"description\"`\n    Type        string      `json:\"type\"`\n    Params      []ParamInfo `json:\"params\"`\n    Tags        []string    `json:\"tags,omitempty\"`\n}\n\ntype ParamInfo struct {\n    Name     string `json:\"name\"`\n    Type     string `json:\"type\"`\n    Required bool   `json:\"required\"`\n}\n\ntype StatementRegistry struct {\n    Table      string          `json:\"table\"`\n    Queries    []StatementInfo `json:\"queries,omitempty\"`\n    Selects    []StatementInfo `json:\"selects,omitempty\"`\n    Updates    []StatementInfo `json:\"updates,omitempty\"`\n    Deletes    []StatementInfo `json:\"deletes,omitempty\"`\n    Aggregates []StatementInfo `json:\"aggregates,omitempty\"`\n}\n\nfunc NewRegistry(table string) *StatementRegistry {\n    return &StatementRegistry{Table: table}\n}\n\nfunc (r *StatementRegistry) AddQuery(stmt edamame.QueryStatement) {\n    r.Queries = append(r.Queries, toStatementInfo(stmt.Name(), stmt.Description(), \"query\", stmt.Params(), stmt.Tags()))\n}\n\nfunc (r *StatementRegistry) AddSelect(stmt edamame.SelectStatement) {\n    r.Selects = append(r.Selects, toStatementInfo(stmt.Name(), stmt.Description(), \"select\", stmt.Params(), stmt.Tags()))\n}\n\nfunc (r *StatementRegistry) AddAggregate(stmt edamame.AggregateStatement) {\n    r.Aggregates = append(r.Aggregates, toStatementInfo(stmt.Name(), stmt.Description(), \"aggregate\", stmt.Params(), stmt.Tags()))\n}\n\nfunc toStatementInfo(name, desc, typ string, params []edamame.ParamSpec, tags []string) StatementInfo {\n    info := StatementInfo{\n        Name:        name,\n        Description: desc,\n        Type:        typ,\n        Tags:        tags,\n    }\n    for _, p := range params {\n        info.Params = append(info.Params, ParamInfo{\n            Name:     p.Name,\n            Type:     p.Type,\n            Required: p.Required,\n        })\n    }\n    return info\n}\n\nfunc (r *StatementRegistry) JSON() (string, error) {\n    data, err := json.MarshalIndent(r, \"\", \"  \")\n    return string(data), err\n}",{"id":541,"title":542,"titles":543,"content":544,"level":19},"/v1.0.3/cookbook/llm-integration#exporting-for-llm-context","Exporting for LLM Context",[519],"// Build registry\nregistry := NewRegistry(\"users\")\nregistry.AddQuery(QueryAll)\nregistry.AddQuery(ByRole)\nregistry.AddQuery(ActiveAdults)\nregistry.AddSelect(SelectByID)\nregistry.AddAggregate(CountAll)\n\n// Export as JSON\njson, _ := registry.JSON() Example output: {\n  \"table\": \"users\",\n  \"queries\": [\n    {\n      \"name\": \"query-all\",\n      \"description\": \"Query all users\",\n      \"type\": \"query\",\n      \"params\": []\n    },\n    {\n      \"name\": \"by-role\",\n      \"description\": \"Find users by role\",\n      \"type\": \"query\",\n      \"params\": [\n        {\"name\": \"role\", \"type\": \"any\", \"required\": true}\n      ],\n      \"tags\": [\"filter\", \"security\"]\n    },\n    {\n      \"name\": \"active-adults\",\n      \"description\": \"Find active users over 18\",\n      \"type\": \"query\",\n      \"params\": [\n        {\"name\": \"active\", \"type\": \"any\", \"required\": true},\n        {\"name\": \"min_age\", \"type\": \"any\", \"required\": true}\n      ],\n      \"tags\": [\"filter\"]\n    }\n  ],\n  \"selects\": [\n    {\n      \"name\": \"select-by-id\",\n      \"description\": \"Select a single user by ID\",\n      \"type\": \"select\",\n      \"params\": [\n        {\"name\": \"id\", \"type\": \"any\", \"required\": true}\n      ]\n    }\n  ],\n  \"aggregates\": [\n    {\n      \"name\": \"count-all\",\n      \"description\": \"Count all users\",\n      \"type\": \"aggregate\",\n      \"params\": []\n    }\n  ]\n}",{"id":546,"title":547,"titles":548,"content":549,"level":19},"/v1.0.3/cookbook/llm-integration#system-prompt-design","System Prompt Design",[519],"Provide statement metadata in your LLM system prompt: You are a database assistant. You have access to the following operations:\n\n{registry_json}\n\nWhen the user asks a question about data:\n1. Identify the appropriate operation\n2. Extract required parameters from the user's request\n3. Respond with JSON: {\"statement\": \"name\", \"type\": \"query|select|...\", \"params\": {...}}\n\nExamples:\n- \"How many users are there?\" → {\"statement\": \"count-all\", \"type\": \"aggregate\", \"params\": {}}\n- \"Find admins\" → {\"statement\": \"by-role\", \"type\": \"query\", \"params\": {\"role\": \"admin\"}}\n- \"Get user 123\" → {\"statement\": \"select-by-id\", \"type\": \"select\", \"params\": {\"id\": 123}}",{"id":551,"title":552,"titles":553,"content":554,"level":19},"/v1.0.3/cookbook/llm-integration#executing-llm-responses","Executing LLM Responses",[519],"Create a dispatcher that maps statement names to actual statements: type LLMResponse struct {\n    Statement string         `json:\"statement\"`\n    Type      string         `json:\"type\"`\n    Params    map[string]any `json:\"params\"`\n}\n\ntype StatementDispatcher struct {\n    exec       *edamame.Executor[User]\n    queries    map[string]edamame.QueryStatement\n    selects    map[string]edamame.SelectStatement\n    aggregates map[string]edamame.AggregateStatement\n}\n\nfunc NewDispatcher(exec *edamame.Executor[User]) *StatementDispatcher {\n    return &StatementDispatcher{\n        exec:       exec,\n        queries:    make(map[string]edamame.QueryStatement),\n        selects:    make(map[string]edamame.SelectStatement),\n        aggregates: make(map[string]edamame.AggregateStatement),\n    }\n}\n\nfunc (d *StatementDispatcher) RegisterQuery(stmt edamame.QueryStatement) {\n    d.queries[stmt.Name()] = stmt\n}\n\nfunc (d *StatementDispatcher) RegisterSelect(stmt edamame.SelectStatement) {\n    d.selects[stmt.Name()] = stmt\n}\n\nfunc (d *StatementDispatcher) RegisterAggregate(stmt edamame.AggregateStatement) {\n    d.aggregates[stmt.Name()] = stmt\n}\n\nfunc (d *StatementDispatcher) Execute(ctx context.Context, resp LLMResponse) (any, error) {\n    switch resp.Type {\n    case \"query\":\n        stmt, ok := d.queries[resp.Statement]\n        if !ok {\n            return nil, fmt.Errorf(\"unknown query: %s\", resp.Statement)\n        }\n        return d.exec.ExecQuery(ctx, stmt, resp.Params)\n    case \"select\":\n        stmt, ok := d.selects[resp.Statement]\n        if !ok {\n            return nil, fmt.Errorf(\"unknown select: %s\", resp.Statement)\n        }\n        return d.exec.ExecSelect(ctx, stmt, resp.Params)\n    case \"aggregate\":\n        stmt, ok := d.aggregates[resp.Statement]\n        if !ok {\n            return nil, fmt.Errorf(\"unknown aggregate: %s\", resp.Statement)\n        }\n        return d.exec.ExecAggregate(ctx, stmt, resp.Params)\n    default:\n        return nil, fmt.Errorf(\"unknown type: %s\", resp.Type)\n    }\n}",{"id":556,"title":557,"titles":558,"content":559,"level":19},"/v1.0.3/cookbook/llm-integration#complete-setup","Complete Setup",[519],"// Create executor\nexec, _ := edamame.New[User](db, \"users\", postgres.New())\n\n// Create dispatcher and register statements\ndispatcher := NewDispatcher(exec)\ndispatcher.RegisterQuery(QueryAll)\ndispatcher.RegisterQuery(ByRole)\ndispatcher.RegisterQuery(ActiveAdults)\ndispatcher.RegisterSelect(SelectByID)\ndispatcher.RegisterAggregate(CountAll)\n\n// Build registry for LLM context\nregistry := NewRegistry(\"users\")\nregistry.AddQuery(QueryAll)\nregistry.AddQuery(ByRole)\nregistry.AddQuery(ActiveAdults)\nregistry.AddSelect(SelectByID)\nregistry.AddAggregate(CountAll)\n\nllmContext, _ := registry.JSON()",{"id":561,"title":562,"titles":563,"content":564,"level":19},"/v1.0.3/cookbook/llm-integration#validation","Validation",[519],"Validate LLM responses before execution: func (d *StatementDispatcher) Validate(resp LLMResponse) error {\n    switch resp.Type {\n    case \"query\":\n        stmt, ok := d.queries[resp.Statement]\n        if !ok {\n            return fmt.Errorf(\"unknown query: %s\", resp.Statement)\n        }\n        return validateParams(stmt.Params(), resp.Params)\n    case \"select\":\n        stmt, ok := d.selects[resp.Statement]\n        if !ok {\n            return fmt.Errorf(\"unknown select: %s\", resp.Statement)\n        }\n        return validateParams(stmt.Params(), resp.Params)\n    case \"aggregate\":\n        stmt, ok := d.aggregates[resp.Statement]\n        if !ok {\n            return fmt.Errorf(\"unknown aggregate: %s\", resp.Statement)\n        }\n        return validateParams(stmt.Params(), resp.Params)\n    default:\n        return fmt.Errorf(\"unknown type: %s\", resp.Type)\n    }\n}\n\nfunc validateParams(specs []edamame.ParamSpec, provided map[string]any) error {\n    for _, spec := range specs {\n        if spec.Required {\n            if _, ok := provided[spec.Name]; !ok {\n                return fmt.Errorf(\"missing required param: %s\", spec.Name)\n            }\n        }\n    }\n    return nil\n}",{"id":566,"title":567,"titles":568,"content":569,"level":19},"/v1.0.3/cookbook/llm-integration#rate-limiting","Rate Limiting",[519],"Protect against LLM-driven query floods: type RateLimitedDispatcher struct {\n    dispatcher *StatementDispatcher\n    limiter    *rate.Limiter\n}\n\nfunc NewRateLimitedDispatcher(dispatcher *StatementDispatcher, rps float64) *RateLimitedDispatcher {\n    return &RateLimitedDispatcher{\n        dispatcher: dispatcher,\n        limiter:    rate.NewLimiter(rate.Limit(rps), 10),\n    }\n}\n\nfunc (d *RateLimitedDispatcher) Execute(ctx context.Context, resp LLMResponse) (any, error) {\n    if err := d.limiter.Wait(ctx); err != nil {\n        return nil, err\n    }\n    return d.dispatcher.Execute(ctx, resp)\n}",{"id":571,"title":572,"titles":573,"content":574,"level":19},"/v1.0.3/cookbook/llm-integration#audit-logging","Audit Logging",[519],"Log LLM-driven operations: func (d *StatementDispatcher) ExecuteWithAudit(ctx context.Context, resp LLMResponse, userID string) (any, error) {\n    start := time.Now()\n\n    result, err := d.Execute(ctx, resp)\n\n    log.Printf(\"LLM execution: user=%s statement=%s type=%s params=%v duration=%v error=%v\",\n        userID,\n        resp.Statement,\n        resp.Type,\n        resp.Params,\n        time.Since(start),\n        err,\n    )\n\n    return result, err\n}",{"id":576,"title":577,"titles":578,"content":579,"level":19},"/v1.0.3/cookbook/llm-integration#example-chat-interface","Example: Chat Interface",[519],"Complete example with a simple chat interface: func HandleChat(ctx context.Context, dispatcher *StatementDispatcher, registry *StatementRegistry, llm LLMClient, userMessage string) string {\n    // 1. Get statement metadata\n    specs, _ := registry.JSON()\n\n    // 2. Build prompt\n    prompt := fmt.Sprintf(`You are a database assistant. Available operations:\n%s\n\nUser: %s\n\nRespond with JSON: {\"statement\": \"...\", \"type\": \"...\", \"params\": {...}}\nOr respond with {\"error\": \"...\"} if the request cannot be fulfilled.`, specs, userMessage)\n\n    // 3. Get LLM response\n    llmResp, err := llm.Complete(ctx, prompt)\n    if err != nil {\n        return \"I couldn't process that request.\"\n    }\n\n    // 4. Parse response\n    var resp LLMResponse\n    if err := json.Unmarshal([]byte(llmResp), &resp); err != nil {\n        return \"I couldn't understand how to query the database.\"\n    }\n\n    // 5. Validate\n    if err := dispatcher.Validate(resp); err != nil {\n        return fmt.Sprintf(\"Invalid request: %v\", err)\n    }\n\n    // 6. Execute\n    result, err := dispatcher.Execute(ctx, resp)\n    if err != nil {\n        return fmt.Sprintf(\"Query failed: %v\", err)\n    }\n\n    // 7. Format response\n    return formatResult(result)\n}",{"id":581,"title":582,"titles":583,"content":584,"level":19},"/v1.0.3/cookbook/llm-integration#security-considerations","Security Considerations",[519],"Validate all LLM outputs before executionUse parameterized queries (edamame handles this)Limit exposed statements to what's safeRate limit LLM-driven operationsAudit log all executionsNever expose raw SQL generation to LLMs html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}",{"id":586,"title":587,"titles":588,"content":589,"level":9},"/v1.0.3/reference/api","API Reference",[],"Complete API reference for the edamame package",{"id":591,"title":587,"titles":592,"content":593,"level":9},"/v1.0.3/reference/api#api-reference",[],"Complete API reference for the github.com/zoobz-io/edamame package.",{"id":595,"title":110,"titles":596,"content":597,"level":19},"/v1.0.3/reference/api#executor",[587],"The main execution context for a model type.",{"id":599,"title":600,"titles":601,"content":602,"level":40},"/v1.0.3/reference/api#new","New",[587,110],"func New[T any](db *sqlx.DB, tableName string, renderer astql.Renderer) (*Executor[T], error) Creates a new executor for type T bound to the given table with the specified SQL renderer. The db parameter can be nil for testing statement rendering without database access. Supported renderers via astql: github.com/zoobz-io/astql/pkg/postgres - PostgreSQLgithub.com/zoobz-io/astql/pkg/mariadb - MariaDBgithub.com/zoobz-io/astql/pkg/sqlite - SQLitegithub.com/zoobz-io/astql/pkg/mssql - SQL Server import \"github.com/zoobz-io/astql/pkg/postgres\" // or mariadb, sqlite, mssql\n\nexec, err := edamame.New[User](db, \"users\", postgres.New())",{"id":604,"title":605,"titles":606,"content":34,"level":19},"/v1.0.3/reference/api#statement-constructors","Statement Constructors",[587],{"id":608,"title":609,"titles":610,"content":611,"level":40},"/v1.0.3/reference/api#newquerystatement","NewQueryStatement",[587,605],"func NewQueryStatement(name, description string, spec QuerySpec, tags ...string) QueryStatement Creates a typed query statement for multi-record retrieval. Parameters are automatically derived from the spec.",{"id":613,"title":614,"titles":615,"content":616,"level":40},"/v1.0.3/reference/api#newselectstatement","NewSelectStatement",[587,605],"func NewSelectStatement(name, description string, spec SelectSpec, tags ...string) SelectStatement Creates a typed select statement for single-record retrieval.",{"id":618,"title":619,"titles":620,"content":621,"level":40},"/v1.0.3/reference/api#newupdatestatement","NewUpdateStatement",[587,605],"func NewUpdateStatement(name, description string, spec UpdateSpec, tags ...string) UpdateStatement Creates a typed update statement for modifications.",{"id":623,"title":624,"titles":625,"content":626,"level":40},"/v1.0.3/reference/api#newdeletestatement","NewDeleteStatement",[587,605],"func NewDeleteStatement(name, description string, spec DeleteSpec, tags ...string) DeleteStatement Creates a typed delete statement for deletions.",{"id":628,"title":629,"titles":630,"content":631,"level":40},"/v1.0.3/reference/api#newaggregatestatement","NewAggregateStatement",[587,605],"func NewAggregateStatement(name, description string, fn AggregateFunc, spec AggregateSpec, tags ...string) AggregateStatement Creates a typed aggregate statement for COUNT, SUM, AVG, MIN, MAX operations.",{"id":633,"title":27,"titles":634,"content":635,"level":19},"/v1.0.3/reference/api#statement-types",[587],"All statement types share common methods: func (s Statement) ID() uuid.UUID      // Unique identifier\nfunc (s Statement) Name() string       // Human-readable name\nfunc (s Statement) Description() string // What the statement does\nfunc (s Statement) Params() []ParamSpec // Required parameters\nfunc (s Statement) Tags() []string     // Optional categorization tags",{"id":637,"title":638,"titles":639,"content":640,"level":40},"/v1.0.3/reference/api#querystatement","QueryStatement",[587,27],"For multi-record retrieval operations.",{"id":642,"title":643,"titles":644,"content":645,"level":40},"/v1.0.3/reference/api#selectstatement","SelectStatement",[587,27],"For single-record retrieval operations.",{"id":647,"title":648,"titles":649,"content":650,"level":40},"/v1.0.3/reference/api#updatestatement","UpdateStatement",[587,27],"For modification operations.",{"id":652,"title":653,"titles":654,"content":655,"level":40},"/v1.0.3/reference/api#deletestatement","DeleteStatement",[587,27],"For deletion operations.",{"id":657,"title":658,"titles":659,"content":660,"level":40},"/v1.0.3/reference/api#aggregatestatement","AggregateStatement",[587,27],"For aggregate operations (COUNT, SUM, AVG, MIN, MAX).",{"id":662,"title":663,"titles":664,"content":34,"level":19},"/v1.0.3/reference/api#executor-methods","Executor Methods",[587],{"id":666,"title":667,"titles":668,"content":34,"level":40},"/v1.0.3/reference/api#builder-access","Builder Access",[587,663],{"id":670,"title":671,"titles":672,"content":673,"level":674},"/v1.0.3/reference/api#query","Query",[587,663,667],"func (e *Executor[T]) Query(stmt QueryStatement) (*soy.Query[T], error) Returns a soy Query builder for the statement.",4,{"id":676,"title":677,"titles":678,"content":679,"level":674},"/v1.0.3/reference/api#select","Select",[587,663,667],"func (e *Executor[T]) Select(stmt SelectStatement) (*soy.Select[T], error) Returns a soy Select builder for the statement.",{"id":681,"title":682,"titles":683,"content":684,"level":674},"/v1.0.3/reference/api#update","Update",[587,663,667],"func (e *Executor[T]) Update(stmt UpdateStatement) (*soy.Update[T], error) Returns a soy Update builder for the statement.",{"id":686,"title":687,"titles":688,"content":689,"level":674},"/v1.0.3/reference/api#delete","Delete",[587,663,667],"func (e *Executor[T]) Delete(stmt DeleteStatement) (*soy.Delete[T], error) Returns a soy Delete builder for the statement.",{"id":691,"title":692,"titles":693,"content":694,"level":674},"/v1.0.3/reference/api#aggregate","Aggregate",[587,663,667],"func (e *Executor[T]) Aggregate(stmt AggregateStatement) *soy.Aggregate[T] Returns a soy Aggregate builder for the statement.",{"id":696,"title":697,"titles":698,"content":699,"level":674},"/v1.0.3/reference/api#insert","Insert",[587,663,667],"func (e *Executor[T]) Insert() *soy.Create[T] Returns a soy Create builder for inserts.",{"id":701,"title":702,"titles":703,"content":704,"level":674},"/v1.0.3/reference/api#compound","Compound",[587,663,667],"func (e *Executor[T]) Compound(spec CompoundQuerySpec) (*soy.Compound[T], error) Returns a soy Compound builder for set operations (UNION, INTERSECT, EXCEPT).",{"id":706,"title":707,"titles":708,"content":34,"level":40},"/v1.0.3/reference/api#execution-methods","Execution Methods",[587,663],{"id":710,"title":711,"titles":712,"content":713,"level":674},"/v1.0.3/reference/api#execquery-execquerytx","ExecQuery / ExecQueryTx",[587,663,707],"func (e *Executor[T]) ExecQuery(ctx context.Context, stmt QueryStatement, params map[string]any) ([]*T, error)\nfunc (e *Executor[T]) ExecQueryTx(ctx context.Context, tx *sqlx.Tx, stmt QueryStatement, params map[string]any) ([]*T, error) Executes a query statement, returning multiple records.",{"id":715,"title":716,"titles":717,"content":718,"level":674},"/v1.0.3/reference/api#execselect-execselecttx","ExecSelect / ExecSelectTx",[587,663,707],"func (e *Executor[T]) ExecSelect(ctx context.Context, stmt SelectStatement, params map[string]any) (*T, error)\nfunc (e *Executor[T]) ExecSelectTx(ctx context.Context, tx *sqlx.Tx, stmt SelectStatement, params map[string]any) (*T, error) Executes a select statement, returning a single record.",{"id":720,"title":721,"titles":722,"content":723,"level":674},"/v1.0.3/reference/api#execupdate-execupdatetx","ExecUpdate / ExecUpdateTx",[587,663,707],"func (e *Executor[T]) ExecUpdate(ctx context.Context, stmt UpdateStatement, params map[string]any) (*T, error)\nfunc (e *Executor[T]) ExecUpdateTx(ctx context.Context, tx *sqlx.Tx, stmt UpdateStatement, params map[string]any) (*T, error) Executes an update statement, returning the updated record.",{"id":725,"title":726,"titles":727,"content":728,"level":674},"/v1.0.3/reference/api#execdelete-execdeletetx","ExecDelete / ExecDeleteTx",[587,663,707],"func (e *Executor[T]) ExecDelete(ctx context.Context, stmt DeleteStatement, params map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecDeleteTx(ctx context.Context, tx *sqlx.Tx, stmt DeleteStatement, params map[string]any) (int64, error) Executes a delete statement, returning the count of deleted rows.",{"id":730,"title":731,"titles":732,"content":733,"level":674},"/v1.0.3/reference/api#execaggregate-execaggregatetx","ExecAggregate / ExecAggregateTx",[587,663,707],"func (e *Executor[T]) ExecAggregate(ctx context.Context, stmt AggregateStatement, params map[string]any) (float64, error)\nfunc (e *Executor[T]) ExecAggregateTx(ctx context.Context, tx *sqlx.Tx, stmt AggregateStatement, params map[string]any) (float64, error) Executes an aggregate statement, returning the result.",{"id":735,"title":736,"titles":737,"content":738,"level":674},"/v1.0.3/reference/api#execinsert-execinserttx","ExecInsert / ExecInsertTx",[587,663,707],"func (e *Executor[T]) ExecInsert(ctx context.Context, record *T) (*T, error)\nfunc (e *Executor[T]) ExecInsertTx(ctx context.Context, tx *sqlx.Tx, record *T) (*T, error) Inserts a record, returning it with generated fields populated.",{"id":740,"title":741,"titles":742,"content":743,"level":674},"/v1.0.3/reference/api#execcompound-execcompoundtx","ExecCompound / ExecCompoundTx",[587,663,707],"func (e *Executor[T]) ExecCompound(ctx context.Context, spec CompoundQuerySpec, params map[string]any) ([]*T, error)\nfunc (e *Executor[T]) ExecCompoundTx(ctx context.Context, tx *sqlx.Tx, spec CompoundQuerySpec, params map[string]any) ([]*T, error) Executes a compound query (UNION, INTERSECT, EXCEPT), returning multiple records.",{"id":745,"title":746,"titles":747,"content":34,"level":40},"/v1.0.3/reference/api#batch-execution","Batch Execution",[587,663],{"id":749,"title":750,"titles":751,"content":752,"level":674},"/v1.0.3/reference/api#execinsertbatch-execinsertbatchtx","ExecInsertBatch / ExecInsertBatchTx",[587,663,746],"func (e *Executor[T]) ExecInsertBatch(ctx context.Context, records []*T) (int64, error)\nfunc (e *Executor[T]) ExecInsertBatchTx(ctx context.Context, tx *sqlx.Tx, records []*T) (int64, error) Inserts multiple records, returning the count.",{"id":754,"title":755,"titles":756,"content":757,"level":674},"/v1.0.3/reference/api#execupdatebatch-execupdatebatchtx","ExecUpdateBatch / ExecUpdateBatchTx",[587,663,746],"func (e *Executor[T]) ExecUpdateBatch(ctx context.Context, stmt UpdateStatement, batchParams []map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecUpdateBatchTx(ctx context.Context, tx *sqlx.Tx, stmt UpdateStatement, batchParams []map[string]any) (int64, error) Executes an update statement with multiple parameter sets.",{"id":759,"title":760,"titles":761,"content":762,"level":674},"/v1.0.3/reference/api#execdeletebatch-execdeletebatchtx","ExecDeleteBatch / ExecDeleteBatchTx",[587,663,746],"func (e *Executor[T]) ExecDeleteBatch(ctx context.Context, stmt DeleteStatement, batchParams []map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecDeleteBatchTx(ctx context.Context, tx *sqlx.Tx, stmt DeleteStatement, batchParams []map[string]any) (int64, error) Executes a delete statement with multiple parameter sets.",{"id":764,"title":765,"titles":766,"content":767,"level":40},"/v1.0.3/reference/api#type-erased-execution-atom","Type-Erased Execution (Atom)",[587,663],"These methods return results as atom.Atom types, enabling type-erased execution where the concrete type T is not known at consumption time. Useful for dynamic query handling and LLM-driven database operations.",{"id":769,"title":770,"titles":771,"content":772,"level":674},"/v1.0.3/reference/api#execqueryatom","ExecQueryAtom",[587,663,765],"func (e *Executor[T]) ExecQueryAtom(ctx context.Context, stmt QueryStatement, params map[string]any) ([]*atom.Atom, error) Executes a query statement and returns results as Atoms.",{"id":774,"title":775,"titles":776,"content":777,"level":674},"/v1.0.3/reference/api#execselectatom","ExecSelectAtom",[587,663,765],"func (e *Executor[T]) ExecSelectAtom(ctx context.Context, stmt SelectStatement, params map[string]any) (*atom.Atom, error) Executes a select statement and returns the result as an Atom.",{"id":779,"title":780,"titles":781,"content":782,"level":674},"/v1.0.3/reference/api#execinsertatom","ExecInsertAtom",[587,663,765],"func (e *Executor[T]) ExecInsertAtom(ctx context.Context, params map[string]any) (*atom.Atom, error) Executes an insert using parameter map and returns the result as an Atom.",{"id":784,"title":785,"titles":786,"content":34,"level":40},"/v1.0.3/reference/api#rendering","Rendering",[587,663],{"id":788,"title":789,"titles":790,"content":791,"level":674},"/v1.0.3/reference/api#rendercompound","RenderCompound",[587,663,785],"func (e *Executor[T]) RenderCompound(spec CompoundQuerySpec) (string, error) Renders a compound query to SQL for inspection or debugging.",{"id":793,"title":794,"titles":795,"content":34,"level":40},"/v1.0.3/reference/api#other","Other",[587,663],{"id":797,"title":241,"titles":798,"content":799,"level":674},"/v1.0.3/reference/api#soy",[587,663,794],"func (e *Executor[T]) Soy() *soy.Soy[T] Returns the underlying soy instance for direct builder access.",{"id":801,"title":802,"titles":803,"content":804,"level":674},"/v1.0.3/reference/api#tablename","TableName",[587,663,794],"func (e *Executor[T]) TableName() string Returns the table name.",{"id":806,"title":807,"titles":808,"content":34,"level":19},"/v1.0.3/reference/api#spec-types","Spec Types",[587],{"id":810,"title":144,"titles":811,"content":812,"level":40},"/v1.0.3/reference/api#queryspec",[587,807],"type QuerySpec struct {\n    Fields      []string\n    SelectExprs []SelectExprSpec  // Expression-based SELECT (functions, aggregates)\n    Where       []ConditionSpec\n    OrderBy     []OrderBySpec\n    GroupBy     []string\n    Having      []ConditionSpec\n    HavingAgg   []HavingAggSpec\n    Limit       *int\n    LimitParam  string            // Parameterized LIMIT\n    Offset      *int\n    OffsetParam string            // Parameterized OFFSET\n    Distinct    bool\n    DistinctOn  []string\n    ForLocking  string\n}",{"id":814,"title":149,"titles":815,"content":816,"level":40},"/v1.0.3/reference/api#selectspec",[587,807],"type SelectSpec struct {\n    Fields      []string\n    SelectExprs []SelectExprSpec  // Expression-based SELECT (functions, aggregates)\n    Where       []ConditionSpec\n    OrderBy     []OrderBySpec\n    GroupBy     []string\n    Having      []ConditionSpec\n    HavingAgg   []HavingAggSpec\n    Limit       *int\n    LimitParam  string            // Parameterized LIMIT\n    Offset      *int\n    OffsetParam string            // Parameterized OFFSET\n    Distinct    bool\n    DistinctOn  []string\n    ForLocking  string\n}",{"id":818,"title":154,"titles":819,"content":820,"level":40},"/v1.0.3/reference/api#updatespec",[587,807],"type UpdateSpec struct {\n    Set   map[string]string  // field -> param\n    Where []ConditionSpec\n}",{"id":822,"title":159,"titles":823,"content":824,"level":40},"/v1.0.3/reference/api#deletespec",[587,807],"type DeleteSpec struct {\n    Where []ConditionSpec\n}",{"id":826,"title":164,"titles":827,"content":828,"level":40},"/v1.0.3/reference/api#aggregatespec",[587,807],"type AggregateSpec struct {\n    Field string\n    Where []ConditionSpec\n}",{"id":830,"title":831,"titles":832,"content":833,"level":40},"/v1.0.3/reference/api#conditionspec","ConditionSpec",[587,807],"type ConditionSpec struct {\n    Field      string\n    Operator   string\n    Param      string\n    IsNull     bool\n    Logic      string           // \"AND\" or \"OR\" for groups\n    Group      []ConditionSpec  // Nested conditions\n    Between    bool             // Use BETWEEN with LowParam/HighParam\n    NotBetween bool             // Use NOT BETWEEN with LowParam/HighParam\n    LowParam   string           // Lower bound param for BETWEEN\n    HighParam  string           // Upper bound param for BETWEEN\n    RightField string           // For field-to-field comparisons (WHERE a.field = b.field)\n}",{"id":835,"title":836,"titles":837,"content":838,"level":674},"/v1.0.3/reference/api#helper-methods","Helper Methods",[587,807,831],"func (c ConditionSpec) IsGroup() bool           // Returns true if this is a grouped condition\nfunc (c ConditionSpec) IsBetween() bool         // Returns true if Between is set\nfunc (c ConditionSpec) IsNotBetween() bool      // Returns true if NotBetween is set\nfunc (c ConditionSpec) IsFieldComparison() bool // Returns true if RightField is set",{"id":840,"title":841,"titles":842,"content":843,"level":40},"/v1.0.3/reference/api#orderbyspec","OrderBySpec",[587,807],"type OrderBySpec struct {\n    Field     string\n    Direction string  // \"asc\" or \"desc\"\n    Nulls     string  // \"first\" or \"last\"\n    Operator  string  // For expressions (e.g., \"\u003C->\")\n    Param     string  // For expression parameters\n}",{"id":845,"title":846,"titles":847,"content":848,"level":40},"/v1.0.3/reference/api#paramspec","ParamSpec",[587,807],"type ParamSpec struct {\n    Name        string\n    Type        string\n    Required    bool\n    Default     any\n    Description string\n}",{"id":850,"title":851,"titles":852,"content":853,"level":40},"/v1.0.3/reference/api#selectexprspec","SelectExprSpec",[587,807],"Defines expression-based SELECT columns (functions, aggregates, casts). type SelectExprSpec struct {\n    Func     string          // Function name (see supported functions below)\n    Field    string          // Primary field for single-field functions\n    Fields   []string        // Multiple fields for multi-field functions (concat)\n    Params   []string        // Additional parameters (substring positions, power exponent)\n    CastType string          // Target type for cast operations\n    Filter   *ConditionSpec  // Filter clause for aggregate functions\n    Alias    string          // Required: column alias in result\n} Supported Functions: CategoryFunctionsStringupper, lower, length, trim, ltrim, rtrim, substring, replace, concatMathabs, ceil, floor, round, sqrt, powerDate/Timenow, current_date, current_time, current_timestampTypecastAggregatecount, count_star, count_distinct, sum, avg, min, maxConditionalcoalesce, nullif",{"id":855,"title":856,"titles":857,"content":858,"level":40},"/v1.0.3/reference/api#havingaggspec","HavingAggSpec",[587,807],"Defines aggregate conditions for HAVING clauses. type HavingAggSpec struct {\n    Func     string  // Aggregate function: \"count\", \"sum\", \"avg\", \"min\", \"max\"\n    Field    string  // Field to aggregate\n    Operator string  // Comparison operator\n    Param    string  // Parameter name for comparison value\n}",{"id":860,"title":861,"titles":862,"content":863,"level":40},"/v1.0.3/reference/api#compoundqueryspec","CompoundQuerySpec",[587,807],"Defines compound queries using set operations (UNION, INTERSECT, EXCEPT). type CompoundQuerySpec struct {\n    Base     QuerySpec         // The base query\n    Operands []CompoundOperand // Set operations with additional queries\n    OrderBy  []OrderBySpec     // Final ORDER BY (applies to combined result)\n    Limit    *int              // Final LIMIT\n    Offset   *int              // Final OFFSET\n}",{"id":865,"title":866,"titles":867,"content":868,"level":40},"/v1.0.3/reference/api#compoundoperand","CompoundOperand",[587,807],"Defines a set operation in a compound query. type CompoundOperand struct {\n    Operation string    // \"union\", \"union_all\", \"intersect\", \"intersect_all\", \"except\", \"except_all\"\n    Query     QuerySpec // The query to combine\n}",{"id":870,"title":871,"titles":872,"content":873,"level":19},"/v1.0.3/reference/api#aggregatefunc","AggregateFunc",[587],"type AggregateFunc string\n\nconst (\n    AggCount AggregateFunc = \"COUNT\"\n    AggSum   AggregateFunc = \"SUM\"\n    AggAvg   AggregateFunc = \"AVG\"\n    AggMin   AggregateFunc = \"MIN\"\n    AggMax   AggregateFunc = \"MAX\"\n)",{"id":875,"title":876,"titles":877,"content":878,"level":19},"/v1.0.3/reference/api#event-keys","Event Keys",[587],"var (\n    KeyTable    = capitan.NewStringKey(\"table\")\n    KeyError    = capitan.NewStringKey(\"error\")\n    KeyDuration = capitan.NewDurationKey(\"duration\")\n)",{"id":880,"title":881,"titles":882,"content":883,"level":19},"/v1.0.3/reference/api#signals","Signals",[587],"var (\n    ExecutorCreated = capitan.NewSignal(\"edamame.executor.created\", \"Executor instance created\")\n) Hook for monitoring: capitan.Hook(edamame.ExecutorCreated, func(ctx context.Context, e *capitan.Event) {\n    table, _ := edamame.KeyTable.From(e)\n    log.Printf(\"Executor created for table: %s\", table)\n})",{"id":885,"title":115,"titles":886,"content":887,"level":19},"/v1.0.3/reference/api#struct-tags",[587],"Edamame uses struct tags to understand your model: type User struct {\n    ID    int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name  string `db:\"name\" type:\"text\"`\n    Age   *int   `db:\"age\" type:\"integer\"`\n} TagPurposeExampledbColumn namedb:\"user_id\"typeSQL typetype:\"text\", type:\"integer\"constraintsColumn constraintsconstraints:\"primarykey,notnull\" html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sfm-E, html code.shiki .sfm-E{--shiki-default:var(--shiki-variable)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",[889],{"title":890,"path":891,"stem":892,"children":893,"page":907},"V103","/v1.0.3","v1.0.3",[894,896,908,917,924],{"title":6,"path":5,"stem":895,"description":8},"v1.0.3/1.overview",{"title":897,"path":898,"stem":899,"children":900,"page":907},"Learn","/v1.0.3/learn","v1.0.3/2.learn",[901,903,905],{"title":58,"path":57,"stem":902,"description":60},"v1.0.3/2.learn/1.quickstart",{"title":101,"path":100,"stem":904,"description":103},"v1.0.3/2.learn/2.concepts",{"title":16,"path":218,"stem":906,"description":220},"v1.0.3/2.learn/3.architecture",false,{"title":909,"path":910,"stem":911,"children":912,"page":907},"Guides","/v1.0.3/guides","v1.0.3/3.guides",[913,915],{"title":120,"path":274,"stem":914,"description":276},"v1.0.3/3.guides/1.statements",{"title":456,"path":455,"stem":916,"description":458},"v1.0.3/3.guides/2.testing",{"title":918,"path":919,"stem":920,"children":921,"page":907},"Cookbook","/v1.0.3/cookbook","v1.0.3/4.cookbook",[922],{"title":519,"path":518,"stem":923,"description":521},"v1.0.3/4.cookbook/1.llm-integration",{"title":925,"path":926,"stem":927,"children":928,"page":907},"Reference","/v1.0.3/reference","v1.0.3/5.reference",[929],{"title":587,"path":586,"stem":930,"description":589},"v1.0.3/5.reference/1.api",[932],{"title":890,"path":891,"stem":892,"children":933,"page":907},[934,935,940,944,947],{"title":6,"path":5,"stem":895},{"title":897,"path":898,"stem":899,"children":936,"page":907},[937,938,939],{"title":58,"path":57,"stem":902},{"title":101,"path":100,"stem":904},{"title":16,"path":218,"stem":906},{"title":909,"path":910,"stem":911,"children":941,"page":907},[942,943],{"title":120,"path":274,"stem":914},{"title":456,"path":455,"stem":916},{"title":918,"path":919,"stem":920,"children":945,"page":907},[946],{"title":519,"path":518,"stem":923},{"title":925,"path":926,"stem":927,"children":948,"page":907},[949],{"title":587,"path":586,"stem":930},[951,2753,3194],{"id":952,"title":953,"body":954,"description":34,"extension":2746,"icon":2747,"meta":2748,"navigation":1117,"path":2749,"seo":2750,"stem":2751,"__hash__":2752},"resources/readme.md","README",{"type":955,"value":956,"toc":2731},"minimark",[957,961,1029,1032,1035,1040,1043,1488,1491,1495,1512,1520,1524,2344,2348,2444,2448,2491,2495,2501,2504,2650,2653,2657,2665,2669,2683,2686,2697,2700,2706,2710,2718,2721,2727],[958,959,960],"h1",{"id":960},"edamame",[962,963,964,975,983,991,999,1007,1014,1021],"p",{},[965,966,970],"a",{"href":967,"rel":968},"https://github.com/zoobz-io/edamame/actions/workflows/ci.yml",[969],"nofollow",[971,972],"img",{"alt":973,"src":974},"CI Status","https://github.com/zoobz-io/edamame/workflows/CI/badge.svg",[965,976,979],{"href":977,"rel":978},"https://codecov.io/gh/zoobz-io/edamame",[969],[971,980],{"alt":981,"src":982},"codecov","https://codecov.io/gh/zoobz-io/edamame/graph/badge.svg?branch=main",[965,984,987],{"href":985,"rel":986},"https://goreportcard.com/report/github.com/zoobz-io/edamame",[969],[971,988],{"alt":989,"src":990},"Go Report Card","https://goreportcard.com/badge/github.com/zoobz-io/edamame",[965,992,995],{"href":993,"rel":994},"https://github.com/zoobz-io/edamame/security/code-scanning",[969],[971,996],{"alt":997,"src":998},"CodeQL","https://github.com/zoobz-io/edamame/workflows/CodeQL/badge.svg",[965,1000,1003],{"href":1001,"rel":1002},"https://pkg.go.dev/github.com/zoobz-io/edamame",[969],[971,1004],{"alt":1005,"src":1006},"Go Reference","https://pkg.go.dev/badge/github.com/zoobz-io/edamame.svg",[965,1008,1010],{"href":1009},"LICENSE",[971,1011],{"alt":1012,"src":1013},"License","https://img.shields.io/github/license/zoobz-io/edamame",[965,1015,1017],{"href":1016},"go.mod",[971,1018],{"alt":1019,"src":1020},"Go Version","https://img.shields.io/github/go-mod/go-version/zoobz-io/edamame",[965,1022,1025],{"href":1023,"rel":1024},"https://github.com/zoobz-io/edamame/releases",[969],[971,1026],{"alt":1027,"src":1028},"Release","https://img.shields.io/github/v/release/zoobz-io/edamame",[962,1030,1031],{},"Statement-driven query exec for Go.",[962,1033,1034],{},"Define database queries as typed statements, execute them without magic strings.",[1036,1037,1039],"h2",{"id":1038},"queries-as-data","Queries as Data",[962,1041,1042],{},"Edamame treats queries as specs—pure data structures wrapped in typed statements.",[1044,1045,1049],"pre",{"className":1046,"code":1047,"language":1048,"meta":34,"style":34},"language-go shiki shiki-themes","// Define statements as package-level variables\nvar (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    ByStatus = edamame.NewQueryStatement(\"by-status\", \"Query users by status\", edamame.QuerySpec{\n        Where:   []edamame.ConditionSpec{{Field: \"status\", Operator: \"=\", Param: \"status\"}},\n        OrderBy: []edamame.OrderBySpec{{Field: \"created_at\", Direction: \"desc\"}},\n        Limit:   ptr(50),\n    })\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n)\n\n// Execute with type safety\nusers, _ := exec.ExecQuery(ctx, ByStatus, map[string]any{\"status\": \"active\"})\nuser, _ := exec.ExecSelect(ctx, SelectByID, map[string]any{\"id\": 123})\n","go",[1050,1051,1052,1060,1070,1113,1119,1154,1206,1244,1264,1270,1275,1309,1351,1356,1362,1367,1373,1436],"code",{"__ignoreMap":34},[1053,1054,1056],"span",{"class":1055,"line":9},"line",[1053,1057,1059],{"class":1058},"sLkEo","// Define statements as package-level variables\n",[1053,1061,1062,1066],{"class":1055,"line":19},[1053,1063,1065],{"class":1064},"sUt3r","var",[1053,1067,1069],{"class":1068},"sq5bi"," (\n",[1053,1071,1072,1076,1079,1082,1085,1088,1091,1095,1098,1101,1103,1106,1108,1110],{"class":1055,"line":40},[1053,1073,1075],{"class":1074},"sh8_p","    QueryAll",[1053,1077,1078],{"class":1074}," =",[1053,1080,1081],{"class":1074}," edamame",[1053,1083,1084],{"class":1068},".",[1053,1086,609],{"class":1087},"s5klm",[1053,1089,1090],{"class":1068},"(",[1053,1092,1094],{"class":1093},"sxAnc","\"query-all\"",[1053,1096,1097],{"class":1068},",",[1053,1099,1100],{"class":1093}," \"Query all users\"",[1053,1102,1097],{"class":1068},[1053,1104,1081],{"class":1105},"sYBwO",[1053,1107,1084],{"class":1068},[1053,1109,144],{"class":1105},[1053,1111,1112],{"class":1068},"{})\n",[1053,1114,1115],{"class":1055,"line":674},[1053,1116,1118],{"emptyLinePlaceholder":1117},true,"\n",[1053,1120,1122,1125,1127,1129,1131,1133,1135,1138,1140,1143,1145,1147,1149,1151],{"class":1055,"line":1121},5,[1053,1123,1124],{"class":1074},"    ByStatus",[1053,1126,1078],{"class":1074},[1053,1128,1081],{"class":1074},[1053,1130,1084],{"class":1068},[1053,1132,609],{"class":1087},[1053,1134,1090],{"class":1068},[1053,1136,1137],{"class":1093},"\"by-status\"",[1053,1139,1097],{"class":1068},[1053,1141,1142],{"class":1093}," \"Query users by status\"",[1053,1144,1097],{"class":1068},[1053,1146,1081],{"class":1105},[1053,1148,1084],{"class":1068},[1053,1150,144],{"class":1105},[1053,1152,1153],{"class":1068},"{\n",[1053,1155,1157,1161,1164,1167,1169,1171,1173,1176,1179,1181,1184,1186,1189,1191,1194,1196,1199,1201,1203],{"class":1055,"line":1156},6,[1053,1158,1160],{"class":1159},"sBGCq","        Where",[1053,1162,1163],{"class":1068},":",[1053,1165,1166],{"class":1068},"   []",[1053,1168,960],{"class":1105},[1053,1170,1084],{"class":1068},[1053,1172,831],{"class":1105},[1053,1174,1175],{"class":1068},"{{",[1053,1177,1178],{"class":1159},"Field",[1053,1180,1163],{"class":1068},[1053,1182,1183],{"class":1093}," \"status\"",[1053,1185,1097],{"class":1068},[1053,1187,1188],{"class":1159}," Operator",[1053,1190,1163],{"class":1068},[1053,1192,1193],{"class":1093}," \"=\"",[1053,1195,1097],{"class":1068},[1053,1197,1198],{"class":1159}," Param",[1053,1200,1163],{"class":1068},[1053,1202,1183],{"class":1093},[1053,1204,1205],{"class":1068},"}},\n",[1053,1207,1209,1212,1214,1217,1219,1221,1223,1225,1227,1229,1232,1234,1237,1239,1242],{"class":1055,"line":1208},7,[1053,1210,1211],{"class":1159},"        OrderBy",[1053,1213,1163],{"class":1068},[1053,1215,1216],{"class":1068}," []",[1053,1218,960],{"class":1105},[1053,1220,1084],{"class":1068},[1053,1222,841],{"class":1105},[1053,1224,1175],{"class":1068},[1053,1226,1178],{"class":1159},[1053,1228,1163],{"class":1068},[1053,1230,1231],{"class":1093}," \"created_at\"",[1053,1233,1097],{"class":1068},[1053,1235,1236],{"class":1159}," Direction",[1053,1238,1163],{"class":1068},[1053,1240,1241],{"class":1093}," \"desc\"",[1053,1243,1205],{"class":1068},[1053,1245,1247,1250,1252,1255,1257,1261],{"class":1055,"line":1246},8,[1053,1248,1249],{"class":1159},"        Limit",[1053,1251,1163],{"class":1068},[1053,1253,1254],{"class":1087},"   ptr",[1053,1256,1090],{"class":1068},[1053,1258,1260],{"class":1259},"sMAmT","50",[1053,1262,1263],{"class":1068},"),\n",[1053,1265,1267],{"class":1055,"line":1266},9,[1053,1268,1269],{"class":1068},"    })\n",[1053,1271,1273],{"class":1055,"line":1272},10,[1053,1274,1118],{"emptyLinePlaceholder":1117},[1053,1276,1278,1281,1283,1285,1287,1289,1291,1294,1296,1299,1301,1303,1305,1307],{"class":1055,"line":1277},11,[1053,1279,1280],{"class":1074},"    SelectByID",[1053,1282,1078],{"class":1074},[1053,1284,1081],{"class":1074},[1053,1286,1084],{"class":1068},[1053,1288,614],{"class":1087},[1053,1290,1090],{"class":1068},[1053,1292,1293],{"class":1093},"\"select-by-id\"",[1053,1295,1097],{"class":1068},[1053,1297,1298],{"class":1093}," \"Select user by ID\"",[1053,1300,1097],{"class":1068},[1053,1302,1081],{"class":1105},[1053,1304,1084],{"class":1068},[1053,1306,149],{"class":1105},[1053,1308,1153],{"class":1068},[1053,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330,1333,1335,1337,1339,1341,1343,1345,1347,1349],{"class":1055,"line":1311},12,[1053,1313,1160],{"class":1159},[1053,1315,1163],{"class":1068},[1053,1317,1216],{"class":1068},[1053,1319,960],{"class":1105},[1053,1321,1084],{"class":1068},[1053,1323,831],{"class":1105},[1053,1325,1175],{"class":1068},[1053,1327,1178],{"class":1159},[1053,1329,1163],{"class":1068},[1053,1331,1332],{"class":1093}," \"id\"",[1053,1334,1097],{"class":1068},[1053,1336,1188],{"class":1159},[1053,1338,1163],{"class":1068},[1053,1340,1193],{"class":1093},[1053,1342,1097],{"class":1068},[1053,1344,1198],{"class":1159},[1053,1346,1163],{"class":1068},[1053,1348,1332],{"class":1093},[1053,1350,1205],{"class":1068},[1053,1352,1354],{"class":1055,"line":1353},13,[1053,1355,1269],{"class":1068},[1053,1357,1359],{"class":1055,"line":1358},14,[1053,1360,1361],{"class":1068},")\n",[1053,1363,1365],{"class":1055,"line":1364},15,[1053,1366,1118],{"emptyLinePlaceholder":1117},[1053,1368,1370],{"class":1055,"line":1369},16,[1053,1371,1372],{"class":1058},"// Execute with type safety\n",[1053,1374,1376,1379,1381,1384,1387,1390,1392,1395,1397,1400,1402,1405,1407,1410,1413,1416,1419,1422,1425,1428,1430,1433],{"class":1055,"line":1375},17,[1053,1377,1378],{"class":1074},"users",[1053,1380,1097],{"class":1068},[1053,1382,1383],{"class":1074}," _",[1053,1385,1386],{"class":1074}," :=",[1053,1388,1389],{"class":1074}," exec",[1053,1391,1084],{"class":1068},[1053,1393,1394],{"class":1087},"ExecQuery",[1053,1396,1090],{"class":1068},[1053,1398,1399],{"class":1074},"ctx",[1053,1401,1097],{"class":1068},[1053,1403,1404],{"class":1074}," ByStatus",[1053,1406,1097],{"class":1068},[1053,1408,1409],{"class":1064}," map",[1053,1411,1412],{"class":1068},"[",[1053,1414,1415],{"class":1105},"string",[1053,1417,1418],{"class":1068},"]",[1053,1420,1421],{"class":1105},"any",[1053,1423,1424],{"class":1068},"{",[1053,1426,1427],{"class":1093},"\"status\"",[1053,1429,1163],{"class":1068},[1053,1431,1432],{"class":1093}," \"active\"",[1053,1434,1435],{"class":1068},"})\n",[1053,1437,1439,1442,1444,1446,1448,1450,1452,1455,1457,1459,1461,1464,1466,1468,1470,1472,1474,1476,1478,1481,1483,1486],{"class":1055,"line":1438},18,[1053,1440,1441],{"class":1074},"user",[1053,1443,1097],{"class":1068},[1053,1445,1383],{"class":1074},[1053,1447,1386],{"class":1074},[1053,1449,1389],{"class":1074},[1053,1451,1084],{"class":1068},[1053,1453,1454],{"class":1087},"ExecSelect",[1053,1456,1090],{"class":1068},[1053,1458,1399],{"class":1074},[1053,1460,1097],{"class":1068},[1053,1462,1463],{"class":1074}," SelectByID",[1053,1465,1097],{"class":1068},[1053,1467,1409],{"class":1064},[1053,1469,1412],{"class":1068},[1053,1471,1415],{"class":1105},[1053,1473,1418],{"class":1068},[1053,1475,1421],{"class":1105},[1053,1477,1424],{"class":1068},[1053,1479,1480],{"class":1093},"\"id\"",[1053,1482,1163],{"class":1068},[1053,1484,1485],{"class":1259}," 123",[1053,1487,1435],{"class":1068},[962,1489,1490],{},"Type-safe. No magic strings. Compile-time guarantees.",[1036,1492,1494],{"id":1493},"install","Install",[1044,1496,1500],{"className":1497,"code":1498,"language":1499,"meta":34,"style":34},"language-bash shiki shiki-themes","go get github.com/zoobz-io/edamame\n","bash",[1050,1501,1502],{"__ignoreMap":34},[1053,1503,1504,1506,1509],{"class":1055,"line":9},[1053,1505,1048],{"class":1087},[1053,1507,1508],{"class":1093}," get",[1053,1510,1511],{"class":1093}," github.com/zoobz-io/edamame\n",[962,1513,1514,1515,1084],{},"Requires Go 1.24+. Supports PostgreSQL, MariaDB, SQLite, and SQL Server via ",[965,1516,1519],{"href":1517,"rel":1518},"https://github.com/zoobz-io/astql",[969],"astql",[1036,1521,1523],{"id":1522},"quick-start","Quick Start",[1044,1525,1527],{"className":1046,"code":1526,"language":1048,"meta":34,"style":34},"package main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/jmoiron/sqlx\"\n    _ \"github.com/lib/pq\" // or mariadb, sqlite3, mssql driver\n    \"github.com/zoobz-io/astql/pkg/postgres\" // or mariadb, sqlite, mssql\n    \"github.com/zoobz-io/edamame\"\n)\n\ntype User struct {\n    ID     int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email  string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name   string `db:\"name\" type:\"text\"`\n    Status string `db:\"status\" type:\"text\"`\n}\n\n// Define statements\nvar (\n    QueryAll = edamame.NewQueryStatement(\"query-all\", \"Query all users\", edamame.QuerySpec{})\n\n    SelectByID = edamame.NewSelectStatement(\"select-by-id\", \"Select user by ID\", edamame.SelectSpec{\n        Where: []edamame.ConditionSpec{{Field: \"id\", Operator: \"=\", Param: \"id\"}},\n    })\n\n    CountAll = edamame.NewAggregateStatement(\"count-all\", \"Count all users\", edamame.AggCount, edamame.AggregateSpec{})\n\n    ActiveUsers = edamame.NewQueryStatement(\"active\", \"Query active users\", edamame.QuerySpec{\n        Where: []edamame.ConditionSpec{\n            {Field: \"status\", Operator: \"=\", Param: \"status\"},\n        },\n    })\n)\n\nfunc main() {\n    db, _ := sqlx.Connect(\"postgres\", \"postgres://localhost/mydb?sslmode=disable\")\n    ctx := context.Background()\n\n    // Create exec\n    exec, _ := edamame.New[User](db, \"users\", postgres.New())\n\n    // Execute statements\n    users, _ := exec.ExecQuery(ctx, QueryAll, nil)\n    user, _ := exec.ExecSelect(ctx, SelectByID, map[string]any{\"id\": 1})\n    count, _ := exec.ExecAggregate(ctx, CountAll, nil)\n    active, _ := exec.ExecQuery(ctx, ActiveUsers, map[string]any{\"status\": \"active\"})\n\n    fmt.Printf(\"%d users, user #1: %s, %.0f total, %d active\\n\", len(users), user.Name, count, len(active))\n}\n",[1050,1528,1529,1537,1541,1549,1554,1559,1563,1568,1580,1588,1593,1597,1601,1615,1626,1637,1648,1659,1664,1669,1675,1682,1713,1718,1749,1790,1795,1800,1843,1848,1882,1899,1930,1936,1941,1946,1951,1965,1997,2016,2021,2027,2073,2078,2084,2118,2167,2201,2250,2255,2339],{"__ignoreMap":34},[1053,1530,1531,1534],{"class":1055,"line":9},[1053,1532,1533],{"class":1064},"package",[1053,1535,1536],{"class":1105}," main\n",[1053,1538,1539],{"class":1055,"line":19},[1053,1540,1118],{"emptyLinePlaceholder":1117},[1053,1542,1543,1546],{"class":1055,"line":40},[1053,1544,1545],{"class":1064},"import",[1053,1547,1069],{"class":1548},"soy-K",[1053,1550,1551],{"class":1055,"line":674},[1053,1552,1553],{"class":1093},"    \"context\"\n",[1053,1555,1556],{"class":1055,"line":1121},[1053,1557,1558],{"class":1093},"    \"fmt\"\n",[1053,1560,1561],{"class":1055,"line":1156},[1053,1562,1118],{"emptyLinePlaceholder":1117},[1053,1564,1565],{"class":1055,"line":1208},[1053,1566,1567],{"class":1093},"    \"github.com/jmoiron/sqlx\"\n",[1053,1569,1570,1574,1577],{"class":1055,"line":1246},[1053,1571,1573],{"class":1572},"sSYET","    _",[1053,1575,1576],{"class":1093}," \"github.com/lib/pq\"",[1053,1578,1579],{"class":1058}," // or mariadb, sqlite3, mssql driver\n",[1053,1581,1582,1585],{"class":1055,"line":1266},[1053,1583,1584],{"class":1093},"    \"github.com/zoobz-io/astql/pkg/postgres\"",[1053,1586,1587],{"class":1058}," // or mariadb, sqlite, mssql\n",[1053,1589,1590],{"class":1055,"line":1272},[1053,1591,1592],{"class":1093},"    \"github.com/zoobz-io/edamame\"\n",[1053,1594,1595],{"class":1055,"line":1277},[1053,1596,1361],{"class":1548},[1053,1598,1599],{"class":1055,"line":1311},[1053,1600,1118],{"emptyLinePlaceholder":1117},[1053,1602,1603,1606,1609,1612],{"class":1055,"line":1353},[1053,1604,1605],{"class":1064},"type",[1053,1607,1608],{"class":1105}," User",[1053,1610,1611],{"class":1064}," struct",[1053,1613,1614],{"class":1068}," {\n",[1053,1616,1617,1620,1623],{"class":1055,"line":1358},[1053,1618,1619],{"class":1159},"    ID",[1053,1621,1622],{"class":1105},"     int",[1053,1624,1625],{"class":1093},"    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n",[1053,1627,1628,1631,1634],{"class":1055,"line":1364},[1053,1629,1630],{"class":1159},"    Email",[1053,1632,1633],{"class":1105},"  string",[1053,1635,1636],{"class":1093}," `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n",[1053,1638,1639,1642,1645],{"class":1055,"line":1369},[1053,1640,1641],{"class":1159},"    Name",[1053,1643,1644],{"class":1105},"   string",[1053,1646,1647],{"class":1093}," `db:\"name\" type:\"text\"`\n",[1053,1649,1650,1653,1656],{"class":1055,"line":1375},[1053,1651,1652],{"class":1159},"    Status",[1053,1654,1655],{"class":1105}," string",[1053,1657,1658],{"class":1093}," `db:\"status\" type:\"text\"`\n",[1053,1660,1661],{"class":1055,"line":1438},[1053,1662,1663],{"class":1068},"}\n",[1053,1665,1667],{"class":1055,"line":1666},19,[1053,1668,1118],{"emptyLinePlaceholder":1117},[1053,1670,1672],{"class":1055,"line":1671},20,[1053,1673,1674],{"class":1058},"// Define statements\n",[1053,1676,1678,1680],{"class":1055,"line":1677},21,[1053,1679,1065],{"class":1064},[1053,1681,1069],{"class":1068},[1053,1683,1685,1687,1689,1691,1693,1695,1697,1699,1701,1703,1705,1707,1709,1711],{"class":1055,"line":1684},22,[1053,1686,1075],{"class":1074},[1053,1688,1078],{"class":1074},[1053,1690,1081],{"class":1074},[1053,1692,1084],{"class":1068},[1053,1694,609],{"class":1087},[1053,1696,1090],{"class":1068},[1053,1698,1094],{"class":1093},[1053,1700,1097],{"class":1068},[1053,1702,1100],{"class":1093},[1053,1704,1097],{"class":1068},[1053,1706,1081],{"class":1105},[1053,1708,1084],{"class":1068},[1053,1710,144],{"class":1105},[1053,1712,1112],{"class":1068},[1053,1714,1716],{"class":1055,"line":1715},23,[1053,1717,1118],{"emptyLinePlaceholder":1117},[1053,1719,1721,1723,1725,1727,1729,1731,1733,1735,1737,1739,1741,1743,1745,1747],{"class":1055,"line":1720},24,[1053,1722,1280],{"class":1074},[1053,1724,1078],{"class":1074},[1053,1726,1081],{"class":1074},[1053,1728,1084],{"class":1068},[1053,1730,614],{"class":1087},[1053,1732,1090],{"class":1068},[1053,1734,1293],{"class":1093},[1053,1736,1097],{"class":1068},[1053,1738,1298],{"class":1093},[1053,1740,1097],{"class":1068},[1053,1742,1081],{"class":1105},[1053,1744,1084],{"class":1068},[1053,1746,149],{"class":1105},[1053,1748,1153],{"class":1068},[1053,1750,1752,1754,1756,1758,1760,1762,1764,1766,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786,1788],{"class":1055,"line":1751},25,[1053,1753,1160],{"class":1159},[1053,1755,1163],{"class":1068},[1053,1757,1216],{"class":1068},[1053,1759,960],{"class":1105},[1053,1761,1084],{"class":1068},[1053,1763,831],{"class":1105},[1053,1765,1175],{"class":1068},[1053,1767,1178],{"class":1159},[1053,1769,1163],{"class":1068},[1053,1771,1332],{"class":1093},[1053,1773,1097],{"class":1068},[1053,1775,1188],{"class":1159},[1053,1777,1163],{"class":1068},[1053,1779,1193],{"class":1093},[1053,1781,1097],{"class":1068},[1053,1783,1198],{"class":1159},[1053,1785,1163],{"class":1068},[1053,1787,1332],{"class":1093},[1053,1789,1205],{"class":1068},[1053,1791,1793],{"class":1055,"line":1792},26,[1053,1794,1269],{"class":1068},[1053,1796,1798],{"class":1055,"line":1797},27,[1053,1799,1118],{"emptyLinePlaceholder":1117},[1053,1801,1803,1806,1808,1810,1812,1814,1816,1819,1821,1824,1826,1828,1830,1833,1835,1837,1839,1841],{"class":1055,"line":1802},28,[1053,1804,1805],{"class":1074},"    CountAll",[1053,1807,1078],{"class":1074},[1053,1809,1081],{"class":1074},[1053,1811,1084],{"class":1068},[1053,1813,629],{"class":1087},[1053,1815,1090],{"class":1068},[1053,1817,1818],{"class":1093},"\"count-all\"",[1053,1820,1097],{"class":1068},[1053,1822,1823],{"class":1093}," \"Count all users\"",[1053,1825,1097],{"class":1068},[1053,1827,1081],{"class":1074},[1053,1829,1084],{"class":1068},[1053,1831,1832],{"class":1074},"AggCount",[1053,1834,1097],{"class":1068},[1053,1836,1081],{"class":1105},[1053,1838,1084],{"class":1068},[1053,1840,164],{"class":1105},[1053,1842,1112],{"class":1068},[1053,1844,1846],{"class":1055,"line":1845},29,[1053,1847,1118],{"emptyLinePlaceholder":1117},[1053,1849,1851,1854,1856,1858,1860,1862,1864,1867,1869,1872,1874,1876,1878,1880],{"class":1055,"line":1850},30,[1053,1852,1853],{"class":1074},"    ActiveUsers",[1053,1855,1078],{"class":1074},[1053,1857,1081],{"class":1074},[1053,1859,1084],{"class":1068},[1053,1861,609],{"class":1087},[1053,1863,1090],{"class":1068},[1053,1865,1866],{"class":1093},"\"active\"",[1053,1868,1097],{"class":1068},[1053,1870,1871],{"class":1093}," \"Query active users\"",[1053,1873,1097],{"class":1068},[1053,1875,1081],{"class":1105},[1053,1877,1084],{"class":1068},[1053,1879,144],{"class":1105},[1053,1881,1153],{"class":1068},[1053,1883,1885,1887,1889,1891,1893,1895,1897],{"class":1055,"line":1884},31,[1053,1886,1160],{"class":1159},[1053,1888,1163],{"class":1068},[1053,1890,1216],{"class":1068},[1053,1892,960],{"class":1105},[1053,1894,1084],{"class":1068},[1053,1896,831],{"class":1105},[1053,1898,1153],{"class":1068},[1053,1900,1902,1905,1907,1909,1911,1913,1915,1917,1919,1921,1923,1925,1927],{"class":1055,"line":1901},32,[1053,1903,1904],{"class":1068},"            {",[1053,1906,1178],{"class":1159},[1053,1908,1163],{"class":1068},[1053,1910,1183],{"class":1093},[1053,1912,1097],{"class":1068},[1053,1914,1188],{"class":1159},[1053,1916,1163],{"class":1068},[1053,1918,1193],{"class":1093},[1053,1920,1097],{"class":1068},[1053,1922,1198],{"class":1159},[1053,1924,1163],{"class":1068},[1053,1926,1183],{"class":1093},[1053,1928,1929],{"class":1068},"},\n",[1053,1931,1933],{"class":1055,"line":1932},33,[1053,1934,1935],{"class":1068},"        },\n",[1053,1937,1939],{"class":1055,"line":1938},34,[1053,1940,1269],{"class":1068},[1053,1942,1944],{"class":1055,"line":1943},35,[1053,1945,1361],{"class":1068},[1053,1947,1949],{"class":1055,"line":1948},36,[1053,1950,1118],{"emptyLinePlaceholder":1117},[1053,1952,1954,1957,1960,1963],{"class":1055,"line":1953},37,[1053,1955,1956],{"class":1064},"func",[1053,1958,1959],{"class":1087}," main",[1053,1961,1962],{"class":1068},"()",[1053,1964,1614],{"class":1068},[1053,1966,1968,1971,1973,1975,1977,1980,1982,1985,1987,1990,1992,1995],{"class":1055,"line":1967},38,[1053,1969,1970],{"class":1074},"    db",[1053,1972,1097],{"class":1068},[1053,1974,1383],{"class":1074},[1053,1976,1386],{"class":1074},[1053,1978,1979],{"class":1074}," sqlx",[1053,1981,1084],{"class":1068},[1053,1983,1984],{"class":1087},"Connect",[1053,1986,1090],{"class":1068},[1053,1988,1989],{"class":1093},"\"postgres\"",[1053,1991,1097],{"class":1068},[1053,1993,1994],{"class":1093}," \"postgres://localhost/mydb?sslmode=disable\"",[1053,1996,1361],{"class":1068},[1053,1998,2000,2003,2005,2008,2010,2013],{"class":1055,"line":1999},39,[1053,2001,2002],{"class":1074},"    ctx",[1053,2004,1386],{"class":1074},[1053,2006,2007],{"class":1074}," context",[1053,2009,1084],{"class":1068},[1053,2011,2012],{"class":1087},"Background",[1053,2014,2015],{"class":1068},"()\n",[1053,2017,2019],{"class":1055,"line":2018},40,[1053,2020,1118],{"emptyLinePlaceholder":1117},[1053,2022,2024],{"class":1055,"line":2023},41,[1053,2025,2026],{"class":1058},"    // Create exec\n",[1053,2028,2030,2033,2035,2037,2039,2041,2043,2045,2047,2050,2053,2056,2058,2061,2063,2066,2068,2070],{"class":1055,"line":2029},42,[1053,2031,2032],{"class":1074},"    exec",[1053,2034,1097],{"class":1068},[1053,2036,1383],{"class":1074},[1053,2038,1386],{"class":1074},[1053,2040,1081],{"class":1074},[1053,2042,1084],{"class":1068},[1053,2044,600],{"class":1087},[1053,2046,1412],{"class":1068},[1053,2048,2049],{"class":1105},"User",[1053,2051,2052],{"class":1068},"](",[1053,2054,2055],{"class":1074},"db",[1053,2057,1097],{"class":1068},[1053,2059,2060],{"class":1093}," \"users\"",[1053,2062,1097],{"class":1068},[1053,2064,2065],{"class":1074}," postgres",[1053,2067,1084],{"class":1068},[1053,2069,600],{"class":1087},[1053,2071,2072],{"class":1068},"())\n",[1053,2074,2076],{"class":1055,"line":2075},43,[1053,2077,1118],{"emptyLinePlaceholder":1117},[1053,2079,2081],{"class":1055,"line":2080},44,[1053,2082,2083],{"class":1058},"    // Execute statements\n",[1053,2085,2087,2090,2092,2094,2096,2098,2100,2102,2104,2106,2108,2111,2113,2116],{"class":1055,"line":2086},45,[1053,2088,2089],{"class":1074},"    users",[1053,2091,1097],{"class":1068},[1053,2093,1383],{"class":1074},[1053,2095,1386],{"class":1074},[1053,2097,1389],{"class":1074},[1053,2099,1084],{"class":1068},[1053,2101,1394],{"class":1087},[1053,2103,1090],{"class":1068},[1053,2105,1399],{"class":1074},[1053,2107,1097],{"class":1068},[1053,2109,2110],{"class":1074}," QueryAll",[1053,2112,1097],{"class":1068},[1053,2114,2115],{"class":1064}," nil",[1053,2117,1361],{"class":1068},[1053,2119,2121,2124,2126,2128,2130,2132,2134,2136,2138,2140,2142,2144,2146,2148,2150,2152,2154,2156,2158,2160,2162,2165],{"class":1055,"line":2120},46,[1053,2122,2123],{"class":1074},"    user",[1053,2125,1097],{"class":1068},[1053,2127,1383],{"class":1074},[1053,2129,1386],{"class":1074},[1053,2131,1389],{"class":1074},[1053,2133,1084],{"class":1068},[1053,2135,1454],{"class":1087},[1053,2137,1090],{"class":1068},[1053,2139,1399],{"class":1074},[1053,2141,1097],{"class":1068},[1053,2143,1463],{"class":1074},[1053,2145,1097],{"class":1068},[1053,2147,1409],{"class":1064},[1053,2149,1412],{"class":1068},[1053,2151,1415],{"class":1105},[1053,2153,1418],{"class":1068},[1053,2155,1421],{"class":1105},[1053,2157,1424],{"class":1068},[1053,2159,1480],{"class":1093},[1053,2161,1163],{"class":1068},[1053,2163,2164],{"class":1259}," 1",[1053,2166,1435],{"class":1068},[1053,2168,2170,2173,2175,2177,2179,2181,2183,2186,2188,2190,2192,2195,2197,2199],{"class":1055,"line":2169},47,[1053,2171,2172],{"class":1074},"    count",[1053,2174,1097],{"class":1068},[1053,2176,1383],{"class":1074},[1053,2178,1386],{"class":1074},[1053,2180,1389],{"class":1074},[1053,2182,1084],{"class":1068},[1053,2184,2185],{"class":1087},"ExecAggregate",[1053,2187,1090],{"class":1068},[1053,2189,1399],{"class":1074},[1053,2191,1097],{"class":1068},[1053,2193,2194],{"class":1074}," CountAll",[1053,2196,1097],{"class":1068},[1053,2198,2115],{"class":1064},[1053,2200,1361],{"class":1068},[1053,2202,2204,2207,2209,2211,2213,2215,2217,2219,2221,2223,2225,2228,2230,2232,2234,2236,2238,2240,2242,2244,2246,2248],{"class":1055,"line":2203},48,[1053,2205,2206],{"class":1074},"    active",[1053,2208,1097],{"class":1068},[1053,2210,1383],{"class":1074},[1053,2212,1386],{"class":1074},[1053,2214,1389],{"class":1074},[1053,2216,1084],{"class":1068},[1053,2218,1394],{"class":1087},[1053,2220,1090],{"class":1068},[1053,2222,1399],{"class":1074},[1053,2224,1097],{"class":1068},[1053,2226,2227],{"class":1074}," ActiveUsers",[1053,2229,1097],{"class":1068},[1053,2231,1409],{"class":1064},[1053,2233,1412],{"class":1068},[1053,2235,1415],{"class":1105},[1053,2237,1418],{"class":1068},[1053,2239,1421],{"class":1105},[1053,2241,1424],{"class":1068},[1053,2243,1427],{"class":1093},[1053,2245,1163],{"class":1068},[1053,2247,1432],{"class":1093},[1053,2249,1435],{"class":1068},[1053,2251,2253],{"class":1055,"line":2252},49,[1053,2254,1118],{"emptyLinePlaceholder":1117},[1053,2256,2258,2261,2263,2266,2268,2271,2275,2278,2281,2284,2287,2290,2292,2295,2299,2301,2303,2307,2309,2311,2314,2317,2319,2322,2324,2327,2329,2331,2333,2336],{"class":1055,"line":2257},50,[1053,2259,2260],{"class":1074},"    fmt",[1053,2262,1084],{"class":1068},[1053,2264,2265],{"class":1087},"Printf",[1053,2267,1090],{"class":1068},[1053,2269,2270],{"class":1093},"\"",[1053,2272,2274],{"class":2273},"scyPU","%d",[1053,2276,2277],{"class":1093}," users, user #1: ",[1053,2279,2280],{"class":2273},"%s",[1053,2282,2283],{"class":1093},", ",[1053,2285,2286],{"class":2273},"%.0f",[1053,2288,2289],{"class":1093}," total, ",[1053,2291,2274],{"class":2273},[1053,2293,2294],{"class":1093}," active",[1053,2296,2298],{"class":2297},"suWN2","\\n",[1053,2300,2270],{"class":1093},[1053,2302,1097],{"class":1068},[1053,2304,2306],{"class":2305},"skxcq"," len",[1053,2308,1090],{"class":1068},[1053,2310,1378],{"class":1074},[1053,2312,2313],{"class":1068},"),",[1053,2315,2316],{"class":1074}," user",[1053,2318,1084],{"class":1068},[1053,2320,2321],{"class":1074},"Name",[1053,2323,1097],{"class":1068},[1053,2325,2326],{"class":1074}," count",[1053,2328,1097],{"class":1068},[1053,2330,2306],{"class":2305},[1053,2332,1090],{"class":1068},[1053,2334,2335],{"class":1074},"active",[1053,2337,2338],{"class":1068},"))\n",[1053,2340,2342],{"class":1055,"line":2341},51,[1053,2343,1663],{"class":1068},[1036,2345,2347],{"id":2346},"capabilities","Capabilities",[2349,2350,2351,2367],"table",{},[2352,2353,2354],"thead",{},[2355,2356,2357,2361,2364],"tr",{},[2358,2359,2360],"th",{},"Feature",[2358,2362,2363],{},"Description",[2358,2365,2366],{},"Docs",[2368,2369,2370,2383,2401,2417,2430],"tbody",{},[2355,2371,2372,2375,2378],{},[2373,2374,27],"td",{},[2373,2376,2377],{},"Query, Select, Aggregate, Insert, Update, Delete",[2373,2379,2380],{},[965,2381,120],{"href":2382},"docs/guides/statements",[2355,2384,2385,2388,2395],{},[2373,2386,2387],{},"Generic Executor",[2373,2389,2390,2391,2394],{},"Type-safe ",[1050,2392,2393],{},"Executor[T]"," with compile-time checking",[2373,2396,2397],{},[965,2398,2400],{"href":2399},"docs/learn/concepts","Concepts",[2355,2402,2403,2406,2412],{},[2373,2404,2405],{},"Multi-Dialect Support",[2373,2407,2408,2409],{},"PostgreSQL, MariaDB, SQLite, SQL Server via ",[965,2410,1519],{"href":1517,"rel":2411},[969],[2373,2413,2414],{},[965,2415,58],{"href":2416},"docs/learn/quickstart",[2355,2418,2419,2422,2425],{},[2373,2420,2421],{},"Declarative Specs",[2373,2423,2424],{},"Queries as pure data structures",[2373,2426,2427],{},[965,2428,16],{"href":2429},"docs/learn/architecture",[2355,2431,2432,2435,2438],{},[2373,2433,2434],{},"Thread-Safe Execution",[2373,2436,2437],{},"Concurrent access, no shared mutable state",[2373,2439,2440],{},[965,2441,2443],{"href":2442},"docs/reference/api","API",[1036,2445,2447],{"id":2446},"why-edamame","Why edamame?",[2449,2450,2451,2467,2473,2479,2485],"ul",{},[2452,2453,2454,2458,2459,2461,2462],"li",{},[2455,2456,2457],"strong",{},"Type-safe"," — Generic ",[1050,2460,2393],{}," with compile-time safety via ",[965,2463,2466],{"href":2464,"rel":2465},"https://github.com/zoobz-io/soy",[969],"soy",[2452,2468,2469,2472],{},[2455,2470,2471],{},"No magic strings"," — Typed statements, not string keys",[2452,2474,2475,2478],{},[2455,2476,2477],{},"Declarative"," — Specs are data, statements wrap them with identity",[2452,2480,2481,2484],{},[2455,2482,2483],{},"Compile-time guarantees"," — Pass wrong statement type? Compiler catches it",[2452,2486,2487,2490],{},[2455,2488,2489],{},"Thread-safe"," — Concurrent execution, no shared mutable state",[1036,2492,2494],{"id":2493},"structural-query-safety","Structural Query Safety",[962,2496,2497,2498,1084],{},"Edamame enables a pattern: ",[2455,2499,2500],{},"define statements once, execute them anywhere",[962,2502,2503],{},"Your query logic lives in typed statements as package-level variables. The executor consumes them with full type safety. No string interpolation, no runtime query building, no SQL injection vectors.",[1044,2505,2507],{"className":1046,"code":2506,"language":1048,"meta":34,"style":34},"// In your repository package\nvar FindActive = edamame.NewQueryStatement(\"find-active\", \"Find active users\", edamame.QuerySpec{\n    Where: []edamame.ConditionSpec{{Field: \"status\", Operator: \"=\", Param: \"status\"}},\n})\n\n// In your service layer\nusers, err := exec.ExecQuery(ctx, FindActive, map[string]any{\"status\": \"active\"})\n",[1050,2508,2509,2514,2549,2590,2594,2598,2603],{"__ignoreMap":34},[1053,2510,2511],{"class":1055,"line":9},[1053,2512,2513],{"class":1058},"// In your repository package\n",[1053,2515,2516,2518,2521,2523,2525,2527,2529,2531,2534,2536,2539,2541,2543,2545,2547],{"class":1055,"line":19},[1053,2517,1065],{"class":1064},[1053,2519,2520],{"class":1074}," FindActive",[1053,2522,1078],{"class":1074},[1053,2524,1081],{"class":1074},[1053,2526,1084],{"class":1068},[1053,2528,609],{"class":1087},[1053,2530,1090],{"class":1068},[1053,2532,2533],{"class":1093},"\"find-active\"",[1053,2535,1097],{"class":1068},[1053,2537,2538],{"class":1093}," \"Find active users\"",[1053,2540,1097],{"class":1068},[1053,2542,1081],{"class":1105},[1053,2544,1084],{"class":1068},[1053,2546,144],{"class":1105},[1053,2548,1153],{"class":1068},[1053,2550,2551,2554,2556,2558,2560,2562,2564,2566,2568,2570,2572,2574,2576,2578,2580,2582,2584,2586,2588],{"class":1055,"line":40},[1053,2552,2553],{"class":1159},"    Where",[1053,2555,1163],{"class":1068},[1053,2557,1216],{"class":1068},[1053,2559,960],{"class":1105},[1053,2561,1084],{"class":1068},[1053,2563,831],{"class":1105},[1053,2565,1175],{"class":1068},[1053,2567,1178],{"class":1159},[1053,2569,1163],{"class":1068},[1053,2571,1183],{"class":1093},[1053,2573,1097],{"class":1068},[1053,2575,1188],{"class":1159},[1053,2577,1163],{"class":1068},[1053,2579,1193],{"class":1093},[1053,2581,1097],{"class":1068},[1053,2583,1198],{"class":1159},[1053,2585,1163],{"class":1068},[1053,2587,1183],{"class":1093},[1053,2589,1205],{"class":1068},[1053,2591,2592],{"class":1055,"line":674},[1053,2593,1435],{"class":1068},[1053,2595,2596],{"class":1055,"line":1121},[1053,2597,1118],{"emptyLinePlaceholder":1117},[1053,2599,2600],{"class":1055,"line":1156},[1053,2601,2602],{"class":1058},"// In your service layer\n",[1053,2604,2605,2607,2609,2612,2614,2616,2618,2620,2622,2624,2626,2628,2630,2632,2634,2636,2638,2640,2642,2644,2646,2648],{"class":1055,"line":1208},[1053,2606,1378],{"class":1074},[1053,2608,1097],{"class":1068},[1053,2610,2611],{"class":1074}," err",[1053,2613,1386],{"class":1074},[1053,2615,1389],{"class":1074},[1053,2617,1084],{"class":1068},[1053,2619,1394],{"class":1087},[1053,2621,1090],{"class":1068},[1053,2623,1399],{"class":1074},[1053,2625,1097],{"class":1068},[1053,2627,2520],{"class":1074},[1053,2629,1097],{"class":1068},[1053,2631,1409],{"class":1064},[1053,2633,1412],{"class":1068},[1053,2635,1415],{"class":1105},[1053,2637,1418],{"class":1068},[1053,2639,1421],{"class":1105},[1053,2641,1424],{"class":1068},[1053,2643,1427],{"class":1093},[1053,2645,1163],{"class":1068},[1053,2647,1432],{"class":1093},[1053,2649,1435],{"class":1068},[962,2651,2652],{},"Statements are the single source of truth. The database dialect handles rendering. Your code stays clean.",[1036,2654,2656],{"id":2655},"documentation","Documentation",[2449,2658,2659],{},[2452,2660,2661,2664],{},[965,2662,6],{"href":2663},"docs/overview"," — Design philosophy and architecture",[2666,2667,897],"h3",{"id":2668},"learn",[2449,2670,2671,2675,2679],{},[2452,2672,2673],{},[965,2674,58],{"href":2416},[2452,2676,2677],{},[965,2678,101],{"href":2399},[2452,2680,2681],{},[965,2682,16],{"href":2429},[2666,2684,909],{"id":2685},"guides",[2449,2687,2688,2692],{},[2452,2689,2690],{},[965,2691,120],{"href":2382},[2452,2693,2694],{},[965,2695,456],{"href":2696},"docs/guides/testing",[2666,2698,925],{"id":2699},"reference",[2449,2701,2702],{},[2452,2703,2704],{},[965,2705,587],{"href":2442},[1036,2707,2709],{"id":2708},"contributing","Contributing",[962,2711,2712,2713,2717],{},"See ",[965,2714,2716],{"href":2715},"CONTRIBUTING","CONTRIBUTING.md"," for guidelines.",[1036,2719,1012],{"id":2720},"license",[962,2722,2723,2724,2726],{},"MIT License — see ",[965,2725,1009],{"href":1009}," for details.",[2728,2729,2730],"style",{},"html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sMAmT, html code.shiki .sMAmT{--shiki-default:var(--shiki-number)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .soy-K, html code.shiki .soy-K{--shiki-default:#BBBBBB}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}html pre.shiki code .suWN2, html code.shiki .suWN2{--shiki-default:var(--shiki-tag)}html pre.shiki code .skxcq, html code.shiki .skxcq{--shiki-default:var(--shiki-builtin)}",{"title":34,"searchDepth":19,"depth":19,"links":2732},[2733,2734,2735,2736,2737,2738,2739,2744,2745],{"id":1038,"depth":19,"text":1039},{"id":1493,"depth":19,"text":1494},{"id":1522,"depth":19,"text":1523},{"id":2346,"depth":19,"text":2347},{"id":2446,"depth":19,"text":2447},{"id":2493,"depth":19,"text":2494},{"id":2655,"depth":19,"text":2656,"children":2740},[2741,2742,2743],{"id":2668,"depth":40,"text":897},{"id":2685,"depth":40,"text":909},{"id":2699,"depth":40,"text":925},{"id":2708,"depth":19,"text":2709},{"id":2720,"depth":19,"text":1012},"md","book-open",{},"/readme",{"title":953,"description":34},"readme","BscYQNVE6yaJgKSiVGtWPnquY2UTEYnFwgQPUaLtbJU",{"id":2754,"title":48,"body":2755,"description":34,"extension":2746,"icon":3188,"meta":3189,"navigation":1117,"path":3190,"seo":3191,"stem":3192,"__hash__":3193},"resources/security.md",{"type":955,"value":2756,"toc":3174},[2757,2761,2765,2768,2807,2811,2814,2818,2823,2826,2865,2869,2872,2921,2925,2951,2955,2958,2962,2965,3061,3065,3068,3099,3103,3106,3131,3135,3149,3153,3156,3162,3165,3171],[958,2758,2760],{"id":2759},"security-policy","Security Policy",[1036,2762,2764],{"id":2763},"supported-versions","Supported Versions",[962,2766,2767],{},"We release patches for security vulnerabilities. Which versions are eligible for receiving such patches depends on the CVSS v3.0 Rating:",[2349,2769,2770,2783],{},[2352,2771,2772],{},[2355,2773,2774,2777,2780],{},[2358,2775,2776],{},"Version",[2358,2778,2779],{},"Supported",[2358,2781,2782],{},"Status",[2368,2784,2785,2796],{},[2355,2786,2787,2790,2793],{},[2373,2788,2789],{},"latest",[2373,2791,2792],{},"✅",[2373,2794,2795],{},"Active development",[2355,2797,2798,2801,2804],{},[2373,2799,2800],{},"\u003C latest",[2373,2802,2803],{},"❌",[2373,2805,2806],{},"Security fixes only for critical issues",[1036,2808,2810],{"id":2809},"reporting-a-vulnerability","Reporting a Vulnerability",[962,2812,2813],{},"We take the security of edamame seriously. If you have discovered a security vulnerability in this project, please report it responsibly.",[2666,2815,2817],{"id":2816},"how-to-report","How to Report",[962,2819,2820],{},[2455,2821,2822],{},"Please DO NOT report security vulnerabilities through public GitHub issues.",[962,2824,2825],{},"Instead, please report them via one of the following methods:",[2827,2828,2829,2852],"ol",{},[2452,2830,2831,2834,2835],{},[2455,2832,2833],{},"GitHub Security Advisories"," (Preferred)",[2449,2836,2837,2846,2849],{},[2452,2838,2839,2840,2845],{},"Go to the ",[965,2841,2844],{"href":2842,"rel":2843},"https://github.com/zoobz-io/edamame/security",[969],"Security tab"," of this repository",[2452,2847,2848],{},"Click \"Report a vulnerability\"",[2452,2850,2851],{},"Fill out the form with details about the vulnerability",[2452,2853,2854,2857],{},[2455,2855,2856],{},"Email",[2449,2858,2859,2862],{},[2452,2860,2861],{},"Send details to the repository maintainer through GitHub profile contact information",[2452,2863,2864],{},"Use PGP encryption if possible for sensitive details",[2666,2866,2868],{"id":2867},"what-to-include","What to Include",[962,2870,2871],{},"Please include the following information (as much as you can provide) to help us better understand the nature and scope of the possible issue:",[2449,2873,2874,2880,2886,2892,2898,2903,2909,2915],{},[2452,2875,2876,2879],{},[2455,2877,2878],{},"Type of issue"," (e.g., SQL injection, race condition, information disclosure, etc.)",[2452,2881,2882,2885],{},[2455,2883,2884],{},"Full paths of source file(s)"," related to the manifestation of the issue",[2452,2887,2888,2891],{},[2455,2889,2890],{},"The location of the affected source code"," (tag/branch/commit or direct URL)",[2452,2893,2894,2897],{},[2455,2895,2896],{},"Any special configuration required"," to reproduce the issue",[2452,2899,2900,2897],{},[2455,2901,2902],{},"Step-by-step instructions",[2452,2904,2905,2908],{},[2455,2906,2907],{},"Proof-of-concept or exploit code"," (if possible)",[2452,2910,2911,2914],{},[2455,2912,2913],{},"Impact of the issue",", including how an attacker might exploit the issue",[2452,2916,2917,2920],{},[2455,2918,2919],{},"Your name and affiliation"," (optional)",[2666,2922,2924],{"id":2923},"what-to-expect","What to Expect",[2449,2926,2927,2933,2939,2945],{},[2452,2928,2929,2932],{},[2455,2930,2931],{},"Acknowledgment",": We will acknowledge receipt of your vulnerability report within 48 hours",[2452,2934,2935,2938],{},[2455,2936,2937],{},"Initial Assessment",": Within 7 days, we will provide an initial assessment of the report",[2452,2940,2941,2944],{},[2455,2942,2943],{},"Resolution Timeline",": We aim to resolve critical issues within 30 days",[2452,2946,2947,2950],{},[2455,2948,2949],{},"Disclosure",": We will coordinate with you on the disclosure timeline",[2666,2952,2954],{"id":2953},"preferred-languages","Preferred Languages",[962,2956,2957],{},"We prefer all communications to be in English.",[1036,2959,2961],{"id":2960},"security-best-practices","Security Best Practices",[962,2963,2964],{},"When using edamame in your applications, we recommend:",[2827,2966,2967,2988,3007,3026,3045],{},[2452,2968,2969,2972],{},[2455,2970,2971],{},"Keep Dependencies Updated",[1044,2973,2975],{"className":1497,"code":2974,"language":1499,"meta":34,"style":34},"go get -u github.com/zoobz-io/edamame\n",[1050,2976,2977],{"__ignoreMap":34},[1053,2978,2979,2981,2983,2986],{"class":1055,"line":9},[1053,2980,1048],{"class":1087},[1053,2982,1508],{"class":1093},[1053,2984,2985],{"class":1064}," -u",[1053,2987,1511],{"class":1093},[2452,2989,2990,2993],{},[2455,2991,2992],{},"Database Security",[2449,2994,2995,2998,3001,3004],{},[2452,2996,2997],{},"Use least-privilege database accounts",[2452,2999,3000],{},"Never expose factory specs publicly without authentication",[2452,3002,3003],{},"Validate all user input before passing to capabilities",[2452,3005,3006],{},"Use transactions for multi-step operations",[2452,3008,3009,3012],{},[2455,3010,3011],{},"LLM Integration Security",[2449,3013,3014,3017,3020,3023],{},[2452,3015,3016],{},"Always validate LLM-generated capability names and params",[2452,3018,3019],{},"Rate limit LLM-driven database operations",[2452,3021,3022],{},"Audit log all LLM-executed queries",[2452,3024,3025],{},"Never expose raw SQL generation to external systems",[2452,3027,3028,3031],{},[2455,3029,3030],{},"Capability Management",[2449,3032,3033,3036,3039,3042],{},[2452,3034,3035],{},"Only expose capabilities that are safe for your use case",[2452,3037,3038],{},"Use explicit params with validation",[2452,3040,3041],{},"Avoid overly permissive WHERE clauses",[2452,3043,3044],{},"Review auto-derived params before deployment",[2452,3046,3047,3050],{},[2455,3048,3049],{},"Error Handling",[2449,3051,3052,3055,3058],{},[2452,3053,3054],{},"Implement proper error handling",[2452,3056,3057],{},"Don't expose internal errors to users",[2452,3059,3060],{},"Log errors appropriately",[1036,3062,3064],{"id":3063},"security-features","Security Features",[962,3066,3067],{},"edamame includes several built-in security features:",[2449,3069,3070,3076,3081,3087,3093],{},[2452,3071,3072,3075],{},[2455,3073,3074],{},"Parameterized Queries",": All queries use parameterized SQL via sqlx, preventing SQL injection",[2452,3077,3078,3080],{},[2455,3079,37],{},": Generic types prevent type confusion",[2452,3082,3083,3086],{},[2455,3084,3085],{},"Spec Validation",": Capability specs are validated before execution",[2452,3088,3089,3092],{},[2455,3090,3091],{},"No Raw SQL",": Users define specs, not raw SQL strings",[2452,3094,3095,3098],{},[2455,3096,3097],{},"Introspection Only",": Spec export is read-only, doesn't expose credentials",[1036,3100,3102],{"id":3101},"automated-security-scanning","Automated Security Scanning",[962,3104,3105],{},"This project uses:",[2449,3107,3108,3113,3119,3125],{},[2452,3109,3110,3112],{},[2455,3111,997],{},": GitHub's semantic code analysis for security vulnerabilities",[2452,3114,3115,3118],{},[2455,3116,3117],{},"gosec",": Go security checker for common vulnerabilities",[2452,3120,3121,3124],{},[2455,3122,3123],{},"golangci-lint",": Static analysis including security linters (sqlclosecheck, noctx, bodyclose)",[2452,3126,3127,3130],{},[2455,3128,3129],{},"Codecov",": Coverage tracking to ensure security-critical code is tested",[1036,3132,3134],{"id":3133},"vulnerability-disclosure-policy","Vulnerability Disclosure Policy",[2449,3136,3137,3140,3143,3146],{},[2452,3138,3139],{},"Security vulnerabilities will be disclosed via GitHub Security Advisories",[2452,3141,3142],{},"We follow a 90-day disclosure timeline for non-critical issues",[2452,3144,3145],{},"Critical vulnerabilities may be disclosed sooner after patches are available",[2452,3147,3148],{},"We will credit reporters who follow responsible disclosure practices",[1036,3150,3152],{"id":3151},"credits","Credits",[962,3154,3155],{},"We thank the following individuals for responsibly disclosing security issues:",[962,3157,3158],{},[3159,3160,3161],"em",{},"This list is currently empty. Be the first to help improve our security!",[3163,3164],"hr",{},[962,3166,3167,3170],{},[2455,3168,3169],{},"Last Updated",": 2025-12-17",[2728,3172,3173],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":34,"searchDepth":19,"depth":19,"links":3175},[3176,3177,3183,3184,3185,3186,3187],{"id":2763,"depth":19,"text":2764},{"id":2809,"depth":19,"text":2810,"children":3178},[3179,3180,3181,3182],{"id":2816,"depth":40,"text":2817},{"id":2867,"depth":40,"text":2868},{"id":2923,"depth":40,"text":2924},{"id":2953,"depth":40,"text":2954},{"id":2960,"depth":19,"text":2961},{"id":3063,"depth":19,"text":3064},{"id":3101,"depth":19,"text":3102},{"id":3133,"depth":19,"text":3134},{"id":3151,"depth":19,"text":3152},"shield",{},"/security",{"title":48,"description":34},"security","Sx8ErY-iTzxHLX7iGbih6ydeebS0veDo30qsuQcZLEI",{"id":3195,"title":2709,"body":3196,"description":3204,"extension":2746,"icon":1050,"meta":3699,"navigation":1117,"path":3700,"seo":3701,"stem":2708,"__hash__":3702},"resources/contributing.md",{"type":955,"value":3197,"toc":3675},[3198,3202,3205,3209,3212,3216,3260,3264,3268,3286,3289,3312,3314,3328,3332,3336,3350,3354,3365,3369,3372,3386,3390,3418,3421,3424,3437,3440,3452,3455,3467,3470,3482,3485,3497,3501,3509,3513,3516,3560,3564,3568,3571,3582,3585,3599,3603,3630,3636,3640,3643,3654,3658,3669,3672],[958,3199,3201],{"id":3200},"contributing-to-edamame","Contributing to edamame",[962,3203,3204],{},"Thank you for your interest in contributing to edamame! This guide will help you get started.",[1036,3206,3208],{"id":3207},"code-of-conduct","Code of Conduct",[962,3210,3211],{},"By participating in this project, you agree to maintain a respectful and inclusive environment for all contributors.",[1036,3213,3215],{"id":3214},"getting-started","Getting Started",[2827,3217,3218,3221,3227,3233,3236,3242,3248,3251,3257],{},[2452,3219,3220],{},"Fork the repository",[2452,3222,3223,3224],{},"Clone your fork: ",[1050,3225,3226],{},"git clone https://github.com/yourusername/edamame.git",[2452,3228,3229,3230],{},"Create a feature branch: ",[1050,3231,3232],{},"git checkout -b feature/your-feature-name",[2452,3234,3235],{},"Make your changes",[2452,3237,3238,3239],{},"Run tests: ",[1050,3240,3241],{},"make test",[2452,3243,3244,3245],{},"Run linters: ",[1050,3246,3247],{},"make lint",[2452,3249,3250],{},"Commit your changes with a descriptive message",[2452,3252,3253,3254],{},"Push to your fork: ",[1050,3255,3256],{},"git push origin feature/your-feature-name",[2452,3258,3259],{},"Create a Pull Request",[1036,3261,3263],{"id":3262},"development-guidelines","Development Guidelines",[2666,3265,3267],{"id":3266},"code-style","Code Style",[2449,3269,3270,3273,3280,3283],{},[2452,3271,3272],{},"Follow standard Go conventions",[2452,3274,3275,3276,3279],{},"Run ",[1050,3277,3278],{},"go fmt"," before committing",[2452,3281,3282],{},"Add comments for exported functions and types",[2452,3284,3285],{},"Keep functions small and focused",[2666,3287,456],{"id":3288},"testing",[2449,3290,3291,3294,3299,3302,3305],{},[2452,3292,3293],{},"Write tests for new functionality",[2452,3295,3296,3297],{},"Ensure all tests pass: ",[1050,3298,3241],{},[2452,3300,3301],{},"Maintain 1:1 file-to-test ratio",[2452,3303,3304],{},"Aim for 80%+ test coverage",[2452,3306,3307,3308,3311],{},"Use the ",[1050,3309,3310],{},"testing/"," package helpers for capability testing",[2666,3313,2656],{"id":2655},[2449,3315,3316,3319,3322,3325],{},[2452,3317,3318],{},"Update README.md for API changes",[2452,3320,3321],{},"Add comments to all exported types",[2452,3323,3324],{},"Keep doc comments clear and concise",[2452,3326,3327],{},"Update docs/ for significant changes",[1036,3329,3331],{"id":3330},"types-of-contributions","Types of Contributions",[2666,3333,3335],{"id":3334},"bug-reports","Bug Reports",[2449,3337,3338,3341,3344,3347],{},[2452,3339,3340],{},"Use GitHub Issues",[2452,3342,3343],{},"Include minimal reproduction code",[2452,3345,3346],{},"Describe expected vs actual behavior",[2452,3348,3349],{},"Include Go version and OS",[2666,3351,3353],{"id":3352},"feature-requests","Feature Requests",[2449,3355,3356,3359,3362],{},[2452,3357,3358],{},"Open an issue for discussion first",[2452,3360,3361],{},"Explain the use case",[2452,3363,3364],{},"Consider backwards compatibility",[2666,3366,3368],{"id":3367},"code-contributions","Code Contributions",[962,3370,3371],{},"All contributions should:",[2449,3373,3374,3377,3380,3383],{},[2452,3375,3376],{},"Include comprehensive tests",[2452,3378,3379],{},"Pass linter checks",[2452,3381,3382],{},"Maintain existing code style",[2452,3384,3385],{},"Update documentation as needed",[1036,3387,3389],{"id":3388},"pull-request-process","Pull Request Process",[2827,3391,3392,3398,3403,3408,3413],{},[2452,3393,3394,3397],{},[2455,3395,3396],{},"Keep PRs focused"," - One feature/fix per PR",[2452,3399,3400],{},[2455,3401,3402],{},"Write descriptive commit messages",[2452,3404,3405],{},[2455,3406,3407],{},"Update tests and documentation",[2452,3409,3410],{},[2455,3411,3412],{},"Ensure CI passes",[2452,3414,3415],{},[2455,3416,3417],{},"Respond to review feedback",[1036,3419,456],{"id":3420},"testing-1",[962,3422,3423],{},"Run the full test suite:",[1044,3425,3427],{"className":1497,"code":3426,"language":1499,"meta":34,"style":34},"make test\n",[1050,3428,3429],{"__ignoreMap":34},[1053,3430,3431,3434],{"class":1055,"line":9},[1053,3432,3433],{"class":1087},"make",[1053,3435,3436],{"class":1093}," test\n",[962,3438,3439],{},"Run with coverage:",[1044,3441,3443],{"className":1497,"code":3442,"language":1499,"meta":34,"style":34},"make coverage\n",[1050,3444,3445],{"__ignoreMap":34},[1053,3446,3447,3449],{"class":1055,"line":9},[1053,3448,3433],{"class":1087},[1053,3450,3451],{"class":1093}," coverage\n",[962,3453,3454],{},"Run linters:",[1044,3456,3458],{"className":1497,"code":3457,"language":1499,"meta":34,"style":34},"make lint\n",[1050,3459,3460],{"__ignoreMap":34},[1053,3461,3462,3464],{"class":1055,"line":9},[1053,3463,3433],{"class":1087},[1053,3465,3466],{"class":1093}," lint\n",[962,3468,3469],{},"Run integration tests (requires Docker):",[1044,3471,3473],{"className":1497,"code":3472,"language":1499,"meta":34,"style":34},"make test-integration\n",[1050,3474,3475],{"__ignoreMap":34},[1053,3476,3477,3479],{"class":1055,"line":9},[1053,3478,3433],{"class":1087},[1053,3480,3481],{"class":1093}," test-integration\n",[962,3483,3484],{},"Run full CI simulation:",[1044,3486,3488],{"className":1497,"code":3487,"language":1499,"meta":34,"style":34},"make ci\n",[1050,3489,3490],{"__ignoreMap":34},[1053,3491,3492,3494],{"class":1055,"line":9},[1053,3493,3433],{"class":1087},[1053,3495,3496],{"class":1093}," ci\n",[1036,3498,3500],{"id":3499},"project-structure","Project Structure",[1044,3502,3507],{"className":3503,"code":3505,"language":3506},[3504],"language-text","edamame/\n├── *.go              # Core library files\n├── *_test.go         # Tests (1:1 with source files)\n├── testing/          # Test helpers and benchmarks\n│   ├── helpers.go    # Test utilities\n│   ├── benchmarks/   # Performance benchmarks\n│   └── integration/  # Database integration tests\n├── docs/             # Documentation\n├── .github/          # GitHub workflows and templates\n├── README.md         # Project documentation\n└── Makefile          # Build and test commands\n","text",[1050,3508,3505],{"__ignoreMap":34},[1036,3510,3512],{"id":3511},"commit-messages","Commit Messages",[962,3514,3515],{},"Follow conventional commits:",[2449,3517,3518,3524,3530,3536,3542,3548,3554],{},[2452,3519,3520,3523],{},[1050,3521,3522],{},"feat:"," New feature",[2452,3525,3526,3529],{},[1050,3527,3528],{},"fix:"," Bug fix",[2452,3531,3532,3535],{},[1050,3533,3534],{},"docs:"," Documentation changes",[2452,3537,3538,3541],{},[1050,3539,3540],{},"test:"," Test additions/changes",[2452,3543,3544,3547],{},[1050,3545,3546],{},"refactor:"," Code refactoring",[2452,3549,3550,3553],{},[1050,3551,3552],{},"perf:"," Performance improvements",[2452,3555,3556,3559],{},[1050,3557,3558],{},"chore:"," Maintenance tasks",[1036,3561,3563],{"id":3562},"release-process","Release Process",[2666,3565,3567],{"id":3566},"automated-releases","Automated Releases",[962,3569,3570],{},"This project uses automated release versioning. To create a release:",[2827,3572,3573,3576,3579],{},[2452,3574,3575],{},"Go to Actions → Release → Run workflow",[2452,3577,3578],{},"Leave \"Version override\" empty for automatic version inference",[2452,3580,3581],{},"Click \"Run workflow\"",[962,3583,3584],{},"The system will:",[2449,3586,3587,3590,3593,3596],{},[2452,3588,3589],{},"Automatically determine the next version from conventional commits",[2452,3591,3592],{},"Create a git tag",[2452,3594,3595],{},"Generate release notes via GoReleaser",[2452,3597,3598],{},"Publish the release to GitHub",[2666,3600,3602],{"id":3601},"commit-conventions-for-versioning","Commit Conventions for Versioning",[2449,3604,3605,3610,3615,3621],{},[2452,3606,3607,3609],{},[1050,3608,3522],{}," new features (minor version: 1.2.0 → 1.3.0)",[2452,3611,3612,3614],{},[1050,3613,3528],{}," bug fixes (patch version: 1.2.0 → 1.2.1)",[2452,3616,3617,3620],{},[1050,3618,3619],{},"feat!:"," breaking changes (major version: 1.2.0 → 2.0.0)",[2452,3622,3623,2283,3625,2283,3627,3629],{},[1050,3624,3534],{},[1050,3626,3540],{},[1050,3628,3558],{}," no version change",[962,3631,3632,3633],{},"Example: ",[1050,3634,3635],{},"feat(factory): add batch delete support",[2666,3637,3639],{"id":3638},"version-preview-on-pull-requests","Version Preview on Pull Requests",[962,3641,3642],{},"Every PR automatically shows the next version that will be created:",[2449,3644,3645,3648,3651],{},[2452,3646,3647],{},"Check PR comments for \"Version Preview\"",[2452,3649,3650],{},"Updates automatically as you add commits",[2452,3652,3653],{},"Helps verify your commits have the intended effect",[1036,3655,3657],{"id":3656},"questions","Questions?",[2449,3659,3660,3663,3666],{},[2452,3661,3662],{},"Open an issue for questions",[2452,3664,3665],{},"Check existing issues first",[2452,3667,3668],{},"Be patient and respectful",[962,3670,3671],{},"Thank you for contributing to edamame!",[2728,3673,3674],{},"html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":34,"searchDepth":19,"depth":19,"links":3676},[3677,3678,3679,3684,3689,3690,3691,3692,3693,3698],{"id":3207,"depth":19,"text":3208},{"id":3214,"depth":19,"text":3215},{"id":3262,"depth":19,"text":3263,"children":3680},[3681,3682,3683],{"id":3266,"depth":40,"text":3267},{"id":3288,"depth":40,"text":456},{"id":2655,"depth":40,"text":2656},{"id":3330,"depth":19,"text":3331,"children":3685},[3686,3687,3688],{"id":3334,"depth":40,"text":3335},{"id":3352,"depth":40,"text":3353},{"id":3367,"depth":40,"text":3368},{"id":3388,"depth":19,"text":3389},{"id":3420,"depth":19,"text":456},{"id":3499,"depth":19,"text":3500},{"id":3511,"depth":19,"text":3512},{"id":3562,"depth":19,"text":3563,"children":3694},[3695,3696,3697],{"id":3566,"depth":40,"text":3567},{"id":3601,"depth":40,"text":3602},{"id":3638,"depth":40,"text":3639},{"id":3656,"depth":19,"text":3657},{},"/contributing",{"title":2709,"description":3204},"QcMmj_qs3DqAuZIWSIkA2CW6kAKXQPr0ftDXK0qwA9k",{"id":3704,"title":587,"author":3705,"body":3706,"description":589,"extension":2746,"meta":8329,"navigation":1117,"path":586,"published":8330,"readtime":8331,"seo":8332,"stem":930,"tags":8333,"updated":8335,"__hash__":8336},"edamame/v1.0.3/5.reference/1.api.md","zoobzio",{"type":955,"value":3707,"toc":8284},[3708,3711,3718,3721,3723,3726,3805,3811,3817,3843,3900,3903,3906,3953,3956,3959,4001,4004,4007,4049,4052,4055,4097,4100,4103,4153,4156,4159,4162,4289,4292,4294,4297,4299,4302,4304,4307,4309,4312,4314,4317,4320,4324,4382,4385,4388,4443,4446,4449,4504,4507,4510,4565,4568,4571,4621,4624,4627,4670,4673,4676,4732,4735,4738,4741,4894,4897,4900,5047,5050,5053,5200,5203,5206,5350,5353,5356,5500,5503,5506,5630,5633,5636,5783,5786,5789,5792,5916,5919,5922,6071,6074,6077,6224,6227,6230,6237,6240,6316,6319,6322,6396,6399,6402,6470,6473,6476,6479,6523,6526,6529,6531,6573,6576,6579,6610,6613,6616,6619,6777,6780,6909,6912,6958,6961,6988,6991,7025,7028,7153,7156,7250,7253,7319,7322,7378,7381,7384,7480,7485,7627,7630,7633,7689,7692,7695,7772,7775,7778,7818,7821,7911,7914,7993,7996,8037,8040,8156,8159,8162,8218,8281],[958,3709,587],{"id":3710},"api-reference",[962,3712,3713,3714,3717],{},"Complete API reference for the ",[1050,3715,3716],{},"github.com/zoobz-io/edamame"," package.",[1036,3719,110],{"id":3720},"executor",[962,3722,597],{},[2666,3724,600],{"id":3725},"new",[1044,3727,3729],{"className":1046,"code":3728,"language":1048,"meta":34,"style":34},"func New[T any](db *sqlx.DB, tableName string, renderer astql.Renderer) (*Executor[T], error)\n",[1050,3730,3731],{"__ignoreMap":34},[1053,3732,3733,3735,3738,3740,3743,3746,3748,3750,3754,3757,3759,3762,3764,3767,3769,3771,3774,3777,3779,3782,3785,3788,3791,3793,3795,3797,3800,3803],{"class":1055,"line":9},[1053,3734,1956],{"class":1064},[1053,3736,3737],{"class":1087}," New",[1053,3739,1412],{"class":1068},[1053,3741,3742],{"class":1572},"T",[1053,3744,3745],{"class":1105}," any",[1053,3747,2052],{"class":1068},[1053,3749,2055],{"class":1572},[1053,3751,3753],{"class":3752},"sW3Qg"," *",[1053,3755,3756],{"class":1105},"sqlx",[1053,3758,1084],{"class":1068},[1053,3760,3761],{"class":1105},"DB",[1053,3763,1097],{"class":1068},[1053,3765,3766],{"class":1572}," tableName",[1053,3768,1655],{"class":1105},[1053,3770,1097],{"class":1068},[1053,3772,3773],{"class":1572}," renderer",[1053,3775,3776],{"class":1105}," astql",[1053,3778,1084],{"class":1068},[1053,3780,3781],{"class":1105},"Renderer",[1053,3783,3784],{"class":1068},")",[1053,3786,3787],{"class":1068}," (",[1053,3789,3790],{"class":3752},"*",[1053,3792,110],{"class":1105},[1053,3794,1412],{"class":1068},[1053,3796,3742],{"class":1105},[1053,3798,3799],{"class":1068},"],",[1053,3801,3802],{"class":1105}," error",[1053,3804,1361],{"class":1068},[962,3806,3807,3808,3810],{},"Creates a new executor for type T bound to the given table with the specified SQL renderer. The ",[1050,3809,2055],{}," parameter can be nil for testing statement rendering without database access.",[962,3812,3813,3814,1163],{},"Supported renderers via ",[965,3815,1519],{"href":1517,"rel":3816},[969],[2449,3818,3819,3825,3831,3837],{},[2452,3820,3821,3824],{},[1050,3822,3823],{},"github.com/zoobz-io/astql/pkg/postgres"," - PostgreSQL",[2452,3826,3827,3830],{},[1050,3828,3829],{},"github.com/zoobz-io/astql/pkg/mariadb"," - MariaDB",[2452,3832,3833,3836],{},[1050,3834,3835],{},"github.com/zoobz-io/astql/pkg/sqlite"," - SQLite",[2452,3838,3839,3842],{},[1050,3840,3841],{},"github.com/zoobz-io/astql/pkg/mssql"," - SQL Server",[1044,3844,3846],{"className":1046,"code":3845,"language":1048,"meta":34,"style":34},"import \"github.com/zoobz-io/astql/pkg/postgres\" // or mariadb, sqlite, mssql\n\nexec, err := edamame.New[User](db, \"users\", postgres.New())\n",[1050,3847,3848,3857,3861],{"__ignoreMap":34},[1053,3849,3850,3852,3855],{"class":1055,"line":9},[1053,3851,1545],{"class":1064},[1053,3853,3854],{"class":1093}," \"github.com/zoobz-io/astql/pkg/postgres\"",[1053,3856,1587],{"class":1058},[1053,3858,3859],{"class":1055,"line":19},[1053,3860,1118],{"emptyLinePlaceholder":1117},[1053,3862,3863,3866,3868,3870,3872,3874,3876,3878,3880,3882,3884,3886,3888,3890,3892,3894,3896,3898],{"class":1055,"line":40},[1053,3864,3865],{"class":1074},"exec",[1053,3867,1097],{"class":1068},[1053,3869,2611],{"class":1074},[1053,3871,1386],{"class":1074},[1053,3873,1081],{"class":1074},[1053,3875,1084],{"class":1068},[1053,3877,600],{"class":1087},[1053,3879,1412],{"class":1068},[1053,3881,2049],{"class":1105},[1053,3883,2052],{"class":1068},[1053,3885,2055],{"class":1074},[1053,3887,1097],{"class":1068},[1053,3889,2060],{"class":1093},[1053,3891,1097],{"class":1068},[1053,3893,2065],{"class":1074},[1053,3895,1084],{"class":1068},[1053,3897,600],{"class":1087},[1053,3899,2072],{"class":1068},[1036,3901,605],{"id":3902},"statement-constructors",[2666,3904,609],{"id":3905},"newquerystatement",[1044,3907,3909],{"className":1046,"code":3908,"language":1048,"meta":34,"style":34},"func NewQueryStatement(name, description string, spec QuerySpec, tags ...string) QueryStatement\n",[1050,3910,3911],{"__ignoreMap":34},[1053,3912,3913,3915,3918,3920,3923,3925,3928,3930,3932,3935,3938,3940,3943,3946,3948,3950],{"class":1055,"line":9},[1053,3914,1956],{"class":1064},[1053,3916,3917],{"class":1087}," NewQueryStatement",[1053,3919,1090],{"class":1068},[1053,3921,3922],{"class":1572},"name",[1053,3924,1097],{"class":1068},[1053,3926,3927],{"class":1572}," description",[1053,3929,1655],{"class":1105},[1053,3931,1097],{"class":1068},[1053,3933,3934],{"class":1572}," spec",[1053,3936,3937],{"class":1105}," QuerySpec",[1053,3939,1097],{"class":1068},[1053,3941,3942],{"class":1572}," tags",[1053,3944,3945],{"class":3752}," ...",[1053,3947,1415],{"class":1105},[1053,3949,3784],{"class":1068},[1053,3951,3952],{"class":1105}," QueryStatement\n",[962,3954,3955],{},"Creates a typed query statement for multi-record retrieval. Parameters are automatically derived from the spec.",[2666,3957,614],{"id":3958},"newselectstatement",[1044,3960,3962],{"className":1046,"code":3961,"language":1048,"meta":34,"style":34},"func NewSelectStatement(name, description string, spec SelectSpec, tags ...string) SelectStatement\n",[1050,3963,3964],{"__ignoreMap":34},[1053,3965,3966,3968,3971,3973,3975,3977,3979,3981,3983,3985,3988,3990,3992,3994,3996,3998],{"class":1055,"line":9},[1053,3967,1956],{"class":1064},[1053,3969,3970],{"class":1087}," NewSelectStatement",[1053,3972,1090],{"class":1068},[1053,3974,3922],{"class":1572},[1053,3976,1097],{"class":1068},[1053,3978,3927],{"class":1572},[1053,3980,1655],{"class":1105},[1053,3982,1097],{"class":1068},[1053,3984,3934],{"class":1572},[1053,3986,3987],{"class":1105}," SelectSpec",[1053,3989,1097],{"class":1068},[1053,3991,3942],{"class":1572},[1053,3993,3945],{"class":3752},[1053,3995,1415],{"class":1105},[1053,3997,3784],{"class":1068},[1053,3999,4000],{"class":1105}," SelectStatement\n",[962,4002,4003],{},"Creates a typed select statement for single-record retrieval.",[2666,4005,619],{"id":4006},"newupdatestatement",[1044,4008,4010],{"className":1046,"code":4009,"language":1048,"meta":34,"style":34},"func NewUpdateStatement(name, description string, spec UpdateSpec, tags ...string) UpdateStatement\n",[1050,4011,4012],{"__ignoreMap":34},[1053,4013,4014,4016,4019,4021,4023,4025,4027,4029,4031,4033,4036,4038,4040,4042,4044,4046],{"class":1055,"line":9},[1053,4015,1956],{"class":1064},[1053,4017,4018],{"class":1087}," NewUpdateStatement",[1053,4020,1090],{"class":1068},[1053,4022,3922],{"class":1572},[1053,4024,1097],{"class":1068},[1053,4026,3927],{"class":1572},[1053,4028,1655],{"class":1105},[1053,4030,1097],{"class":1068},[1053,4032,3934],{"class":1572},[1053,4034,4035],{"class":1105}," UpdateSpec",[1053,4037,1097],{"class":1068},[1053,4039,3942],{"class":1572},[1053,4041,3945],{"class":3752},[1053,4043,1415],{"class":1105},[1053,4045,3784],{"class":1068},[1053,4047,4048],{"class":1105}," UpdateStatement\n",[962,4050,4051],{},"Creates a typed update statement for modifications.",[2666,4053,624],{"id":4054},"newdeletestatement",[1044,4056,4058],{"className":1046,"code":4057,"language":1048,"meta":34,"style":34},"func NewDeleteStatement(name, description string, spec DeleteSpec, tags ...string) DeleteStatement\n",[1050,4059,4060],{"__ignoreMap":34},[1053,4061,4062,4064,4067,4069,4071,4073,4075,4077,4079,4081,4084,4086,4088,4090,4092,4094],{"class":1055,"line":9},[1053,4063,1956],{"class":1064},[1053,4065,4066],{"class":1087}," NewDeleteStatement",[1053,4068,1090],{"class":1068},[1053,4070,3922],{"class":1572},[1053,4072,1097],{"class":1068},[1053,4074,3927],{"class":1572},[1053,4076,1655],{"class":1105},[1053,4078,1097],{"class":1068},[1053,4080,3934],{"class":1572},[1053,4082,4083],{"class":1105}," DeleteSpec",[1053,4085,1097],{"class":1068},[1053,4087,3942],{"class":1572},[1053,4089,3945],{"class":3752},[1053,4091,1415],{"class":1105},[1053,4093,3784],{"class":1068},[1053,4095,4096],{"class":1105}," DeleteStatement\n",[962,4098,4099],{},"Creates a typed delete statement for deletions.",[2666,4101,629],{"id":4102},"newaggregatestatement",[1044,4104,4106],{"className":1046,"code":4105,"language":1048,"meta":34,"style":34},"func NewAggregateStatement(name, description string, fn AggregateFunc, spec AggregateSpec, tags ...string) AggregateStatement\n",[1050,4107,4108],{"__ignoreMap":34},[1053,4109,4110,4112,4115,4117,4119,4121,4123,4125,4127,4130,4133,4135,4137,4140,4142,4144,4146,4148,4150],{"class":1055,"line":9},[1053,4111,1956],{"class":1064},[1053,4113,4114],{"class":1087}," NewAggregateStatement",[1053,4116,1090],{"class":1068},[1053,4118,3922],{"class":1572},[1053,4120,1097],{"class":1068},[1053,4122,3927],{"class":1572},[1053,4124,1655],{"class":1105},[1053,4126,1097],{"class":1068},[1053,4128,4129],{"class":1572}," fn",[1053,4131,4132],{"class":1105}," AggregateFunc",[1053,4134,1097],{"class":1068},[1053,4136,3934],{"class":1572},[1053,4138,4139],{"class":1105}," AggregateSpec",[1053,4141,1097],{"class":1068},[1053,4143,3942],{"class":1572},[1053,4145,3945],{"class":3752},[1053,4147,1415],{"class":1105},[1053,4149,3784],{"class":1068},[1053,4151,4152],{"class":1105}," AggregateStatement\n",[962,4154,4155],{},"Creates a typed aggregate statement for COUNT, SUM, AVG, MIN, MAX operations.",[1036,4157,27],{"id":4158},"statement-types",[962,4160,4161],{},"All statement types share common methods:",[1044,4163,4165],{"className":1046,"code":4164,"language":1048,"meta":34,"style":34},"func (s Statement) ID() uuid.UUID      // Unique identifier\nfunc (s Statement) Name() string       // Human-readable name\nfunc (s Statement) Description() string // What the statement does\nfunc (s Statement) Params() []ParamSpec // Required parameters\nfunc (s Statement) Tags() []string     // Optional categorization tags\n",[1050,4166,4167,4197,4219,4241,4265],{"__ignoreMap":34},[1053,4168,4169,4171,4173,4176,4179,4181,4184,4186,4189,4191,4194],{"class":1055,"line":9},[1053,4170,1956],{"class":1064},[1053,4172,3787],{"class":1068},[1053,4174,4175],{"class":1572},"s ",[1053,4177,4178],{"class":1105},"Statement",[1053,4180,3784],{"class":1068},[1053,4182,4183],{"class":1087}," ID",[1053,4185,1962],{"class":1068},[1053,4187,4188],{"class":1105}," uuid",[1053,4190,1084],{"class":1068},[1053,4192,4193],{"class":1105},"UUID",[1053,4195,4196],{"class":1058},"      // Unique identifier\n",[1053,4198,4199,4201,4203,4205,4207,4209,4212,4214,4216],{"class":1055,"line":19},[1053,4200,1956],{"class":1064},[1053,4202,3787],{"class":1068},[1053,4204,4175],{"class":1572},[1053,4206,4178],{"class":1105},[1053,4208,3784],{"class":1068},[1053,4210,4211],{"class":1087}," Name",[1053,4213,1962],{"class":1068},[1053,4215,1655],{"class":1105},[1053,4217,4218],{"class":1058},"       // Human-readable name\n",[1053,4220,4221,4223,4225,4227,4229,4231,4234,4236,4238],{"class":1055,"line":40},[1053,4222,1956],{"class":1064},[1053,4224,3787],{"class":1068},[1053,4226,4175],{"class":1572},[1053,4228,4178],{"class":1105},[1053,4230,3784],{"class":1068},[1053,4232,4233],{"class":1087}," Description",[1053,4235,1962],{"class":1068},[1053,4237,1655],{"class":1105},[1053,4239,4240],{"class":1058}," // What the statement does\n",[1053,4242,4243,4245,4247,4249,4251,4253,4256,4258,4260,4262],{"class":1055,"line":674},[1053,4244,1956],{"class":1064},[1053,4246,3787],{"class":1068},[1053,4248,4175],{"class":1572},[1053,4250,4178],{"class":1105},[1053,4252,3784],{"class":1068},[1053,4254,4255],{"class":1087}," Params",[1053,4257,1962],{"class":1068},[1053,4259,1216],{"class":1068},[1053,4261,846],{"class":1105},[1053,4263,4264],{"class":1058}," // Required parameters\n",[1053,4266,4267,4269,4271,4273,4275,4277,4280,4282,4284,4286],{"class":1055,"line":1121},[1053,4268,1956],{"class":1064},[1053,4270,3787],{"class":1068},[1053,4272,4175],{"class":1572},[1053,4274,4178],{"class":1105},[1053,4276,3784],{"class":1068},[1053,4278,4279],{"class":1087}," Tags",[1053,4281,1962],{"class":1068},[1053,4283,1216],{"class":1068},[1053,4285,1415],{"class":1105},[1053,4287,4288],{"class":1058},"     // Optional categorization tags\n",[2666,4290,638],{"id":4291},"querystatement",[962,4293,640],{},[2666,4295,643],{"id":4296},"selectstatement",[962,4298,645],{},[2666,4300,648],{"id":4301},"updatestatement",[962,4303,650],{},[2666,4305,653],{"id":4306},"deletestatement",[962,4308,655],{},[2666,4310,658],{"id":4311},"aggregatestatement",[962,4313,660],{},[1036,4315,663],{"id":4316},"executor-methods",[2666,4318,667],{"id":4319},"builder-access",[4321,4322,671],"h4",{"id":4323},"query",[1044,4325,4327],{"className":1046,"code":4326,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Query(stmt QueryStatement) (*soy.Query[T], error)\n",[1050,4328,4329],{"__ignoreMap":34},[1053,4330,4331,4333,4335,4338,4340,4342,4344,4346,4349,4352,4354,4357,4360,4362,4364,4366,4368,4370,4372,4374,4376,4378,4380],{"class":1055,"line":9},[1053,4332,1956],{"class":1064},[1053,4334,3787],{"class":1068},[1053,4336,4337],{"class":1572},"e ",[1053,4339,3790],{"class":3752},[1053,4341,110],{"class":1105},[1053,4343,1412],{"class":1068},[1053,4345,3742],{"class":1105},[1053,4347,4348],{"class":1068},"])",[1053,4350,4351],{"class":1087}," Query",[1053,4353,1090],{"class":1068},[1053,4355,4356],{"class":1572},"stmt",[1053,4358,4359],{"class":1105}," QueryStatement",[1053,4361,3784],{"class":1068},[1053,4363,3787],{"class":1068},[1053,4365,3790],{"class":3752},[1053,4367,2466],{"class":1105},[1053,4369,1084],{"class":1068},[1053,4371,671],{"class":1105},[1053,4373,1412],{"class":1068},[1053,4375,3742],{"class":1105},[1053,4377,3799],{"class":1068},[1053,4379,3802],{"class":1105},[1053,4381,1361],{"class":1068},[962,4383,4384],{},"Returns a soy Query builder for the statement.",[4321,4386,677],{"id":4387},"select",[1044,4389,4391],{"className":1046,"code":4390,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Select(stmt SelectStatement) (*soy.Select[T], error)\n",[1050,4392,4393],{"__ignoreMap":34},[1053,4394,4395,4397,4399,4401,4403,4405,4407,4409,4411,4414,4416,4418,4421,4423,4425,4427,4429,4431,4433,4435,4437,4439,4441],{"class":1055,"line":9},[1053,4396,1956],{"class":1064},[1053,4398,3787],{"class":1068},[1053,4400,4337],{"class":1572},[1053,4402,3790],{"class":3752},[1053,4404,110],{"class":1105},[1053,4406,1412],{"class":1068},[1053,4408,3742],{"class":1105},[1053,4410,4348],{"class":1068},[1053,4412,4413],{"class":1087}," Select",[1053,4415,1090],{"class":1068},[1053,4417,4356],{"class":1572},[1053,4419,4420],{"class":1105}," SelectStatement",[1053,4422,3784],{"class":1068},[1053,4424,3787],{"class":1068},[1053,4426,3790],{"class":3752},[1053,4428,2466],{"class":1105},[1053,4430,1084],{"class":1068},[1053,4432,677],{"class":1105},[1053,4434,1412],{"class":1068},[1053,4436,3742],{"class":1105},[1053,4438,3799],{"class":1068},[1053,4440,3802],{"class":1105},[1053,4442,1361],{"class":1068},[962,4444,4445],{},"Returns a soy Select builder for the statement.",[4321,4447,682],{"id":4448},"update",[1044,4450,4452],{"className":1046,"code":4451,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Update(stmt UpdateStatement) (*soy.Update[T], error)\n",[1050,4453,4454],{"__ignoreMap":34},[1053,4455,4456,4458,4460,4462,4464,4466,4468,4470,4472,4475,4477,4479,4482,4484,4486,4488,4490,4492,4494,4496,4498,4500,4502],{"class":1055,"line":9},[1053,4457,1956],{"class":1064},[1053,4459,3787],{"class":1068},[1053,4461,4337],{"class":1572},[1053,4463,3790],{"class":3752},[1053,4465,110],{"class":1105},[1053,4467,1412],{"class":1068},[1053,4469,3742],{"class":1105},[1053,4471,4348],{"class":1068},[1053,4473,4474],{"class":1087}," Update",[1053,4476,1090],{"class":1068},[1053,4478,4356],{"class":1572},[1053,4480,4481],{"class":1105}," UpdateStatement",[1053,4483,3784],{"class":1068},[1053,4485,3787],{"class":1068},[1053,4487,3790],{"class":3752},[1053,4489,2466],{"class":1105},[1053,4491,1084],{"class":1068},[1053,4493,682],{"class":1105},[1053,4495,1412],{"class":1068},[1053,4497,3742],{"class":1105},[1053,4499,3799],{"class":1068},[1053,4501,3802],{"class":1105},[1053,4503,1361],{"class":1068},[962,4505,4506],{},"Returns a soy Update builder for the statement.",[4321,4508,687],{"id":4509},"delete",[1044,4511,4513],{"className":1046,"code":4512,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Delete(stmt DeleteStatement) (*soy.Delete[T], error)\n",[1050,4514,4515],{"__ignoreMap":34},[1053,4516,4517,4519,4521,4523,4525,4527,4529,4531,4533,4536,4538,4540,4543,4545,4547,4549,4551,4553,4555,4557,4559,4561,4563],{"class":1055,"line":9},[1053,4518,1956],{"class":1064},[1053,4520,3787],{"class":1068},[1053,4522,4337],{"class":1572},[1053,4524,3790],{"class":3752},[1053,4526,110],{"class":1105},[1053,4528,1412],{"class":1068},[1053,4530,3742],{"class":1105},[1053,4532,4348],{"class":1068},[1053,4534,4535],{"class":1087}," Delete",[1053,4537,1090],{"class":1068},[1053,4539,4356],{"class":1572},[1053,4541,4542],{"class":1105}," DeleteStatement",[1053,4544,3784],{"class":1068},[1053,4546,3787],{"class":1068},[1053,4548,3790],{"class":3752},[1053,4550,2466],{"class":1105},[1053,4552,1084],{"class":1068},[1053,4554,687],{"class":1105},[1053,4556,1412],{"class":1068},[1053,4558,3742],{"class":1105},[1053,4560,3799],{"class":1068},[1053,4562,3802],{"class":1105},[1053,4564,1361],{"class":1068},[962,4566,4567],{},"Returns a soy Delete builder for the statement.",[4321,4569,692],{"id":4570},"aggregate",[1044,4572,4574],{"className":1046,"code":4573,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Aggregate(stmt AggregateStatement) *soy.Aggregate[T]\n",[1050,4575,4576],{"__ignoreMap":34},[1053,4577,4578,4580,4582,4584,4586,4588,4590,4592,4594,4597,4599,4601,4604,4606,4608,4610,4612,4614,4616,4618],{"class":1055,"line":9},[1053,4579,1956],{"class":1064},[1053,4581,3787],{"class":1068},[1053,4583,4337],{"class":1572},[1053,4585,3790],{"class":3752},[1053,4587,110],{"class":1105},[1053,4589,1412],{"class":1068},[1053,4591,3742],{"class":1105},[1053,4593,4348],{"class":1068},[1053,4595,4596],{"class":1087}," Aggregate",[1053,4598,1090],{"class":1068},[1053,4600,4356],{"class":1572},[1053,4602,4603],{"class":1105}," AggregateStatement",[1053,4605,3784],{"class":1068},[1053,4607,3753],{"class":3752},[1053,4609,2466],{"class":1105},[1053,4611,1084],{"class":1068},[1053,4613,692],{"class":1105},[1053,4615,1412],{"class":1068},[1053,4617,3742],{"class":1105},[1053,4619,4620],{"class":1068},"]\n",[962,4622,4623],{},"Returns a soy Aggregate builder for the statement.",[4321,4625,697],{"id":4626},"insert",[1044,4628,4630],{"className":1046,"code":4629,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Insert() *soy.Create[T]\n",[1050,4631,4632],{"__ignoreMap":34},[1053,4633,4634,4636,4638,4640,4642,4644,4646,4648,4650,4653,4655,4657,4659,4661,4664,4666,4668],{"class":1055,"line":9},[1053,4635,1956],{"class":1064},[1053,4637,3787],{"class":1068},[1053,4639,4337],{"class":1572},[1053,4641,3790],{"class":3752},[1053,4643,110],{"class":1105},[1053,4645,1412],{"class":1068},[1053,4647,3742],{"class":1105},[1053,4649,4348],{"class":1068},[1053,4651,4652],{"class":1087}," Insert",[1053,4654,1962],{"class":1068},[1053,4656,3753],{"class":3752},[1053,4658,2466],{"class":1105},[1053,4660,1084],{"class":1068},[1053,4662,4663],{"class":1105},"Create",[1053,4665,1412],{"class":1068},[1053,4667,3742],{"class":1105},[1053,4669,4620],{"class":1068},[962,4671,4672],{},"Returns a soy Create builder for inserts.",[4321,4674,702],{"id":4675},"compound",[1044,4677,4679],{"className":1046,"code":4678,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Compound(spec CompoundQuerySpec) (*soy.Compound[T], error)\n",[1050,4680,4681],{"__ignoreMap":34},[1053,4682,4683,4685,4687,4689,4691,4693,4695,4697,4699,4702,4704,4707,4710,4712,4714,4716,4718,4720,4722,4724,4726,4728,4730],{"class":1055,"line":9},[1053,4684,1956],{"class":1064},[1053,4686,3787],{"class":1068},[1053,4688,4337],{"class":1572},[1053,4690,3790],{"class":3752},[1053,4692,110],{"class":1105},[1053,4694,1412],{"class":1068},[1053,4696,3742],{"class":1105},[1053,4698,4348],{"class":1068},[1053,4700,4701],{"class":1087}," Compound",[1053,4703,1090],{"class":1068},[1053,4705,4706],{"class":1572},"spec",[1053,4708,4709],{"class":1105}," CompoundQuerySpec",[1053,4711,3784],{"class":1068},[1053,4713,3787],{"class":1068},[1053,4715,3790],{"class":3752},[1053,4717,2466],{"class":1105},[1053,4719,1084],{"class":1068},[1053,4721,702],{"class":1105},[1053,4723,1412],{"class":1068},[1053,4725,3742],{"class":1105},[1053,4727,3799],{"class":1068},[1053,4729,3802],{"class":1105},[1053,4731,1361],{"class":1068},[962,4733,4734],{},"Returns a soy Compound builder for set operations (UNION, INTERSECT, EXCEPT).",[2666,4736,707],{"id":4737},"execution-methods",[4321,4739,711],{"id":4740},"execquery-execquerytx",[1044,4742,4744],{"className":1046,"code":4743,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecQuery(ctx context.Context, stmt QueryStatement, params map[string]any) ([]*T, error)\nfunc (e *Executor[T]) ExecQueryTx(ctx context.Context, tx *sqlx.Tx, stmt QueryStatement, params map[string]any) ([]*T, error)\n",[1050,4745,4746,4815],{"__ignoreMap":34},[1053,4747,4748,4750,4752,4754,4756,4758,4760,4762,4764,4767,4769,4771,4773,4775,4778,4780,4783,4785,4787,4790,4792,4794,4796,4798,4800,4802,4805,4807,4809,4811,4813],{"class":1055,"line":9},[1053,4749,1956],{"class":1064},[1053,4751,3787],{"class":1068},[1053,4753,4337],{"class":1572},[1053,4755,3790],{"class":3752},[1053,4757,110],{"class":1105},[1053,4759,1412],{"class":1068},[1053,4761,3742],{"class":1105},[1053,4763,4348],{"class":1068},[1053,4765,4766],{"class":1087}," ExecQuery",[1053,4768,1090],{"class":1068},[1053,4770,1399],{"class":1572},[1053,4772,2007],{"class":1105},[1053,4774,1084],{"class":1068},[1053,4776,4777],{"class":1105},"Context",[1053,4779,1097],{"class":1068},[1053,4781,4782],{"class":1572}," stmt",[1053,4784,4359],{"class":1105},[1053,4786,1097],{"class":1068},[1053,4788,4789],{"class":1572}," params",[1053,4791,1409],{"class":1064},[1053,4793,1412],{"class":1068},[1053,4795,1415],{"class":1105},[1053,4797,1418],{"class":1068},[1053,4799,1421],{"class":1105},[1053,4801,3784],{"class":1068},[1053,4803,4804],{"class":1068}," ([]",[1053,4806,3790],{"class":3752},[1053,4808,3742],{"class":1105},[1053,4810,1097],{"class":1068},[1053,4812,3802],{"class":1105},[1053,4814,1361],{"class":1068},[1053,4816,4817,4819,4821,4823,4825,4827,4829,4831,4833,4836,4838,4840,4842,4844,4846,4848,4851,4853,4855,4857,4860,4862,4864,4866,4868,4870,4872,4874,4876,4878,4880,4882,4884,4886,4888,4890,4892],{"class":1055,"line":19},[1053,4818,1956],{"class":1064},[1053,4820,3787],{"class":1068},[1053,4822,4337],{"class":1572},[1053,4824,3790],{"class":3752},[1053,4826,110],{"class":1105},[1053,4828,1412],{"class":1068},[1053,4830,3742],{"class":1105},[1053,4832,4348],{"class":1068},[1053,4834,4835],{"class":1087}," ExecQueryTx",[1053,4837,1090],{"class":1068},[1053,4839,1399],{"class":1572},[1053,4841,2007],{"class":1105},[1053,4843,1084],{"class":1068},[1053,4845,4777],{"class":1105},[1053,4847,1097],{"class":1068},[1053,4849,4850],{"class":1572}," tx",[1053,4852,3753],{"class":3752},[1053,4854,3756],{"class":1105},[1053,4856,1084],{"class":1068},[1053,4858,4859],{"class":1105},"Tx",[1053,4861,1097],{"class":1068},[1053,4863,4782],{"class":1572},[1053,4865,4359],{"class":1105},[1053,4867,1097],{"class":1068},[1053,4869,4789],{"class":1572},[1053,4871,1409],{"class":1064},[1053,4873,1412],{"class":1068},[1053,4875,1415],{"class":1105},[1053,4877,1418],{"class":1068},[1053,4879,1421],{"class":1105},[1053,4881,3784],{"class":1068},[1053,4883,4804],{"class":1068},[1053,4885,3790],{"class":3752},[1053,4887,3742],{"class":1105},[1053,4889,1097],{"class":1068},[1053,4891,3802],{"class":1105},[1053,4893,1361],{"class":1068},[962,4895,4896],{},"Executes a query statement, returning multiple records.",[4321,4898,716],{"id":4899},"execselect-execselecttx",[1044,4901,4903],{"className":1046,"code":4902,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecSelect(ctx context.Context, stmt SelectStatement, params map[string]any) (*T, error)\nfunc (e *Executor[T]) ExecSelectTx(ctx context.Context, tx *sqlx.Tx, stmt SelectStatement, params map[string]any) (*T, error)\n",[1050,4904,4905,4970],{"__ignoreMap":34},[1053,4906,4907,4909,4911,4913,4915,4917,4919,4921,4923,4926,4928,4930,4932,4934,4936,4938,4940,4942,4944,4946,4948,4950,4952,4954,4956,4958,4960,4962,4964,4966,4968],{"class":1055,"line":9},[1053,4908,1956],{"class":1064},[1053,4910,3787],{"class":1068},[1053,4912,4337],{"class":1572},[1053,4914,3790],{"class":3752},[1053,4916,110],{"class":1105},[1053,4918,1412],{"class":1068},[1053,4920,3742],{"class":1105},[1053,4922,4348],{"class":1068},[1053,4924,4925],{"class":1087}," ExecSelect",[1053,4927,1090],{"class":1068},[1053,4929,1399],{"class":1572},[1053,4931,2007],{"class":1105},[1053,4933,1084],{"class":1068},[1053,4935,4777],{"class":1105},[1053,4937,1097],{"class":1068},[1053,4939,4782],{"class":1572},[1053,4941,4420],{"class":1105},[1053,4943,1097],{"class":1068},[1053,4945,4789],{"class":1572},[1053,4947,1409],{"class":1064},[1053,4949,1412],{"class":1068},[1053,4951,1415],{"class":1105},[1053,4953,1418],{"class":1068},[1053,4955,1421],{"class":1105},[1053,4957,3784],{"class":1068},[1053,4959,3787],{"class":1068},[1053,4961,3790],{"class":3752},[1053,4963,3742],{"class":1105},[1053,4965,1097],{"class":1068},[1053,4967,3802],{"class":1105},[1053,4969,1361],{"class":1068},[1053,4971,4972,4974,4976,4978,4980,4982,4984,4986,4988,4991,4993,4995,4997,4999,5001,5003,5005,5007,5009,5011,5013,5015,5017,5019,5021,5023,5025,5027,5029,5031,5033,5035,5037,5039,5041,5043,5045],{"class":1055,"line":19},[1053,4973,1956],{"class":1064},[1053,4975,3787],{"class":1068},[1053,4977,4337],{"class":1572},[1053,4979,3790],{"class":3752},[1053,4981,110],{"class":1105},[1053,4983,1412],{"class":1068},[1053,4985,3742],{"class":1105},[1053,4987,4348],{"class":1068},[1053,4989,4990],{"class":1087}," ExecSelectTx",[1053,4992,1090],{"class":1068},[1053,4994,1399],{"class":1572},[1053,4996,2007],{"class":1105},[1053,4998,1084],{"class":1068},[1053,5000,4777],{"class":1105},[1053,5002,1097],{"class":1068},[1053,5004,4850],{"class":1572},[1053,5006,3753],{"class":3752},[1053,5008,3756],{"class":1105},[1053,5010,1084],{"class":1068},[1053,5012,4859],{"class":1105},[1053,5014,1097],{"class":1068},[1053,5016,4782],{"class":1572},[1053,5018,4420],{"class":1105},[1053,5020,1097],{"class":1068},[1053,5022,4789],{"class":1572},[1053,5024,1409],{"class":1064},[1053,5026,1412],{"class":1068},[1053,5028,1415],{"class":1105},[1053,5030,1418],{"class":1068},[1053,5032,1421],{"class":1105},[1053,5034,3784],{"class":1068},[1053,5036,3787],{"class":1068},[1053,5038,3790],{"class":3752},[1053,5040,3742],{"class":1105},[1053,5042,1097],{"class":1068},[1053,5044,3802],{"class":1105},[1053,5046,1361],{"class":1068},[962,5048,5049],{},"Executes a select statement, returning a single record.",[4321,5051,721],{"id":5052},"execupdate-execupdatetx",[1044,5054,5056],{"className":1046,"code":5055,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecUpdate(ctx context.Context, stmt UpdateStatement, params map[string]any) (*T, error)\nfunc (e *Executor[T]) ExecUpdateTx(ctx context.Context, tx *sqlx.Tx, stmt UpdateStatement, params map[string]any) (*T, error)\n",[1050,5057,5058,5123],{"__ignoreMap":34},[1053,5059,5060,5062,5064,5066,5068,5070,5072,5074,5076,5079,5081,5083,5085,5087,5089,5091,5093,5095,5097,5099,5101,5103,5105,5107,5109,5111,5113,5115,5117,5119,5121],{"class":1055,"line":9},[1053,5061,1956],{"class":1064},[1053,5063,3787],{"class":1068},[1053,5065,4337],{"class":1572},[1053,5067,3790],{"class":3752},[1053,5069,110],{"class":1105},[1053,5071,1412],{"class":1068},[1053,5073,3742],{"class":1105},[1053,5075,4348],{"class":1068},[1053,5077,5078],{"class":1087}," ExecUpdate",[1053,5080,1090],{"class":1068},[1053,5082,1399],{"class":1572},[1053,5084,2007],{"class":1105},[1053,5086,1084],{"class":1068},[1053,5088,4777],{"class":1105},[1053,5090,1097],{"class":1068},[1053,5092,4782],{"class":1572},[1053,5094,4481],{"class":1105},[1053,5096,1097],{"class":1068},[1053,5098,4789],{"class":1572},[1053,5100,1409],{"class":1064},[1053,5102,1412],{"class":1068},[1053,5104,1415],{"class":1105},[1053,5106,1418],{"class":1068},[1053,5108,1421],{"class":1105},[1053,5110,3784],{"class":1068},[1053,5112,3787],{"class":1068},[1053,5114,3790],{"class":3752},[1053,5116,3742],{"class":1105},[1053,5118,1097],{"class":1068},[1053,5120,3802],{"class":1105},[1053,5122,1361],{"class":1068},[1053,5124,5125,5127,5129,5131,5133,5135,5137,5139,5141,5144,5146,5148,5150,5152,5154,5156,5158,5160,5162,5164,5166,5168,5170,5172,5174,5176,5178,5180,5182,5184,5186,5188,5190,5192,5194,5196,5198],{"class":1055,"line":19},[1053,5126,1956],{"class":1064},[1053,5128,3787],{"class":1068},[1053,5130,4337],{"class":1572},[1053,5132,3790],{"class":3752},[1053,5134,110],{"class":1105},[1053,5136,1412],{"class":1068},[1053,5138,3742],{"class":1105},[1053,5140,4348],{"class":1068},[1053,5142,5143],{"class":1087}," ExecUpdateTx",[1053,5145,1090],{"class":1068},[1053,5147,1399],{"class":1572},[1053,5149,2007],{"class":1105},[1053,5151,1084],{"class":1068},[1053,5153,4777],{"class":1105},[1053,5155,1097],{"class":1068},[1053,5157,4850],{"class":1572},[1053,5159,3753],{"class":3752},[1053,5161,3756],{"class":1105},[1053,5163,1084],{"class":1068},[1053,5165,4859],{"class":1105},[1053,5167,1097],{"class":1068},[1053,5169,4782],{"class":1572},[1053,5171,4481],{"class":1105},[1053,5173,1097],{"class":1068},[1053,5175,4789],{"class":1572},[1053,5177,1409],{"class":1064},[1053,5179,1412],{"class":1068},[1053,5181,1415],{"class":1105},[1053,5183,1418],{"class":1068},[1053,5185,1421],{"class":1105},[1053,5187,3784],{"class":1068},[1053,5189,3787],{"class":1068},[1053,5191,3790],{"class":3752},[1053,5193,3742],{"class":1105},[1053,5195,1097],{"class":1068},[1053,5197,3802],{"class":1105},[1053,5199,1361],{"class":1068},[962,5201,5202],{},"Executes an update statement, returning the updated record.",[4321,5204,726],{"id":5205},"execdelete-execdeletetx",[1044,5207,5209],{"className":1046,"code":5208,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecDelete(ctx context.Context, stmt DeleteStatement, params map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecDeleteTx(ctx context.Context, tx *sqlx.Tx, stmt DeleteStatement, params map[string]any) (int64, error)\n",[1050,5210,5211,5275],{"__ignoreMap":34},[1053,5212,5213,5215,5217,5219,5221,5223,5225,5227,5229,5232,5234,5236,5238,5240,5242,5244,5246,5248,5250,5252,5254,5256,5258,5260,5262,5264,5266,5269,5271,5273],{"class":1055,"line":9},[1053,5214,1956],{"class":1064},[1053,5216,3787],{"class":1068},[1053,5218,4337],{"class":1572},[1053,5220,3790],{"class":3752},[1053,5222,110],{"class":1105},[1053,5224,1412],{"class":1068},[1053,5226,3742],{"class":1105},[1053,5228,4348],{"class":1068},[1053,5230,5231],{"class":1087}," ExecDelete",[1053,5233,1090],{"class":1068},[1053,5235,1399],{"class":1572},[1053,5237,2007],{"class":1105},[1053,5239,1084],{"class":1068},[1053,5241,4777],{"class":1105},[1053,5243,1097],{"class":1068},[1053,5245,4782],{"class":1572},[1053,5247,4542],{"class":1105},[1053,5249,1097],{"class":1068},[1053,5251,4789],{"class":1572},[1053,5253,1409],{"class":1064},[1053,5255,1412],{"class":1068},[1053,5257,1415],{"class":1105},[1053,5259,1418],{"class":1068},[1053,5261,1421],{"class":1105},[1053,5263,3784],{"class":1068},[1053,5265,3787],{"class":1068},[1053,5267,5268],{"class":1105},"int64",[1053,5270,1097],{"class":1068},[1053,5272,3802],{"class":1105},[1053,5274,1361],{"class":1068},[1053,5276,5277,5279,5281,5283,5285,5287,5289,5291,5293,5296,5298,5300,5302,5304,5306,5308,5310,5312,5314,5316,5318,5320,5322,5324,5326,5328,5330,5332,5334,5336,5338,5340,5342,5344,5346,5348],{"class":1055,"line":19},[1053,5278,1956],{"class":1064},[1053,5280,3787],{"class":1068},[1053,5282,4337],{"class":1572},[1053,5284,3790],{"class":3752},[1053,5286,110],{"class":1105},[1053,5288,1412],{"class":1068},[1053,5290,3742],{"class":1105},[1053,5292,4348],{"class":1068},[1053,5294,5295],{"class":1087}," ExecDeleteTx",[1053,5297,1090],{"class":1068},[1053,5299,1399],{"class":1572},[1053,5301,2007],{"class":1105},[1053,5303,1084],{"class":1068},[1053,5305,4777],{"class":1105},[1053,5307,1097],{"class":1068},[1053,5309,4850],{"class":1572},[1053,5311,3753],{"class":3752},[1053,5313,3756],{"class":1105},[1053,5315,1084],{"class":1068},[1053,5317,4859],{"class":1105},[1053,5319,1097],{"class":1068},[1053,5321,4782],{"class":1572},[1053,5323,4542],{"class":1105},[1053,5325,1097],{"class":1068},[1053,5327,4789],{"class":1572},[1053,5329,1409],{"class":1064},[1053,5331,1412],{"class":1068},[1053,5333,1415],{"class":1105},[1053,5335,1418],{"class":1068},[1053,5337,1421],{"class":1105},[1053,5339,3784],{"class":1068},[1053,5341,3787],{"class":1068},[1053,5343,5268],{"class":1105},[1053,5345,1097],{"class":1068},[1053,5347,3802],{"class":1105},[1053,5349,1361],{"class":1068},[962,5351,5352],{},"Executes a delete statement, returning the count of deleted rows.",[4321,5354,731],{"id":5355},"execaggregate-execaggregatetx",[1044,5357,5359],{"className":1046,"code":5358,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecAggregate(ctx context.Context, stmt AggregateStatement, params map[string]any) (float64, error)\nfunc (e *Executor[T]) ExecAggregateTx(ctx context.Context, tx *sqlx.Tx, stmt AggregateStatement, params map[string]any) (float64, error)\n",[1050,5360,5361,5425],{"__ignoreMap":34},[1053,5362,5363,5365,5367,5369,5371,5373,5375,5377,5379,5382,5384,5386,5388,5390,5392,5394,5396,5398,5400,5402,5404,5406,5408,5410,5412,5414,5416,5419,5421,5423],{"class":1055,"line":9},[1053,5364,1956],{"class":1064},[1053,5366,3787],{"class":1068},[1053,5368,4337],{"class":1572},[1053,5370,3790],{"class":3752},[1053,5372,110],{"class":1105},[1053,5374,1412],{"class":1068},[1053,5376,3742],{"class":1105},[1053,5378,4348],{"class":1068},[1053,5380,5381],{"class":1087}," ExecAggregate",[1053,5383,1090],{"class":1068},[1053,5385,1399],{"class":1572},[1053,5387,2007],{"class":1105},[1053,5389,1084],{"class":1068},[1053,5391,4777],{"class":1105},[1053,5393,1097],{"class":1068},[1053,5395,4782],{"class":1572},[1053,5397,4603],{"class":1105},[1053,5399,1097],{"class":1068},[1053,5401,4789],{"class":1572},[1053,5403,1409],{"class":1064},[1053,5405,1412],{"class":1068},[1053,5407,1415],{"class":1105},[1053,5409,1418],{"class":1068},[1053,5411,1421],{"class":1105},[1053,5413,3784],{"class":1068},[1053,5415,3787],{"class":1068},[1053,5417,5418],{"class":1105},"float64",[1053,5420,1097],{"class":1068},[1053,5422,3802],{"class":1105},[1053,5424,1361],{"class":1068},[1053,5426,5427,5429,5431,5433,5435,5437,5439,5441,5443,5446,5448,5450,5452,5454,5456,5458,5460,5462,5464,5466,5468,5470,5472,5474,5476,5478,5480,5482,5484,5486,5488,5490,5492,5494,5496,5498],{"class":1055,"line":19},[1053,5428,1956],{"class":1064},[1053,5430,3787],{"class":1068},[1053,5432,4337],{"class":1572},[1053,5434,3790],{"class":3752},[1053,5436,110],{"class":1105},[1053,5438,1412],{"class":1068},[1053,5440,3742],{"class":1105},[1053,5442,4348],{"class":1068},[1053,5444,5445],{"class":1087}," ExecAggregateTx",[1053,5447,1090],{"class":1068},[1053,5449,1399],{"class":1572},[1053,5451,2007],{"class":1105},[1053,5453,1084],{"class":1068},[1053,5455,4777],{"class":1105},[1053,5457,1097],{"class":1068},[1053,5459,4850],{"class":1572},[1053,5461,3753],{"class":3752},[1053,5463,3756],{"class":1105},[1053,5465,1084],{"class":1068},[1053,5467,4859],{"class":1105},[1053,5469,1097],{"class":1068},[1053,5471,4782],{"class":1572},[1053,5473,4603],{"class":1105},[1053,5475,1097],{"class":1068},[1053,5477,4789],{"class":1572},[1053,5479,1409],{"class":1064},[1053,5481,1412],{"class":1068},[1053,5483,1415],{"class":1105},[1053,5485,1418],{"class":1068},[1053,5487,1421],{"class":1105},[1053,5489,3784],{"class":1068},[1053,5491,3787],{"class":1068},[1053,5493,5418],{"class":1105},[1053,5495,1097],{"class":1068},[1053,5497,3802],{"class":1105},[1053,5499,1361],{"class":1068},[962,5501,5502],{},"Executes an aggregate statement, returning the result.",[4321,5504,736],{"id":5505},"execinsert-execinserttx",[1044,5507,5509],{"className":1046,"code":5508,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecInsert(ctx context.Context, record *T) (*T, error)\nfunc (e *Executor[T]) ExecInsertTx(ctx context.Context, tx *sqlx.Tx, record *T) (*T, error)\n",[1050,5510,5511,5565],{"__ignoreMap":34},[1053,5512,5513,5515,5517,5519,5521,5523,5525,5527,5529,5532,5534,5536,5538,5540,5542,5544,5547,5549,5551,5553,5555,5557,5559,5561,5563],{"class":1055,"line":9},[1053,5514,1956],{"class":1064},[1053,5516,3787],{"class":1068},[1053,5518,4337],{"class":1572},[1053,5520,3790],{"class":3752},[1053,5522,110],{"class":1105},[1053,5524,1412],{"class":1068},[1053,5526,3742],{"class":1105},[1053,5528,4348],{"class":1068},[1053,5530,5531],{"class":1087}," ExecInsert",[1053,5533,1090],{"class":1068},[1053,5535,1399],{"class":1572},[1053,5537,2007],{"class":1105},[1053,5539,1084],{"class":1068},[1053,5541,4777],{"class":1105},[1053,5543,1097],{"class":1068},[1053,5545,5546],{"class":1572}," record",[1053,5548,3753],{"class":3752},[1053,5550,3742],{"class":1105},[1053,5552,3784],{"class":1068},[1053,5554,3787],{"class":1068},[1053,5556,3790],{"class":3752},[1053,5558,3742],{"class":1105},[1053,5560,1097],{"class":1068},[1053,5562,3802],{"class":1105},[1053,5564,1361],{"class":1068},[1053,5566,5567,5569,5571,5573,5575,5577,5579,5581,5583,5586,5588,5590,5592,5594,5596,5598,5600,5602,5604,5606,5608,5610,5612,5614,5616,5618,5620,5622,5624,5626,5628],{"class":1055,"line":19},[1053,5568,1956],{"class":1064},[1053,5570,3787],{"class":1068},[1053,5572,4337],{"class":1572},[1053,5574,3790],{"class":3752},[1053,5576,110],{"class":1105},[1053,5578,1412],{"class":1068},[1053,5580,3742],{"class":1105},[1053,5582,4348],{"class":1068},[1053,5584,5585],{"class":1087}," ExecInsertTx",[1053,5587,1090],{"class":1068},[1053,5589,1399],{"class":1572},[1053,5591,2007],{"class":1105},[1053,5593,1084],{"class":1068},[1053,5595,4777],{"class":1105},[1053,5597,1097],{"class":1068},[1053,5599,4850],{"class":1572},[1053,5601,3753],{"class":3752},[1053,5603,3756],{"class":1105},[1053,5605,1084],{"class":1068},[1053,5607,4859],{"class":1105},[1053,5609,1097],{"class":1068},[1053,5611,5546],{"class":1572},[1053,5613,3753],{"class":3752},[1053,5615,3742],{"class":1105},[1053,5617,3784],{"class":1068},[1053,5619,3787],{"class":1068},[1053,5621,3790],{"class":3752},[1053,5623,3742],{"class":1105},[1053,5625,1097],{"class":1068},[1053,5627,3802],{"class":1105},[1053,5629,1361],{"class":1068},[962,5631,5632],{},"Inserts a record, returning it with generated fields populated.",[4321,5634,741],{"id":5635},"execcompound-execcompoundtx",[1044,5637,5639],{"className":1046,"code":5638,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecCompound(ctx context.Context, spec CompoundQuerySpec, params map[string]any) ([]*T, error)\nfunc (e *Executor[T]) ExecCompoundTx(ctx context.Context, tx *sqlx.Tx, spec CompoundQuerySpec, params map[string]any) ([]*T, error)\n",[1050,5640,5641,5706],{"__ignoreMap":34},[1053,5642,5643,5645,5647,5649,5651,5653,5655,5657,5659,5662,5664,5666,5668,5670,5672,5674,5676,5678,5680,5682,5684,5686,5688,5690,5692,5694,5696,5698,5700,5702,5704],{"class":1055,"line":9},[1053,5644,1956],{"class":1064},[1053,5646,3787],{"class":1068},[1053,5648,4337],{"class":1572},[1053,5650,3790],{"class":3752},[1053,5652,110],{"class":1105},[1053,5654,1412],{"class":1068},[1053,5656,3742],{"class":1105},[1053,5658,4348],{"class":1068},[1053,5660,5661],{"class":1087}," ExecCompound",[1053,5663,1090],{"class":1068},[1053,5665,1399],{"class":1572},[1053,5667,2007],{"class":1105},[1053,5669,1084],{"class":1068},[1053,5671,4777],{"class":1105},[1053,5673,1097],{"class":1068},[1053,5675,3934],{"class":1572},[1053,5677,4709],{"class":1105},[1053,5679,1097],{"class":1068},[1053,5681,4789],{"class":1572},[1053,5683,1409],{"class":1064},[1053,5685,1412],{"class":1068},[1053,5687,1415],{"class":1105},[1053,5689,1418],{"class":1068},[1053,5691,1421],{"class":1105},[1053,5693,3784],{"class":1068},[1053,5695,4804],{"class":1068},[1053,5697,3790],{"class":3752},[1053,5699,3742],{"class":1105},[1053,5701,1097],{"class":1068},[1053,5703,3802],{"class":1105},[1053,5705,1361],{"class":1068},[1053,5707,5708,5710,5712,5714,5716,5718,5720,5722,5724,5727,5729,5731,5733,5735,5737,5739,5741,5743,5745,5747,5749,5751,5753,5755,5757,5759,5761,5763,5765,5767,5769,5771,5773,5775,5777,5779,5781],{"class":1055,"line":19},[1053,5709,1956],{"class":1064},[1053,5711,3787],{"class":1068},[1053,5713,4337],{"class":1572},[1053,5715,3790],{"class":3752},[1053,5717,110],{"class":1105},[1053,5719,1412],{"class":1068},[1053,5721,3742],{"class":1105},[1053,5723,4348],{"class":1068},[1053,5725,5726],{"class":1087}," ExecCompoundTx",[1053,5728,1090],{"class":1068},[1053,5730,1399],{"class":1572},[1053,5732,2007],{"class":1105},[1053,5734,1084],{"class":1068},[1053,5736,4777],{"class":1105},[1053,5738,1097],{"class":1068},[1053,5740,4850],{"class":1572},[1053,5742,3753],{"class":3752},[1053,5744,3756],{"class":1105},[1053,5746,1084],{"class":1068},[1053,5748,4859],{"class":1105},[1053,5750,1097],{"class":1068},[1053,5752,3934],{"class":1572},[1053,5754,4709],{"class":1105},[1053,5756,1097],{"class":1068},[1053,5758,4789],{"class":1572},[1053,5760,1409],{"class":1064},[1053,5762,1412],{"class":1068},[1053,5764,1415],{"class":1105},[1053,5766,1418],{"class":1068},[1053,5768,1421],{"class":1105},[1053,5770,3784],{"class":1068},[1053,5772,4804],{"class":1068},[1053,5774,3790],{"class":3752},[1053,5776,3742],{"class":1105},[1053,5778,1097],{"class":1068},[1053,5780,3802],{"class":1105},[1053,5782,1361],{"class":1068},[962,5784,5785],{},"Executes a compound query (UNION, INTERSECT, EXCEPT), returning multiple records.",[2666,5787,746],{"id":5788},"batch-execution",[4321,5790,750],{"id":5791},"execinsertbatch-execinsertbatchtx",[1044,5793,5795],{"className":1046,"code":5794,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecInsertBatch(ctx context.Context, records []*T) (int64, error)\nfunc (e *Executor[T]) ExecInsertBatchTx(ctx context.Context, tx *sqlx.Tx, records []*T) (int64, error)\n",[1050,5796,5797,5851],{"__ignoreMap":34},[1053,5798,5799,5801,5803,5805,5807,5809,5811,5813,5815,5818,5820,5822,5824,5826,5828,5830,5833,5835,5837,5839,5841,5843,5845,5847,5849],{"class":1055,"line":9},[1053,5800,1956],{"class":1064},[1053,5802,3787],{"class":1068},[1053,5804,4337],{"class":1572},[1053,5806,3790],{"class":3752},[1053,5808,110],{"class":1105},[1053,5810,1412],{"class":1068},[1053,5812,3742],{"class":1105},[1053,5814,4348],{"class":1068},[1053,5816,5817],{"class":1087}," ExecInsertBatch",[1053,5819,1090],{"class":1068},[1053,5821,1399],{"class":1572},[1053,5823,2007],{"class":1105},[1053,5825,1084],{"class":1068},[1053,5827,4777],{"class":1105},[1053,5829,1097],{"class":1068},[1053,5831,5832],{"class":1572}," records",[1053,5834,1216],{"class":1068},[1053,5836,3790],{"class":3752},[1053,5838,3742],{"class":1105},[1053,5840,3784],{"class":1068},[1053,5842,3787],{"class":1068},[1053,5844,5268],{"class":1105},[1053,5846,1097],{"class":1068},[1053,5848,3802],{"class":1105},[1053,5850,1361],{"class":1068},[1053,5852,5853,5855,5857,5859,5861,5863,5865,5867,5869,5872,5874,5876,5878,5880,5882,5884,5886,5888,5890,5892,5894,5896,5898,5900,5902,5904,5906,5908,5910,5912,5914],{"class":1055,"line":19},[1053,5854,1956],{"class":1064},[1053,5856,3787],{"class":1068},[1053,5858,4337],{"class":1572},[1053,5860,3790],{"class":3752},[1053,5862,110],{"class":1105},[1053,5864,1412],{"class":1068},[1053,5866,3742],{"class":1105},[1053,5868,4348],{"class":1068},[1053,5870,5871],{"class":1087}," ExecInsertBatchTx",[1053,5873,1090],{"class":1068},[1053,5875,1399],{"class":1572},[1053,5877,2007],{"class":1105},[1053,5879,1084],{"class":1068},[1053,5881,4777],{"class":1105},[1053,5883,1097],{"class":1068},[1053,5885,4850],{"class":1572},[1053,5887,3753],{"class":3752},[1053,5889,3756],{"class":1105},[1053,5891,1084],{"class":1068},[1053,5893,4859],{"class":1105},[1053,5895,1097],{"class":1068},[1053,5897,5832],{"class":1572},[1053,5899,1216],{"class":1068},[1053,5901,3790],{"class":3752},[1053,5903,3742],{"class":1105},[1053,5905,3784],{"class":1068},[1053,5907,3787],{"class":1068},[1053,5909,5268],{"class":1105},[1053,5911,1097],{"class":1068},[1053,5913,3802],{"class":1105},[1053,5915,1361],{"class":1068},[962,5917,5918],{},"Inserts multiple records, returning the count.",[4321,5920,755],{"id":5921},"execupdatebatch-execupdatebatchtx",[1044,5923,5925],{"className":1046,"code":5924,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecUpdateBatch(ctx context.Context, stmt UpdateStatement, batchParams []map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecUpdateBatchTx(ctx context.Context, tx *sqlx.Tx, stmt UpdateStatement, batchParams []map[string]any) (int64, error)\n",[1050,5926,5927,5994],{"__ignoreMap":34},[1053,5928,5929,5931,5933,5935,5937,5939,5941,5943,5945,5948,5950,5952,5954,5956,5958,5960,5962,5964,5966,5969,5971,5974,5976,5978,5980,5982,5984,5986,5988,5990,5992],{"class":1055,"line":9},[1053,5930,1956],{"class":1064},[1053,5932,3787],{"class":1068},[1053,5934,4337],{"class":1572},[1053,5936,3790],{"class":3752},[1053,5938,110],{"class":1105},[1053,5940,1412],{"class":1068},[1053,5942,3742],{"class":1105},[1053,5944,4348],{"class":1068},[1053,5946,5947],{"class":1087}," ExecUpdateBatch",[1053,5949,1090],{"class":1068},[1053,5951,1399],{"class":1572},[1053,5953,2007],{"class":1105},[1053,5955,1084],{"class":1068},[1053,5957,4777],{"class":1105},[1053,5959,1097],{"class":1068},[1053,5961,4782],{"class":1572},[1053,5963,4481],{"class":1105},[1053,5965,1097],{"class":1068},[1053,5967,5968],{"class":1572}," batchParams",[1053,5970,1216],{"class":1068},[1053,5972,5973],{"class":1064},"map",[1053,5975,1412],{"class":1068},[1053,5977,1415],{"class":1105},[1053,5979,1418],{"class":1068},[1053,5981,1421],{"class":1105},[1053,5983,3784],{"class":1068},[1053,5985,3787],{"class":1068},[1053,5987,5268],{"class":1105},[1053,5989,1097],{"class":1068},[1053,5991,3802],{"class":1105},[1053,5993,1361],{"class":1068},[1053,5995,5996,5998,6000,6002,6004,6006,6008,6010,6012,6015,6017,6019,6021,6023,6025,6027,6029,6031,6033,6035,6037,6039,6041,6043,6045,6047,6049,6051,6053,6055,6057,6059,6061,6063,6065,6067,6069],{"class":1055,"line":19},[1053,5997,1956],{"class":1064},[1053,5999,3787],{"class":1068},[1053,6001,4337],{"class":1572},[1053,6003,3790],{"class":3752},[1053,6005,110],{"class":1105},[1053,6007,1412],{"class":1068},[1053,6009,3742],{"class":1105},[1053,6011,4348],{"class":1068},[1053,6013,6014],{"class":1087}," ExecUpdateBatchTx",[1053,6016,1090],{"class":1068},[1053,6018,1399],{"class":1572},[1053,6020,2007],{"class":1105},[1053,6022,1084],{"class":1068},[1053,6024,4777],{"class":1105},[1053,6026,1097],{"class":1068},[1053,6028,4850],{"class":1572},[1053,6030,3753],{"class":3752},[1053,6032,3756],{"class":1105},[1053,6034,1084],{"class":1068},[1053,6036,4859],{"class":1105},[1053,6038,1097],{"class":1068},[1053,6040,4782],{"class":1572},[1053,6042,4481],{"class":1105},[1053,6044,1097],{"class":1068},[1053,6046,5968],{"class":1572},[1053,6048,1216],{"class":1068},[1053,6050,5973],{"class":1064},[1053,6052,1412],{"class":1068},[1053,6054,1415],{"class":1105},[1053,6056,1418],{"class":1068},[1053,6058,1421],{"class":1105},[1053,6060,3784],{"class":1068},[1053,6062,3787],{"class":1068},[1053,6064,5268],{"class":1105},[1053,6066,1097],{"class":1068},[1053,6068,3802],{"class":1105},[1053,6070,1361],{"class":1068},[962,6072,6073],{},"Executes an update statement with multiple parameter sets.",[4321,6075,760],{"id":6076},"execdeletebatch-execdeletebatchtx",[1044,6078,6080],{"className":1046,"code":6079,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecDeleteBatch(ctx context.Context, stmt DeleteStatement, batchParams []map[string]any) (int64, error)\nfunc (e *Executor[T]) ExecDeleteBatchTx(ctx context.Context, tx *sqlx.Tx, stmt DeleteStatement, batchParams []map[string]any) (int64, error)\n",[1050,6081,6082,6147],{"__ignoreMap":34},[1053,6083,6084,6086,6088,6090,6092,6094,6096,6098,6100,6103,6105,6107,6109,6111,6113,6115,6117,6119,6121,6123,6125,6127,6129,6131,6133,6135,6137,6139,6141,6143,6145],{"class":1055,"line":9},[1053,6085,1956],{"class":1064},[1053,6087,3787],{"class":1068},[1053,6089,4337],{"class":1572},[1053,6091,3790],{"class":3752},[1053,6093,110],{"class":1105},[1053,6095,1412],{"class":1068},[1053,6097,3742],{"class":1105},[1053,6099,4348],{"class":1068},[1053,6101,6102],{"class":1087}," ExecDeleteBatch",[1053,6104,1090],{"class":1068},[1053,6106,1399],{"class":1572},[1053,6108,2007],{"class":1105},[1053,6110,1084],{"class":1068},[1053,6112,4777],{"class":1105},[1053,6114,1097],{"class":1068},[1053,6116,4782],{"class":1572},[1053,6118,4542],{"class":1105},[1053,6120,1097],{"class":1068},[1053,6122,5968],{"class":1572},[1053,6124,1216],{"class":1068},[1053,6126,5973],{"class":1064},[1053,6128,1412],{"class":1068},[1053,6130,1415],{"class":1105},[1053,6132,1418],{"class":1068},[1053,6134,1421],{"class":1105},[1053,6136,3784],{"class":1068},[1053,6138,3787],{"class":1068},[1053,6140,5268],{"class":1105},[1053,6142,1097],{"class":1068},[1053,6144,3802],{"class":1105},[1053,6146,1361],{"class":1068},[1053,6148,6149,6151,6153,6155,6157,6159,6161,6163,6165,6168,6170,6172,6174,6176,6178,6180,6182,6184,6186,6188,6190,6192,6194,6196,6198,6200,6202,6204,6206,6208,6210,6212,6214,6216,6218,6220,6222],{"class":1055,"line":19},[1053,6150,1956],{"class":1064},[1053,6152,3787],{"class":1068},[1053,6154,4337],{"class":1572},[1053,6156,3790],{"class":3752},[1053,6158,110],{"class":1105},[1053,6160,1412],{"class":1068},[1053,6162,3742],{"class":1105},[1053,6164,4348],{"class":1068},[1053,6166,6167],{"class":1087}," ExecDeleteBatchTx",[1053,6169,1090],{"class":1068},[1053,6171,1399],{"class":1572},[1053,6173,2007],{"class":1105},[1053,6175,1084],{"class":1068},[1053,6177,4777],{"class":1105},[1053,6179,1097],{"class":1068},[1053,6181,4850],{"class":1572},[1053,6183,3753],{"class":3752},[1053,6185,3756],{"class":1105},[1053,6187,1084],{"class":1068},[1053,6189,4859],{"class":1105},[1053,6191,1097],{"class":1068},[1053,6193,4782],{"class":1572},[1053,6195,4542],{"class":1105},[1053,6197,1097],{"class":1068},[1053,6199,5968],{"class":1572},[1053,6201,1216],{"class":1068},[1053,6203,5973],{"class":1064},[1053,6205,1412],{"class":1068},[1053,6207,1415],{"class":1105},[1053,6209,1418],{"class":1068},[1053,6211,1421],{"class":1105},[1053,6213,3784],{"class":1068},[1053,6215,3787],{"class":1068},[1053,6217,5268],{"class":1105},[1053,6219,1097],{"class":1068},[1053,6221,3802],{"class":1105},[1053,6223,1361],{"class":1068},[962,6225,6226],{},"Executes a delete statement with multiple parameter sets.",[2666,6228,765],{"id":6229},"type-erased-execution-atom",[962,6231,6232,6233,6236],{},"These methods return results as ",[1050,6234,6235],{},"atom.Atom"," types, enabling type-erased execution where the concrete type T is not known at consumption time. Useful for dynamic query handling and LLM-driven database operations.",[4321,6238,770],{"id":6239},"execqueryatom",[1044,6241,6243],{"className":1046,"code":6242,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecQueryAtom(ctx context.Context, stmt QueryStatement, params map[string]any) ([]*atom.Atom, error)\n",[1050,6244,6245],{"__ignoreMap":34},[1053,6246,6247,6249,6251,6253,6255,6257,6259,6261,6263,6266,6268,6270,6272,6274,6276,6278,6280,6282,6284,6286,6288,6290,6292,6294,6296,6298,6300,6302,6305,6307,6310,6312,6314],{"class":1055,"line":9},[1053,6248,1956],{"class":1064},[1053,6250,3787],{"class":1068},[1053,6252,4337],{"class":1572},[1053,6254,3790],{"class":3752},[1053,6256,110],{"class":1105},[1053,6258,1412],{"class":1068},[1053,6260,3742],{"class":1105},[1053,6262,4348],{"class":1068},[1053,6264,6265],{"class":1087}," ExecQueryAtom",[1053,6267,1090],{"class":1068},[1053,6269,1399],{"class":1572},[1053,6271,2007],{"class":1105},[1053,6273,1084],{"class":1068},[1053,6275,4777],{"class":1105},[1053,6277,1097],{"class":1068},[1053,6279,4782],{"class":1572},[1053,6281,4359],{"class":1105},[1053,6283,1097],{"class":1068},[1053,6285,4789],{"class":1572},[1053,6287,1409],{"class":1064},[1053,6289,1412],{"class":1068},[1053,6291,1415],{"class":1105},[1053,6293,1418],{"class":1068},[1053,6295,1421],{"class":1105},[1053,6297,3784],{"class":1068},[1053,6299,4804],{"class":1068},[1053,6301,3790],{"class":3752},[1053,6303,6304],{"class":1105},"atom",[1053,6306,1084],{"class":1068},[1053,6308,6309],{"class":1105},"Atom",[1053,6311,1097],{"class":1068},[1053,6313,3802],{"class":1105},[1053,6315,1361],{"class":1068},[962,6317,6318],{},"Executes a query statement and returns results as Atoms.",[4321,6320,775],{"id":6321},"execselectatom",[1044,6323,6325],{"className":1046,"code":6324,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecSelectAtom(ctx context.Context, stmt SelectStatement, params map[string]any) (*atom.Atom, error)\n",[1050,6326,6327],{"__ignoreMap":34},[1053,6328,6329,6331,6333,6335,6337,6339,6341,6343,6345,6348,6350,6352,6354,6356,6358,6360,6362,6364,6366,6368,6370,6372,6374,6376,6378,6380,6382,6384,6386,6388,6390,6392,6394],{"class":1055,"line":9},[1053,6330,1956],{"class":1064},[1053,6332,3787],{"class":1068},[1053,6334,4337],{"class":1572},[1053,6336,3790],{"class":3752},[1053,6338,110],{"class":1105},[1053,6340,1412],{"class":1068},[1053,6342,3742],{"class":1105},[1053,6344,4348],{"class":1068},[1053,6346,6347],{"class":1087}," ExecSelectAtom",[1053,6349,1090],{"class":1068},[1053,6351,1399],{"class":1572},[1053,6353,2007],{"class":1105},[1053,6355,1084],{"class":1068},[1053,6357,4777],{"class":1105},[1053,6359,1097],{"class":1068},[1053,6361,4782],{"class":1572},[1053,6363,4420],{"class":1105},[1053,6365,1097],{"class":1068},[1053,6367,4789],{"class":1572},[1053,6369,1409],{"class":1064},[1053,6371,1412],{"class":1068},[1053,6373,1415],{"class":1105},[1053,6375,1418],{"class":1068},[1053,6377,1421],{"class":1105},[1053,6379,3784],{"class":1068},[1053,6381,3787],{"class":1068},[1053,6383,3790],{"class":3752},[1053,6385,6304],{"class":1105},[1053,6387,1084],{"class":1068},[1053,6389,6309],{"class":1105},[1053,6391,1097],{"class":1068},[1053,6393,3802],{"class":1105},[1053,6395,1361],{"class":1068},[962,6397,6398],{},"Executes a select statement and returns the result as an Atom.",[4321,6400,780],{"id":6401},"execinsertatom",[1044,6403,6405],{"className":1046,"code":6404,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) ExecInsertAtom(ctx context.Context, params map[string]any) (*atom.Atom, error)\n",[1050,6406,6407],{"__ignoreMap":34},[1053,6408,6409,6411,6413,6415,6417,6419,6421,6423,6425,6428,6430,6432,6434,6436,6438,6440,6442,6444,6446,6448,6450,6452,6454,6456,6458,6460,6462,6464,6466,6468],{"class":1055,"line":9},[1053,6410,1956],{"class":1064},[1053,6412,3787],{"class":1068},[1053,6414,4337],{"class":1572},[1053,6416,3790],{"class":3752},[1053,6418,110],{"class":1105},[1053,6420,1412],{"class":1068},[1053,6422,3742],{"class":1105},[1053,6424,4348],{"class":1068},[1053,6426,6427],{"class":1087}," ExecInsertAtom",[1053,6429,1090],{"class":1068},[1053,6431,1399],{"class":1572},[1053,6433,2007],{"class":1105},[1053,6435,1084],{"class":1068},[1053,6437,4777],{"class":1105},[1053,6439,1097],{"class":1068},[1053,6441,4789],{"class":1572},[1053,6443,1409],{"class":1064},[1053,6445,1412],{"class":1068},[1053,6447,1415],{"class":1105},[1053,6449,1418],{"class":1068},[1053,6451,1421],{"class":1105},[1053,6453,3784],{"class":1068},[1053,6455,3787],{"class":1068},[1053,6457,3790],{"class":3752},[1053,6459,6304],{"class":1105},[1053,6461,1084],{"class":1068},[1053,6463,6309],{"class":1105},[1053,6465,1097],{"class":1068},[1053,6467,3802],{"class":1105},[1053,6469,1361],{"class":1068},[962,6471,6472],{},"Executes an insert using parameter map and returns the result as an Atom.",[2666,6474,785],{"id":6475},"rendering",[4321,6477,789],{"id":6478},"rendercompound",[1044,6480,6482],{"className":1046,"code":6481,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) RenderCompound(spec CompoundQuerySpec) (string, error)\n",[1050,6483,6484],{"__ignoreMap":34},[1053,6485,6486,6488,6490,6492,6494,6496,6498,6500,6502,6505,6507,6509,6511,6513,6515,6517,6519,6521],{"class":1055,"line":9},[1053,6487,1956],{"class":1064},[1053,6489,3787],{"class":1068},[1053,6491,4337],{"class":1572},[1053,6493,3790],{"class":3752},[1053,6495,110],{"class":1105},[1053,6497,1412],{"class":1068},[1053,6499,3742],{"class":1105},[1053,6501,4348],{"class":1068},[1053,6503,6504],{"class":1087}," RenderCompound",[1053,6506,1090],{"class":1068},[1053,6508,4706],{"class":1572},[1053,6510,4709],{"class":1105},[1053,6512,3784],{"class":1068},[1053,6514,3787],{"class":1068},[1053,6516,1415],{"class":1105},[1053,6518,1097],{"class":1068},[1053,6520,3802],{"class":1105},[1053,6522,1361],{"class":1068},[962,6524,6525],{},"Renders a compound query to SQL for inspection or debugging.",[2666,6527,794],{"id":6528},"other",[4321,6530,241],{"id":2466},[1044,6532,6534],{"className":1046,"code":6533,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) Soy() *soy.Soy[T]\n",[1050,6535,6536],{"__ignoreMap":34},[1053,6537,6538,6540,6542,6544,6546,6548,6550,6552,6554,6557,6559,6561,6563,6565,6567,6569,6571],{"class":1055,"line":9},[1053,6539,1956],{"class":1064},[1053,6541,3787],{"class":1068},[1053,6543,4337],{"class":1572},[1053,6545,3790],{"class":3752},[1053,6547,110],{"class":1105},[1053,6549,1412],{"class":1068},[1053,6551,3742],{"class":1105},[1053,6553,4348],{"class":1068},[1053,6555,6556],{"class":1087}," Soy",[1053,6558,1962],{"class":1068},[1053,6560,3753],{"class":3752},[1053,6562,2466],{"class":1105},[1053,6564,1084],{"class":1068},[1053,6566,241],{"class":1105},[1053,6568,1412],{"class":1068},[1053,6570,3742],{"class":1105},[1053,6572,4620],{"class":1068},[962,6574,6575],{},"Returns the underlying soy instance for direct builder access.",[4321,6577,802],{"id":6578},"tablename",[1044,6580,6582],{"className":1046,"code":6581,"language":1048,"meta":34,"style":34},"func (e *Executor[T]) TableName() string\n",[1050,6583,6584],{"__ignoreMap":34},[1053,6585,6586,6588,6590,6592,6594,6596,6598,6600,6602,6605,6607],{"class":1055,"line":9},[1053,6587,1956],{"class":1064},[1053,6589,3787],{"class":1068},[1053,6591,4337],{"class":1572},[1053,6593,3790],{"class":3752},[1053,6595,110],{"class":1105},[1053,6597,1412],{"class":1068},[1053,6599,3742],{"class":1105},[1053,6601,4348],{"class":1068},[1053,6603,6604],{"class":1087}," TableName",[1053,6606,1962],{"class":1068},[1053,6608,6609],{"class":1105}," string\n",[962,6611,6612],{},"Returns the table name.",[1036,6614,807],{"id":6615},"spec-types",[2666,6617,144],{"id":6618},"queryspec",[1044,6620,6622],{"className":1046,"code":6621,"language":1048,"meta":34,"style":34},"type QuerySpec struct {\n    Fields      []string\n    SelectExprs []SelectExprSpec  // Expression-based SELECT (functions, aggregates)\n    Where       []ConditionSpec\n    OrderBy     []OrderBySpec\n    GroupBy     []string\n    Having      []ConditionSpec\n    HavingAgg   []HavingAggSpec\n    Limit       *int\n    LimitParam  string            // Parameterized LIMIT\n    Offset      *int\n    OffsetParam string            // Parameterized OFFSET\n    Distinct    bool\n    DistinctOn  []string\n    ForLocking  string\n}\n",[1050,6623,6624,6634,6645,6657,6667,6678,6687,6696,6706,6717,6727,6737,6747,6755,6765,6773],{"__ignoreMap":34},[1053,6625,6626,6628,6630,6632],{"class":1055,"line":9},[1053,6627,1605],{"class":1064},[1053,6629,3937],{"class":1105},[1053,6631,1611],{"class":1064},[1053,6633,1614],{"class":1068},[1053,6635,6636,6639,6642],{"class":1055,"line":19},[1053,6637,6638],{"class":1159},"    Fields",[1053,6640,6641],{"class":1068},"      []",[1053,6643,6644],{"class":1105},"string\n",[1053,6646,6647,6650,6652,6654],{"class":1055,"line":40},[1053,6648,6649],{"class":1159},"    SelectExprs",[1053,6651,1216],{"class":1068},[1053,6653,851],{"class":1105},[1053,6655,6656],{"class":1058},"  // Expression-based SELECT (functions, aggregates)\n",[1053,6658,6659,6661,6664],{"class":1055,"line":674},[1053,6660,2553],{"class":1159},[1053,6662,6663],{"class":1068},"       []",[1053,6665,6666],{"class":1105},"ConditionSpec\n",[1053,6668,6669,6672,6675],{"class":1055,"line":1121},[1053,6670,6671],{"class":1159},"    OrderBy",[1053,6673,6674],{"class":1068},"     []",[1053,6676,6677],{"class":1105},"OrderBySpec\n",[1053,6679,6680,6683,6685],{"class":1055,"line":1156},[1053,6681,6682],{"class":1159},"    GroupBy",[1053,6684,6674],{"class":1068},[1053,6686,6644],{"class":1105},[1053,6688,6689,6692,6694],{"class":1055,"line":1208},[1053,6690,6691],{"class":1159},"    Having",[1053,6693,6641],{"class":1068},[1053,6695,6666],{"class":1105},[1053,6697,6698,6701,6703],{"class":1055,"line":1246},[1053,6699,6700],{"class":1159},"    HavingAgg",[1053,6702,1166],{"class":1068},[1053,6704,6705],{"class":1105},"HavingAggSpec\n",[1053,6707,6708,6711,6714],{"class":1055,"line":1266},[1053,6709,6710],{"class":1159},"    Limit",[1053,6712,6713],{"class":3752},"       *",[1053,6715,6716],{"class":1105},"int\n",[1053,6718,6719,6722,6724],{"class":1055,"line":1272},[1053,6720,6721],{"class":1159},"    LimitParam",[1053,6723,1633],{"class":1105},[1053,6725,6726],{"class":1058},"            // Parameterized LIMIT\n",[1053,6728,6729,6732,6735],{"class":1055,"line":1277},[1053,6730,6731],{"class":1159},"    Offset",[1053,6733,6734],{"class":3752},"      *",[1053,6736,6716],{"class":1105},[1053,6738,6739,6742,6744],{"class":1055,"line":1311},[1053,6740,6741],{"class":1159},"    OffsetParam",[1053,6743,1655],{"class":1105},[1053,6745,6746],{"class":1058},"            // Parameterized OFFSET\n",[1053,6748,6749,6752],{"class":1055,"line":1353},[1053,6750,6751],{"class":1159},"    Distinct",[1053,6753,6754],{"class":1105},"    bool\n",[1053,6756,6757,6760,6763],{"class":1055,"line":1358},[1053,6758,6759],{"class":1159},"    DistinctOn",[1053,6761,6762],{"class":1068},"  []",[1053,6764,6644],{"class":1105},[1053,6766,6767,6770],{"class":1055,"line":1364},[1053,6768,6769],{"class":1159},"    ForLocking",[1053,6771,6772],{"class":1105},"  string\n",[1053,6774,6775],{"class":1055,"line":1369},[1053,6776,1663],{"class":1068},[2666,6778,149],{"id":6779},"selectspec",[1044,6781,6783],{"className":1046,"code":6782,"language":1048,"meta":34,"style":34},"type SelectSpec struct {\n    Fields      []string\n    SelectExprs []SelectExprSpec  // Expression-based SELECT (functions, aggregates)\n    Where       []ConditionSpec\n    OrderBy     []OrderBySpec\n    GroupBy     []string\n    Having      []ConditionSpec\n    HavingAgg   []HavingAggSpec\n    Limit       *int\n    LimitParam  string            // Parameterized LIMIT\n    Offset      *int\n    OffsetParam string            // Parameterized OFFSET\n    Distinct    bool\n    DistinctOn  []string\n    ForLocking  string\n}\n",[1050,6784,6785,6795,6803,6813,6821,6829,6837,6845,6853,6861,6869,6877,6885,6891,6899,6905],{"__ignoreMap":34},[1053,6786,6787,6789,6791,6793],{"class":1055,"line":9},[1053,6788,1605],{"class":1064},[1053,6790,3987],{"class":1105},[1053,6792,1611],{"class":1064},[1053,6794,1614],{"class":1068},[1053,6796,6797,6799,6801],{"class":1055,"line":19},[1053,6798,6638],{"class":1159},[1053,6800,6641],{"class":1068},[1053,6802,6644],{"class":1105},[1053,6804,6805,6807,6809,6811],{"class":1055,"line":40},[1053,6806,6649],{"class":1159},[1053,6808,1216],{"class":1068},[1053,6810,851],{"class":1105},[1053,6812,6656],{"class":1058},[1053,6814,6815,6817,6819],{"class":1055,"line":674},[1053,6816,2553],{"class":1159},[1053,6818,6663],{"class":1068},[1053,6820,6666],{"class":1105},[1053,6822,6823,6825,6827],{"class":1055,"line":1121},[1053,6824,6671],{"class":1159},[1053,6826,6674],{"class":1068},[1053,6828,6677],{"class":1105},[1053,6830,6831,6833,6835],{"class":1055,"line":1156},[1053,6832,6682],{"class":1159},[1053,6834,6674],{"class":1068},[1053,6836,6644],{"class":1105},[1053,6838,6839,6841,6843],{"class":1055,"line":1208},[1053,6840,6691],{"class":1159},[1053,6842,6641],{"class":1068},[1053,6844,6666],{"class":1105},[1053,6846,6847,6849,6851],{"class":1055,"line":1246},[1053,6848,6700],{"class":1159},[1053,6850,1166],{"class":1068},[1053,6852,6705],{"class":1105},[1053,6854,6855,6857,6859],{"class":1055,"line":1266},[1053,6856,6710],{"class":1159},[1053,6858,6713],{"class":3752},[1053,6860,6716],{"class":1105},[1053,6862,6863,6865,6867],{"class":1055,"line":1272},[1053,6864,6721],{"class":1159},[1053,6866,1633],{"class":1105},[1053,6868,6726],{"class":1058},[1053,6870,6871,6873,6875],{"class":1055,"line":1277},[1053,6872,6731],{"class":1159},[1053,6874,6734],{"class":3752},[1053,6876,6716],{"class":1105},[1053,6878,6879,6881,6883],{"class":1055,"line":1311},[1053,6880,6741],{"class":1159},[1053,6882,1655],{"class":1105},[1053,6884,6746],{"class":1058},[1053,6886,6887,6889],{"class":1055,"line":1353},[1053,6888,6751],{"class":1159},[1053,6890,6754],{"class":1105},[1053,6892,6893,6895,6897],{"class":1055,"line":1358},[1053,6894,6759],{"class":1159},[1053,6896,6762],{"class":1068},[1053,6898,6644],{"class":1105},[1053,6900,6901,6903],{"class":1055,"line":1364},[1053,6902,6769],{"class":1159},[1053,6904,6772],{"class":1105},[1053,6906,6907],{"class":1055,"line":1369},[1053,6908,1663],{"class":1068},[2666,6910,154],{"id":6911},"updatespec",[1044,6913,6915],{"className":1046,"code":6914,"language":1048,"meta":34,"style":34},"type UpdateSpec struct {\n    Set   map[string]string  // field -> param\n    Where []ConditionSpec\n}\n",[1050,6916,6917,6927,6946,6954],{"__ignoreMap":34},[1053,6918,6919,6921,6923,6925],{"class":1055,"line":9},[1053,6920,1605],{"class":1064},[1053,6922,4035],{"class":1105},[1053,6924,1611],{"class":1064},[1053,6926,1614],{"class":1068},[1053,6928,6929,6932,6935,6937,6939,6941,6943],{"class":1055,"line":19},[1053,6930,6931],{"class":1159},"    Set",[1053,6933,6934],{"class":1064},"   map",[1053,6936,1412],{"class":1068},[1053,6938,1415],{"class":1105},[1053,6940,1418],{"class":1068},[1053,6942,1415],{"class":1105},[1053,6944,6945],{"class":1058},"  // field -> param\n",[1053,6947,6948,6950,6952],{"class":1055,"line":40},[1053,6949,2553],{"class":1159},[1053,6951,1216],{"class":1068},[1053,6953,6666],{"class":1105},[1053,6955,6956],{"class":1055,"line":674},[1053,6957,1663],{"class":1068},[2666,6959,159],{"id":6960},"deletespec",[1044,6962,6964],{"className":1046,"code":6963,"language":1048,"meta":34,"style":34},"type DeleteSpec struct {\n    Where []ConditionSpec\n}\n",[1050,6965,6966,6976,6984],{"__ignoreMap":34},[1053,6967,6968,6970,6972,6974],{"class":1055,"line":9},[1053,6969,1605],{"class":1064},[1053,6971,4083],{"class":1105},[1053,6973,1611],{"class":1064},[1053,6975,1614],{"class":1068},[1053,6977,6978,6980,6982],{"class":1055,"line":19},[1053,6979,2553],{"class":1159},[1053,6981,1216],{"class":1068},[1053,6983,6666],{"class":1105},[1053,6985,6986],{"class":1055,"line":40},[1053,6987,1663],{"class":1068},[2666,6989,164],{"id":6990},"aggregatespec",[1044,6992,6994],{"className":1046,"code":6993,"language":1048,"meta":34,"style":34},"type AggregateSpec struct {\n    Field string\n    Where []ConditionSpec\n}\n",[1050,6995,6996,7006,7013,7021],{"__ignoreMap":34},[1053,6997,6998,7000,7002,7004],{"class":1055,"line":9},[1053,6999,1605],{"class":1064},[1053,7001,4139],{"class":1105},[1053,7003,1611],{"class":1064},[1053,7005,1614],{"class":1068},[1053,7007,7008,7011],{"class":1055,"line":19},[1053,7009,7010],{"class":1159},"    Field",[1053,7012,6609],{"class":1105},[1053,7014,7015,7017,7019],{"class":1055,"line":40},[1053,7016,2553],{"class":1159},[1053,7018,1216],{"class":1068},[1053,7020,6666],{"class":1105},[1053,7022,7023],{"class":1055,"line":674},[1053,7024,1663],{"class":1068},[2666,7026,831],{"id":7027},"conditionspec",[1044,7029,7031],{"className":1046,"code":7030,"language":1048,"meta":34,"style":34},"type ConditionSpec struct {\n    Field      string\n    Operator   string\n    Param      string\n    IsNull     bool\n    Logic      string           // \"AND\" or \"OR\" for groups\n    Group      []ConditionSpec  // Nested conditions\n    Between    bool             // Use BETWEEN with LowParam/HighParam\n    NotBetween bool             // Use NOT BETWEEN with LowParam/HighParam\n    LowParam   string           // Lower bound param for BETWEEN\n    HighParam  string           // Upper bound param for BETWEEN\n    RightField string           // For field-to-field comparisons (WHERE a.field = b.field)\n}\n",[1050,7032,7033,7044,7051,7059,7066,7074,7085,7097,7108,7119,7129,7139,7149],{"__ignoreMap":34},[1053,7034,7035,7037,7040,7042],{"class":1055,"line":9},[1053,7036,1605],{"class":1064},[1053,7038,7039],{"class":1105}," ConditionSpec",[1053,7041,1611],{"class":1064},[1053,7043,1614],{"class":1068},[1053,7045,7046,7048],{"class":1055,"line":19},[1053,7047,7010],{"class":1159},[1053,7049,7050],{"class":1105},"      string\n",[1053,7052,7053,7056],{"class":1055,"line":40},[1053,7054,7055],{"class":1159},"    Operator",[1053,7057,7058],{"class":1105},"   string\n",[1053,7060,7061,7064],{"class":1055,"line":674},[1053,7062,7063],{"class":1159},"    Param",[1053,7065,7050],{"class":1105},[1053,7067,7068,7071],{"class":1055,"line":1121},[1053,7069,7070],{"class":1159},"    IsNull",[1053,7072,7073],{"class":1105},"     bool\n",[1053,7075,7076,7079,7082],{"class":1055,"line":1156},[1053,7077,7078],{"class":1159},"    Logic",[1053,7080,7081],{"class":1105},"      string",[1053,7083,7084],{"class":1058},"           // \"AND\" or \"OR\" for groups\n",[1053,7086,7087,7090,7092,7094],{"class":1055,"line":1208},[1053,7088,7089],{"class":1159},"    Group",[1053,7091,6641],{"class":1068},[1053,7093,831],{"class":1105},[1053,7095,7096],{"class":1058},"  // Nested conditions\n",[1053,7098,7099,7102,7105],{"class":1055,"line":1246},[1053,7100,7101],{"class":1159},"    Between",[1053,7103,7104],{"class":1105},"    bool",[1053,7106,7107],{"class":1058},"             // Use BETWEEN with LowParam/HighParam\n",[1053,7109,7110,7113,7116],{"class":1055,"line":1266},[1053,7111,7112],{"class":1159},"    NotBetween",[1053,7114,7115],{"class":1105}," bool",[1053,7117,7118],{"class":1058},"             // Use NOT BETWEEN with LowParam/HighParam\n",[1053,7120,7121,7124,7126],{"class":1055,"line":1272},[1053,7122,7123],{"class":1159},"    LowParam",[1053,7125,1644],{"class":1105},[1053,7127,7128],{"class":1058},"           // Lower bound param for BETWEEN\n",[1053,7130,7131,7134,7136],{"class":1055,"line":1277},[1053,7132,7133],{"class":1159},"    HighParam",[1053,7135,1633],{"class":1105},[1053,7137,7138],{"class":1058},"           // Upper bound param for BETWEEN\n",[1053,7140,7141,7144,7146],{"class":1055,"line":1311},[1053,7142,7143],{"class":1159},"    RightField",[1053,7145,1655],{"class":1105},[1053,7147,7148],{"class":1058},"           // For field-to-field comparisons (WHERE a.field = b.field)\n",[1053,7150,7151],{"class":1055,"line":1353},[1053,7152,1663],{"class":1068},[4321,7154,836],{"id":7155},"helper-methods",[1044,7157,7159],{"className":1046,"code":7158,"language":1048,"meta":34,"style":34},"func (c ConditionSpec) IsGroup() bool           // Returns true if this is a grouped condition\nfunc (c ConditionSpec) IsBetween() bool         // Returns true if Between is set\nfunc (c ConditionSpec) IsNotBetween() bool      // Returns true if NotBetween is set\nfunc (c ConditionSpec) IsFieldComparison() bool // Returns true if RightField is set\n",[1050,7160,7161,7184,7206,7228],{"__ignoreMap":34},[1053,7162,7163,7165,7167,7170,7172,7174,7177,7179,7181],{"class":1055,"line":9},[1053,7164,1956],{"class":1064},[1053,7166,3787],{"class":1068},[1053,7168,7169],{"class":1572},"c ",[1053,7171,831],{"class":1105},[1053,7173,3784],{"class":1068},[1053,7175,7176],{"class":1087}," IsGroup",[1053,7178,1962],{"class":1068},[1053,7180,7115],{"class":1105},[1053,7182,7183],{"class":1058},"           // Returns true if this is a grouped condition\n",[1053,7185,7186,7188,7190,7192,7194,7196,7199,7201,7203],{"class":1055,"line":19},[1053,7187,1956],{"class":1064},[1053,7189,3787],{"class":1068},[1053,7191,7169],{"class":1572},[1053,7193,831],{"class":1105},[1053,7195,3784],{"class":1068},[1053,7197,7198],{"class":1087}," IsBetween",[1053,7200,1962],{"class":1068},[1053,7202,7115],{"class":1105},[1053,7204,7205],{"class":1058},"         // Returns true if Between is set\n",[1053,7207,7208,7210,7212,7214,7216,7218,7221,7223,7225],{"class":1055,"line":40},[1053,7209,1956],{"class":1064},[1053,7211,3787],{"class":1068},[1053,7213,7169],{"class":1572},[1053,7215,831],{"class":1105},[1053,7217,3784],{"class":1068},[1053,7219,7220],{"class":1087}," IsNotBetween",[1053,7222,1962],{"class":1068},[1053,7224,7115],{"class":1105},[1053,7226,7227],{"class":1058},"      // Returns true if NotBetween is set\n",[1053,7229,7230,7232,7234,7236,7238,7240,7243,7245,7247],{"class":1055,"line":674},[1053,7231,1956],{"class":1064},[1053,7233,3787],{"class":1068},[1053,7235,7169],{"class":1572},[1053,7237,831],{"class":1105},[1053,7239,3784],{"class":1068},[1053,7241,7242],{"class":1087}," IsFieldComparison",[1053,7244,1962],{"class":1068},[1053,7246,7115],{"class":1105},[1053,7248,7249],{"class":1058}," // Returns true if RightField is set\n",[2666,7251,841],{"id":7252},"orderbyspec",[1044,7254,7256],{"className":1046,"code":7255,"language":1048,"meta":34,"style":34},"type OrderBySpec struct {\n    Field     string\n    Direction string  // \"asc\" or \"desc\"\n    Nulls     string  // \"first\" or \"last\"\n    Operator  string  // For expressions (e.g., \"\u003C->\")\n    Param     string  // For expression parameters\n}\n",[1050,7257,7258,7269,7276,7286,7297,7306,7315],{"__ignoreMap":34},[1053,7259,7260,7262,7265,7267],{"class":1055,"line":9},[1053,7261,1605],{"class":1064},[1053,7263,7264],{"class":1105}," OrderBySpec",[1053,7266,1611],{"class":1064},[1053,7268,1614],{"class":1068},[1053,7270,7271,7273],{"class":1055,"line":19},[1053,7272,7010],{"class":1159},[1053,7274,7275],{"class":1105},"     string\n",[1053,7277,7278,7281,7283],{"class":1055,"line":40},[1053,7279,7280],{"class":1159},"    Direction",[1053,7282,1655],{"class":1105},[1053,7284,7285],{"class":1058},"  // \"asc\" or \"desc\"\n",[1053,7287,7288,7291,7294],{"class":1055,"line":674},[1053,7289,7290],{"class":1159},"    Nulls",[1053,7292,7293],{"class":1105},"     string",[1053,7295,7296],{"class":1058},"  // \"first\" or \"last\"\n",[1053,7298,7299,7301,7303],{"class":1055,"line":1121},[1053,7300,7055],{"class":1159},[1053,7302,1633],{"class":1105},[1053,7304,7305],{"class":1058},"  // For expressions (e.g., \"\u003C->\")\n",[1053,7307,7308,7310,7312],{"class":1055,"line":1156},[1053,7309,7063],{"class":1159},[1053,7311,7293],{"class":1105},[1053,7313,7314],{"class":1058},"  // For expression parameters\n",[1053,7316,7317],{"class":1055,"line":1208},[1053,7318,1663],{"class":1068},[2666,7320,846],{"id":7321},"paramspec",[1044,7323,7325],{"className":1046,"code":7324,"language":1048,"meta":34,"style":34},"type ParamSpec struct {\n    Name        string\n    Type        string\n    Required    bool\n    Default     any\n    Description string\n}\n",[1050,7326,7327,7338,7345,7352,7359,7367,7374],{"__ignoreMap":34},[1053,7328,7329,7331,7334,7336],{"class":1055,"line":9},[1053,7330,1605],{"class":1064},[1053,7332,7333],{"class":1105}," ParamSpec",[1053,7335,1611],{"class":1064},[1053,7337,1614],{"class":1068},[1053,7339,7340,7342],{"class":1055,"line":19},[1053,7341,1641],{"class":1159},[1053,7343,7344],{"class":1105},"        string\n",[1053,7346,7347,7350],{"class":1055,"line":40},[1053,7348,7349],{"class":1159},"    Type",[1053,7351,7344],{"class":1105},[1053,7353,7354,7357],{"class":1055,"line":674},[1053,7355,7356],{"class":1159},"    Required",[1053,7358,6754],{"class":1105},[1053,7360,7361,7364],{"class":1055,"line":1121},[1053,7362,7363],{"class":1159},"    Default",[1053,7365,7366],{"class":1105},"     any\n",[1053,7368,7369,7372],{"class":1055,"line":1156},[1053,7370,7371],{"class":1159},"    Description",[1053,7373,6609],{"class":1105},[1053,7375,7376],{"class":1055,"line":1208},[1053,7377,1663],{"class":1068},[2666,7379,851],{"id":7380},"selectexprspec",[962,7382,7383],{},"Defines expression-based SELECT columns (functions, aggregates, casts).",[1044,7385,7387],{"className":1046,"code":7386,"language":1048,"meta":34,"style":34},"type SelectExprSpec struct {\n    Func     string          // Function name (see supported functions below)\n    Field    string          // Primary field for single-field functions\n    Fields   []string        // Multiple fields for multi-field functions (concat)\n    Params   []string        // Additional parameters (substring positions, power exponent)\n    CastType string          // Target type for cast operations\n    Filter   *ConditionSpec  // Filter clause for aggregate functions\n    Alias    string          // Required: column alias in result\n}\n",[1050,7388,7389,7400,7410,7420,7431,7443,7453,7466,7476],{"__ignoreMap":34},[1053,7390,7391,7393,7396,7398],{"class":1055,"line":9},[1053,7392,1605],{"class":1064},[1053,7394,7395],{"class":1105}," SelectExprSpec",[1053,7397,1611],{"class":1064},[1053,7399,1614],{"class":1068},[1053,7401,7402,7405,7407],{"class":1055,"line":19},[1053,7403,7404],{"class":1159},"    Func",[1053,7406,7293],{"class":1105},[1053,7408,7409],{"class":1058},"          // Function name (see supported functions below)\n",[1053,7411,7412,7414,7417],{"class":1055,"line":40},[1053,7413,7010],{"class":1159},[1053,7415,7416],{"class":1105},"    string",[1053,7418,7419],{"class":1058},"          // Primary field for single-field functions\n",[1053,7421,7422,7424,7426,7428],{"class":1055,"line":674},[1053,7423,6638],{"class":1159},[1053,7425,1166],{"class":1068},[1053,7427,1415],{"class":1105},[1053,7429,7430],{"class":1058},"        // Multiple fields for multi-field functions (concat)\n",[1053,7432,7433,7436,7438,7440],{"class":1055,"line":1121},[1053,7434,7435],{"class":1159},"    Params",[1053,7437,1166],{"class":1068},[1053,7439,1415],{"class":1105},[1053,7441,7442],{"class":1058},"        // Additional parameters (substring positions, power exponent)\n",[1053,7444,7445,7448,7450],{"class":1055,"line":1156},[1053,7446,7447],{"class":1159},"    CastType",[1053,7449,1655],{"class":1105},[1053,7451,7452],{"class":1058},"          // Target type for cast operations\n",[1053,7454,7455,7458,7461,7463],{"class":1055,"line":1208},[1053,7456,7457],{"class":1159},"    Filter",[1053,7459,7460],{"class":3752},"   *",[1053,7462,831],{"class":1105},[1053,7464,7465],{"class":1058},"  // Filter clause for aggregate functions\n",[1053,7467,7468,7471,7473],{"class":1055,"line":1246},[1053,7469,7470],{"class":1159},"    Alias",[1053,7472,7416],{"class":1105},[1053,7474,7475],{"class":1058},"          // Required: column alias in result\n",[1053,7477,7478],{"class":1055,"line":1266},[1053,7479,1663],{"class":1068},[962,7481,7482],{},[2455,7483,7484],{},"Supported Functions:",[2349,7486,7487,7497],{},[2352,7488,7489],{},[2355,7490,7491,7494],{},[2358,7492,7493],{},"Category",[2358,7495,7496],{},"Functions",[2368,7498,7499,7533,7558,7577,7587,7614],{},[2355,7500,7501,7504],{},[2373,7502,7503],{},"String",[2373,7505,7506,2283,7509,2283,7512,2283,7515,2283,7518,2283,7521,2283,7524,2283,7527,2283,7530],{},[1050,7507,7508],{},"upper",[1050,7510,7511],{},"lower",[1050,7513,7514],{},"length",[1050,7516,7517],{},"trim",[1050,7519,7520],{},"ltrim",[1050,7522,7523],{},"rtrim",[1050,7525,7526],{},"substring",[1050,7528,7529],{},"replace",[1050,7531,7532],{},"concat",[2355,7534,7535,7538],{},[2373,7536,7537],{},"Math",[2373,7539,7540,2283,7543,2283,7546,2283,7549,2283,7552,2283,7555],{},[1050,7541,7542],{},"abs",[1050,7544,7545],{},"ceil",[1050,7547,7548],{},"floor",[1050,7550,7551],{},"round",[1050,7553,7554],{},"sqrt",[1050,7556,7557],{},"power",[2355,7559,7560,7563],{},[2373,7561,7562],{},"Date/Time",[2373,7564,7565,2283,7568,2283,7571,2283,7574],{},[1050,7566,7567],{},"now",[1050,7569,7570],{},"current_date",[1050,7572,7573],{},"current_time",[1050,7575,7576],{},"current_timestamp",[2355,7578,7579,7582],{},[2373,7580,7581],{},"Type",[2373,7583,7584],{},[1050,7585,7586],{},"cast",[2355,7588,7589,7591],{},[2373,7590,692],{},[2373,7592,7593,2283,7596,2283,7599,2283,7602,2283,7605,2283,7608,2283,7611],{},[1050,7594,7595],{},"count",[1050,7597,7598],{},"count_star",[1050,7600,7601],{},"count_distinct",[1050,7603,7604],{},"sum",[1050,7606,7607],{},"avg",[1050,7609,7610],{},"min",[1050,7612,7613],{},"max",[2355,7615,7616,7619],{},[2373,7617,7618],{},"Conditional",[2373,7620,7621,2283,7624],{},[1050,7622,7623],{},"coalesce",[1050,7625,7626],{},"nullif",[2666,7628,856],{"id":7629},"havingaggspec",[962,7631,7632],{},"Defines aggregate conditions for HAVING clauses.",[1044,7634,7636],{"className":1046,"code":7635,"language":1048,"meta":34,"style":34},"type HavingAggSpec struct {\n    Func     string  // Aggregate function: \"count\", \"sum\", \"avg\", \"min\", \"max\"\n    Field    string  // Field to aggregate\n    Operator string  // Comparison operator\n    Param    string  // Parameter name for comparison value\n}\n",[1050,7637,7638,7649,7658,7667,7676,7685],{"__ignoreMap":34},[1053,7639,7640,7642,7645,7647],{"class":1055,"line":9},[1053,7641,1605],{"class":1064},[1053,7643,7644],{"class":1105}," HavingAggSpec",[1053,7646,1611],{"class":1064},[1053,7648,1614],{"class":1068},[1053,7650,7651,7653,7655],{"class":1055,"line":19},[1053,7652,7404],{"class":1159},[1053,7654,7293],{"class":1105},[1053,7656,7657],{"class":1058},"  // Aggregate function: \"count\", \"sum\", \"avg\", \"min\", \"max\"\n",[1053,7659,7660,7662,7664],{"class":1055,"line":40},[1053,7661,7010],{"class":1159},[1053,7663,7416],{"class":1105},[1053,7665,7666],{"class":1058},"  // Field to aggregate\n",[1053,7668,7669,7671,7673],{"class":1055,"line":674},[1053,7670,7055],{"class":1159},[1053,7672,1655],{"class":1105},[1053,7674,7675],{"class":1058},"  // Comparison operator\n",[1053,7677,7678,7680,7682],{"class":1055,"line":1121},[1053,7679,7063],{"class":1159},[1053,7681,7416],{"class":1105},[1053,7683,7684],{"class":1058},"  // Parameter name for comparison value\n",[1053,7686,7687],{"class":1055,"line":1156},[1053,7688,1663],{"class":1068},[2666,7690,861],{"id":7691},"compoundqueryspec",[962,7693,7694],{},"Defines compound queries using set operations (UNION, INTERSECT, EXCEPT).",[1044,7696,7698],{"className":1046,"code":7697,"language":1048,"meta":34,"style":34},"type CompoundQuerySpec struct {\n    Base     QuerySpec         // The base query\n    Operands []CompoundOperand // Set operations with additional queries\n    OrderBy  []OrderBySpec     // Final ORDER BY (applies to combined result)\n    Limit    *int              // Final LIMIT\n    Offset   *int              // Final OFFSET\n}\n",[1050,7699,7700,7710,7721,7733,7744,7757,7768],{"__ignoreMap":34},[1053,7701,7702,7704,7706,7708],{"class":1055,"line":9},[1053,7703,1605],{"class":1064},[1053,7705,4709],{"class":1105},[1053,7707,1611],{"class":1064},[1053,7709,1614],{"class":1068},[1053,7711,7712,7715,7718],{"class":1055,"line":19},[1053,7713,7714],{"class":1159},"    Base",[1053,7716,7717],{"class":1105},"     QuerySpec",[1053,7719,7720],{"class":1058},"         // The base query\n",[1053,7722,7723,7726,7728,7730],{"class":1055,"line":40},[1053,7724,7725],{"class":1159},"    Operands",[1053,7727,1216],{"class":1068},[1053,7729,866],{"class":1105},[1053,7731,7732],{"class":1058}," // Set operations with additional queries\n",[1053,7734,7735,7737,7739,7741],{"class":1055,"line":674},[1053,7736,6671],{"class":1159},[1053,7738,6762],{"class":1068},[1053,7740,841],{"class":1105},[1053,7742,7743],{"class":1058},"     // Final ORDER BY (applies to combined result)\n",[1053,7745,7746,7748,7751,7754],{"class":1055,"line":1121},[1053,7747,6710],{"class":1159},[1053,7749,7750],{"class":3752},"    *",[1053,7752,7753],{"class":1105},"int",[1053,7755,7756],{"class":1058},"              // Final LIMIT\n",[1053,7758,7759,7761,7763,7765],{"class":1055,"line":1156},[1053,7760,6731],{"class":1159},[1053,7762,7460],{"class":3752},[1053,7764,7753],{"class":1105},[1053,7766,7767],{"class":1058},"              // Final OFFSET\n",[1053,7769,7770],{"class":1055,"line":1208},[1053,7771,1663],{"class":1068},[2666,7773,866],{"id":7774},"compoundoperand",[962,7776,7777],{},"Defines a set operation in a compound query.",[1044,7779,7781],{"className":1046,"code":7780,"language":1048,"meta":34,"style":34},"type CompoundOperand struct {\n    Operation string    // \"union\", \"union_all\", \"intersect\", \"intersect_all\", \"except\", \"except_all\"\n    Query     QuerySpec // The query to combine\n}\n",[1050,7782,7783,7794,7804,7814],{"__ignoreMap":34},[1053,7784,7785,7787,7790,7792],{"class":1055,"line":9},[1053,7786,1605],{"class":1064},[1053,7788,7789],{"class":1105}," CompoundOperand",[1053,7791,1611],{"class":1064},[1053,7793,1614],{"class":1068},[1053,7795,7796,7799,7801],{"class":1055,"line":19},[1053,7797,7798],{"class":1159},"    Operation",[1053,7800,1655],{"class":1105},[1053,7802,7803],{"class":1058},"    // \"union\", \"union_all\", \"intersect\", \"intersect_all\", \"except\", \"except_all\"\n",[1053,7805,7806,7809,7811],{"class":1055,"line":40},[1053,7807,7808],{"class":1159},"    Query",[1053,7810,7717],{"class":1105},[1053,7812,7813],{"class":1058}," // The query to combine\n",[1053,7815,7816],{"class":1055,"line":674},[1053,7817,1663],{"class":1068},[1036,7819,871],{"id":7820},"aggregatefunc",[1044,7822,7824],{"className":1046,"code":7823,"language":1048,"meta":34,"style":34},"type AggregateFunc string\n\nconst (\n    AggCount AggregateFunc = \"COUNT\"\n    AggSum   AggregateFunc = \"SUM\"\n    AggAvg   AggregateFunc = \"AVG\"\n    AggMin   AggregateFunc = \"MIN\"\n    AggMax   AggregateFunc = \"MAX\"\n)\n",[1050,7825,7826,7834,7838,7845,7858,7871,7883,7895,7907],{"__ignoreMap":34},[1053,7827,7828,7830,7832],{"class":1055,"line":9},[1053,7829,1605],{"class":1064},[1053,7831,4132],{"class":1105},[1053,7833,6609],{"class":1105},[1053,7835,7836],{"class":1055,"line":19},[1053,7837,1118],{"emptyLinePlaceholder":1117},[1053,7839,7840,7843],{"class":1055,"line":40},[1053,7841,7842],{"class":1064},"const",[1053,7844,1069],{"class":1068},[1053,7846,7847,7851,7853,7855],{"class":1055,"line":674},[1053,7848,7850],{"class":7849},"sfm-E","    AggCount",[1053,7852,4132],{"class":1105},[1053,7854,1078],{"class":1074},[1053,7856,7857],{"class":1093}," \"COUNT\"\n",[1053,7859,7860,7863,7866,7868],{"class":1055,"line":1121},[1053,7861,7862],{"class":7849},"    AggSum",[1053,7864,7865],{"class":1105},"   AggregateFunc",[1053,7867,1078],{"class":1074},[1053,7869,7870],{"class":1093}," \"SUM\"\n",[1053,7872,7873,7876,7878,7880],{"class":1055,"line":1156},[1053,7874,7875],{"class":7849},"    AggAvg",[1053,7877,7865],{"class":1105},[1053,7879,1078],{"class":1074},[1053,7881,7882],{"class":1093}," \"AVG\"\n",[1053,7884,7885,7888,7890,7892],{"class":1055,"line":1208},[1053,7886,7887],{"class":7849},"    AggMin",[1053,7889,7865],{"class":1105},[1053,7891,1078],{"class":1074},[1053,7893,7894],{"class":1093}," \"MIN\"\n",[1053,7896,7897,7900,7902,7904],{"class":1055,"line":1246},[1053,7898,7899],{"class":7849},"    AggMax",[1053,7901,7865],{"class":1105},[1053,7903,1078],{"class":1074},[1053,7905,7906],{"class":1093}," \"MAX\"\n",[1053,7908,7909],{"class":1055,"line":1266},[1053,7910,1361],{"class":1068},[1036,7912,876],{"id":7913},"event-keys",[1044,7915,7917],{"className":1046,"code":7916,"language":1048,"meta":34,"style":34},"var (\n    KeyTable    = capitan.NewStringKey(\"table\")\n    KeyError    = capitan.NewStringKey(\"error\")\n    KeyDuration = capitan.NewDurationKey(\"duration\")\n)\n",[1050,7918,7919,7925,7948,7968,7989],{"__ignoreMap":34},[1053,7920,7921,7923],{"class":1055,"line":9},[1053,7922,1065],{"class":1064},[1053,7924,1069],{"class":1068},[1053,7926,7927,7930,7933,7936,7938,7941,7943,7946],{"class":1055,"line":19},[1053,7928,7929],{"class":1074},"    KeyTable",[1053,7931,7932],{"class":1074},"    =",[1053,7934,7935],{"class":1074}," capitan",[1053,7937,1084],{"class":1068},[1053,7939,7940],{"class":1087},"NewStringKey",[1053,7942,1090],{"class":1068},[1053,7944,7945],{"class":1093},"\"table\"",[1053,7947,1361],{"class":1068},[1053,7949,7950,7953,7955,7957,7959,7961,7963,7966],{"class":1055,"line":40},[1053,7951,7952],{"class":1074},"    KeyError",[1053,7954,7932],{"class":1074},[1053,7956,7935],{"class":1074},[1053,7958,1084],{"class":1068},[1053,7960,7940],{"class":1087},[1053,7962,1090],{"class":1068},[1053,7964,7965],{"class":1093},"\"error\"",[1053,7967,1361],{"class":1068},[1053,7969,7970,7973,7975,7977,7979,7982,7984,7987],{"class":1055,"line":674},[1053,7971,7972],{"class":1074},"    KeyDuration",[1053,7974,1078],{"class":1074},[1053,7976,7935],{"class":1074},[1053,7978,1084],{"class":1068},[1053,7980,7981],{"class":1087},"NewDurationKey",[1053,7983,1090],{"class":1068},[1053,7985,7986],{"class":1093},"\"duration\"",[1053,7988,1361],{"class":1068},[1053,7990,7991],{"class":1055,"line":1121},[1053,7992,1361],{"class":1068},[1036,7994,881],{"id":7995},"signals",[1044,7997,7999],{"className":1046,"code":7998,"language":1048,"meta":34,"style":34},"var (\n    ExecutorCreated = capitan.NewSignal(\"edamame.executor.created\", \"Executor instance created\")\n)\n",[1050,8000,8001,8007,8033],{"__ignoreMap":34},[1053,8002,8003,8005],{"class":1055,"line":9},[1053,8004,1065],{"class":1064},[1053,8006,1069],{"class":1068},[1053,8008,8009,8012,8014,8016,8018,8021,8023,8026,8028,8031],{"class":1055,"line":19},[1053,8010,8011],{"class":1074},"    ExecutorCreated",[1053,8013,1078],{"class":1074},[1053,8015,7935],{"class":1074},[1053,8017,1084],{"class":1068},[1053,8019,8020],{"class":1087},"NewSignal",[1053,8022,1090],{"class":1068},[1053,8024,8025],{"class":1093},"\"edamame.executor.created\"",[1053,8027,1097],{"class":1068},[1053,8029,8030],{"class":1093}," \"Executor instance created\"",[1053,8032,1361],{"class":1068},[1053,8034,8035],{"class":1055,"line":40},[1053,8036,1361],{"class":1068},[962,8038,8039],{},"Hook for monitoring:",[1044,8041,8043],{"className":1046,"code":8042,"language":1048,"meta":34,"style":34},"capitan.Hook(edamame.ExecutorCreated, func(ctx context.Context, e *capitan.Event) {\n    table, _ := edamame.KeyTable.From(e)\n    log.Printf(\"Executor created for table: %s\", table)\n})\n",[1050,8044,8045,8097,8127,8152],{"__ignoreMap":34},[1053,8046,8047,8050,8052,8055,8057,8059,8061,8064,8066,8069,8071,8073,8075,8077,8079,8081,8084,8086,8088,8090,8093,8095],{"class":1055,"line":9},[1053,8048,8049],{"class":1074},"capitan",[1053,8051,1084],{"class":1068},[1053,8053,8054],{"class":1087},"Hook",[1053,8056,1090],{"class":1068},[1053,8058,960],{"class":1074},[1053,8060,1084],{"class":1068},[1053,8062,8063],{"class":1074},"ExecutorCreated",[1053,8065,1097],{"class":1068},[1053,8067,8068],{"class":1064}," func",[1053,8070,1090],{"class":1068},[1053,8072,1399],{"class":1572},[1053,8074,2007],{"class":1105},[1053,8076,1084],{"class":1068},[1053,8078,4777],{"class":1105},[1053,8080,1097],{"class":1068},[1053,8082,8083],{"class":1572}," e",[1053,8085,3753],{"class":3752},[1053,8087,8049],{"class":1105},[1053,8089,1084],{"class":1068},[1053,8091,8092],{"class":1105},"Event",[1053,8094,3784],{"class":1068},[1053,8096,1614],{"class":1068},[1053,8098,8099,8102,8104,8106,8108,8110,8112,8115,8117,8120,8122,8125],{"class":1055,"line":19},[1053,8100,8101],{"class":1074},"    table",[1053,8103,1097],{"class":1068},[1053,8105,1383],{"class":1074},[1053,8107,1386],{"class":1074},[1053,8109,1081],{"class":1074},[1053,8111,1084],{"class":1068},[1053,8113,8114],{"class":1074},"KeyTable",[1053,8116,1084],{"class":1068},[1053,8118,8119],{"class":1087},"From",[1053,8121,1090],{"class":1068},[1053,8123,8124],{"class":1074},"e",[1053,8126,1361],{"class":1068},[1053,8128,8129,8132,8134,8136,8138,8141,8143,8145,8147,8150],{"class":1055,"line":40},[1053,8130,8131],{"class":1074},"    log",[1053,8133,1084],{"class":1068},[1053,8135,2265],{"class":1087},[1053,8137,1090],{"class":1068},[1053,8139,8140],{"class":1093},"\"Executor created for table: ",[1053,8142,2280],{"class":2273},[1053,8144,2270],{"class":1093},[1053,8146,1097],{"class":1068},[1053,8148,8149],{"class":1074}," table",[1053,8151,1361],{"class":1068},[1053,8153,8154],{"class":1055,"line":674},[1053,8155,1435],{"class":1068},[1036,8157,115],{"id":8158},"struct-tags",[962,8160,8161],{},"Edamame uses struct tags to understand your model:",[1044,8163,8165],{"className":1046,"code":8164,"language":1048,"meta":34,"style":34},"type User struct {\n    ID    int    `db:\"id\" type:\"integer\" constraints:\"primarykey\"`\n    Email string `db:\"email\" type:\"text\" constraints:\"notnull,unique\"`\n    Name  string `db:\"name\" type:\"text\"`\n    Age   *int   `db:\"age\" type:\"integer\"`\n}\n",[1050,8166,8167,8177,8186,8194,8202,8214],{"__ignoreMap":34},[1053,8168,8169,8171,8173,8175],{"class":1055,"line":9},[1053,8170,1605],{"class":1064},[1053,8172,1608],{"class":1105},[1053,8174,1611],{"class":1064},[1053,8176,1614],{"class":1068},[1053,8178,8179,8181,8184],{"class":1055,"line":19},[1053,8180,1619],{"class":1159},[1053,8182,8183],{"class":1105},"    int",[1053,8185,1625],{"class":1093},[1053,8187,8188,8190,8192],{"class":1055,"line":40},[1053,8189,1630],{"class":1159},[1053,8191,1655],{"class":1105},[1053,8193,1636],{"class":1093},[1053,8195,8196,8198,8200],{"class":1055,"line":674},[1053,8197,1641],{"class":1159},[1053,8199,1633],{"class":1105},[1053,8201,1647],{"class":1093},[1053,8203,8204,8207,8209,8211],{"class":1055,"line":1121},[1053,8205,8206],{"class":1159},"    Age",[1053,8208,7460],{"class":3752},[1053,8210,7753],{"class":1105},[1053,8212,8213],{"class":1093},"   `db:\"age\" type:\"integer\"`\n",[1053,8215,8216],{"class":1055,"line":1156},[1053,8217,1663],{"class":1068},[2349,8219,8220,8233],{},[2352,8221,8222],{},[2355,8223,8224,8227,8230],{},[2358,8225,8226],{},"Tag",[2358,8228,8229],{},"Purpose",[2358,8231,8232],{},"Example",[2368,8234,8235,8249,8266],{},[2355,8236,8237,8241,8244],{},[2373,8238,8239],{},[1050,8240,2055],{},[2373,8242,8243],{},"Column name",[2373,8245,8246],{},[1050,8247,8248],{},"db:\"user_id\"",[2355,8250,8251,8255,8258],{},[2373,8252,8253],{},[1050,8254,1605],{},[2373,8256,8257],{},"SQL type",[2373,8259,8260,2283,8263],{},[1050,8261,8262],{},"type:\"text\"",[1050,8264,8265],{},"type:\"integer\"",[2355,8267,8268,8273,8276],{},[2373,8269,8270],{},[1050,8271,8272],{},"constraints",[2373,8274,8275],{},"Column constraints",[2373,8277,8278],{},[1050,8279,8280],{},"constraints:\"primarykey,notnull\"",[2728,8282,8283],{},"html pre.shiki code .sUt3r, html code.shiki .sUt3r{--shiki-default:var(--shiki-keyword)}html pre.shiki code .s5klm, html code.shiki .s5klm{--shiki-default:var(--shiki-function)}html pre.shiki code .sq5bi, html code.shiki .sq5bi{--shiki-default:var(--shiki-punctuation)}html pre.shiki code .sSYET, html code.shiki .sSYET{--shiki-default:var(--shiki-parameter)}html pre.shiki code .sYBwO, html code.shiki .sYBwO{--shiki-default:var(--shiki-type)}html pre.shiki code .sW3Qg, html code.shiki .sW3Qg{--shiki-default:var(--shiki-operator)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sxAnc, html code.shiki .sxAnc{--shiki-default:var(--shiki-string)}html pre.shiki code .sLkEo, html code.shiki .sLkEo{--shiki-default:var(--shiki-comment)}html pre.shiki code .sh8_p, html code.shiki .sh8_p{--shiki-default:var(--shiki-text)}html pre.shiki code .sBGCq, html code.shiki .sBGCq{--shiki-default:var(--shiki-property)}html pre.shiki code .sfm-E, html code.shiki .sfm-E{--shiki-default:var(--shiki-variable)}html pre.shiki code .scyPU, html code.shiki .scyPU{--shiki-default:var(--shiki-placeholder)}",{"title":34,"searchDepth":19,"depth":19,"links":8285},[8286,8289,8296,8303,8311,8325,8326,8327,8328],{"id":3720,"depth":19,"text":110,"children":8287},[8288],{"id":3725,"depth":40,"text":600},{"id":3902,"depth":19,"text":605,"children":8290},[8291,8292,8293,8294,8295],{"id":3905,"depth":40,"text":609},{"id":3958,"depth":40,"text":614},{"id":4006,"depth":40,"text":619},{"id":4054,"depth":40,"text":624},{"id":4102,"depth":40,"text":629},{"id":4158,"depth":19,"text":27,"children":8297},[8298,8299,8300,8301,8302],{"id":4291,"depth":40,"text":638},{"id":4296,"depth":40,"text":643},{"id":4301,"depth":40,"text":648},{"id":4306,"depth":40,"text":653},{"id":4311,"depth":40,"text":658},{"id":4316,"depth":19,"text":663,"children":8304},[8305,8306,8307,8308,8309,8310],{"id":4319,"depth":40,"text":667},{"id":4737,"depth":40,"text":707},{"id":5788,"depth":40,"text":746},{"id":6229,"depth":40,"text":765},{"id":6475,"depth":40,"text":785},{"id":6528,"depth":40,"text":794},{"id":6615,"depth":19,"text":807,"children":8312},[8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8324],{"id":6618,"depth":40,"text":144},{"id":6779,"depth":40,"text":149},{"id":6911,"depth":40,"text":154},{"id":6960,"depth":40,"text":159},{"id":6990,"depth":40,"text":164},{"id":7027,"depth":40,"text":831},{"id":7252,"depth":40,"text":841},{"id":7321,"depth":40,"text":846},{"id":7380,"depth":40,"text":851},{"id":7629,"depth":40,"text":856},{"id":7691,"depth":40,"text":861},{"id":7774,"depth":40,"text":866},{"id":7820,"depth":19,"text":871},{"id":7913,"depth":19,"text":876},{"id":7995,"depth":19,"text":881},{"id":8158,"depth":19,"text":115},{},"2025-12-17T00:00:00.000Z",null,{"title":587,"description":589},[925,2443,7496,8334],"Types","2026-01-04T00:00:00.000Z","BFs1pcdU0FzKBYalYNqrC50yOEepACDPuQyIBzHjNuo",[8338,8331],{"title":519,"path":518,"stem":923,"description":521,"children":-1},1776270501873]