RepoPilotOpen in app →

Masterminds/squirrel

Fluent SQL generation for golang

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyConcerns

non-standard license (Other); last commit was 2y ago…

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 32+ active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • Other licensed
Show all 7 evidence items →
  • CI configured
  • Stale — last commit 2y ago
  • Non-standard license (Other) — review terms
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/masterminds/squirrel?axis=fork)](https://repopilot.app/r/masterminds/squirrel)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/masterminds/squirrel on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: Masterminds/squirrel

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/Masterminds/squirrel shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 32+ active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • Other licensed
  • CI configured
  • ⚠ Stale — last commit 2y ago
  • ⚠ Non-standard license (Other) — review terms
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live Masterminds/squirrel repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/Masterminds/squirrel.

What it runs against: a local clone of Masterminds/squirrel — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in Masterminds/squirrel | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 773 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>Masterminds/squirrel</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of Masterminds/squirrel. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/Masterminds/squirrel.git
#   cd squirrel
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of Masterminds/squirrel and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "Masterminds/squirrel(\\.git)?\\b" \\
  && ok "origin remote is Masterminds/squirrel" \\
  || miss "origin remote is not Masterminds/squirrel (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "squirrel.go" \\
  && ok "squirrel.go" \\
  || miss "missing critical file: squirrel.go"
test -f "select.go" \\
  && ok "select.go" \\
  || miss "missing critical file: select.go"
test -f "statement.go" \\
  && ok "statement.go" \\
  || miss "missing critical file: statement.go"
test -f "where.go" \\
  && ok "where.go" \\
  || miss "missing critical file: where.go"
test -f "placeholder.go" \\
  && ok "placeholder.go" \\
  || miss "missing critical file: placeholder.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 773 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~743d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/Masterminds/squirrel"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Squirrel is a fluent SQL query builder for Go that generates parameterized SQL statements without an ORM. It composes SELECT, INSERT, UPDATE, and DELETE queries from chainable methods (e.g., .Select("*").From("users").Where(sq.Eq{"id": 5})), handles placeholder formatting for different databases (PostgreSQL's $1 syntax, MySQL's ?), and can execute queries directly against database/sql connections or prepared statement caches. Single-package structure at repository root: core builder types (Select, Insert, Update, Delete) live in select.go, insert.go, update.go, delete.go; context-aware variants in *_ctx.go files; helper types like Where, Expr, Case in where.go, expr.go, case.go; statement caching in stmtcacher.go; integration tests under integration/ subdirectory. No subdirectory packages—everything is the github.com/Masterminds/squirrel namespace.

👥Who it's for

Go backend developers building database applications who need to construct dynamic SQL queries programmatically without ORM overhead—particularly those using PostgreSQL or MySQL who need safe parameterization and want fluent, readable query composition in application code.

🌱Maturity & risk

Squirrel is in maintenance mode (per README badge showing 'Stability: Maintenance'). The codebase is ~126KB of Go, has comprehensive test coverage (every .go file has a matching _test.go), uses Travis CI, and depends on minimal external packages (lann/builder, stretchr/testify). Production-ready but not actively developed—bug fixes accepted slowly, no new features planned.

Low-risk for a mature library: only 3 direct dependencies (lann/builder, lann/ps, testify), all stable and widely used. The single-maintainer maintenance-mode status means critical bugs may take time to merge. No visible breaking-change risk since the API is frozen. The lack of active development means it won't track bleeding-edge SQL features or database-specific innovations quickly.

Active areas of work

Repository is in maintenance: accepting bug fixes but no active feature development. No milestone or active PR information visible from file list, but the presence of *_ctx.go files alongside non-context versions indicates past work on context.Context support. Last activity inferred from Travis CI integration and recent test files, but the README explicitly states this is 'complete'.

🚀Get running

Clone and verify: git clone https://github.com/Masterminds/squirrel && cd squirrel && go test ./... (uses go.mod, Go 1.14+). No external services or build steps required.

Daily commands: No server—this is a library. Run tests with go test ./... or go test -v ./.... Integration tests in integration/ subdirectory can be run with appropriate database setup (see integration/integration_test.go).

🗺️Map of the codebase

  • squirrel.go — Entry point and core API definition that exports the public builder functions (Select, Insert, Update, Delete) all developers must understand.
  • select.go — Implements the SELECT query builder with fluent chaining; foundational pattern for understanding how all statement builders work.
  • statement.go — Abstract statement interface and helper functions that define the contract all SQL builders (SELECT, INSERT, UPDATE, DELETE) must fulfill.
  • where.go — WHERE clause builder using the Eq/expr pattern; critical for understanding predicate composition across all statement types.
  • placeholder.go — Placeholder token handling and SQL argument interpolation logic; essential for secure parameterized query generation.
  • expr.go — Expression abstraction layer enabling composable SQL fragments; foundational pattern repeated throughout the codebase.
  • squirrel_ctx.go — Context-aware variants of all builders; required reading for understanding the context-propagation pattern in modern Go code.

🛠️How to make changes

Add a new SQL expression type (e.g., BETWEEN, IN, custom operator)

  1. Define a struct type in expr.go that satisfies the Sqlizer interface (ToSql() method) (expr.go)
  2. Implement ToSql() to return the SQL string and args slice for your expression (expr.go)
  3. Export a helper function (e.g., Between, In) to construct your expression type (expr.go)
  4. Add unit tests in expr_test.go to verify SQL generation and placeholder handling (expr_test.go)
  5. Use your expression in Where() clauses: sq.Select().From().Where(sq.Between("age", 18, 65)) (where.go)

Add a new SQL clause to SELECT builder (e.g., HAVING, WITH, WINDOW)

  1. Add a field and builder method to SelectBuilder struct in select.go following the fluent pattern (select.go)
  2. Append the clause string to the SQL in SelectBuilder.ToSql() at the correct position (select.go)
  3. Create a matching context-aware method in SelectBuilder_Ctx struct in select_ctx.go (select_ctx.go)
  4. Write test cases in select_test.go and select_ctx_test.go verifying the clause appears in correct SQL order (select_test.go)

Support a new database placeholder style (e.g., Oracle's :N notation)

  1. Add a new PlaceholderFormat constant in placeholder.go (e.g., Oracle = iota) (placeholder.go)
  2. Implement the placeholder format case in the ReplacePlaceholders() function's switch statement (placeholder.go)
  3. Add unit tests in placeholder_test.go covering conversion from ? to your new format (placeholder_test.go)
  4. Usage: builder.PlaceholderFormat(sq.Oracle).ToSql() will now use :1, :2, :3 etc. (squirrel.go)

Add a new statement type (e.g., UNION, WITH, CREATE TABLE)

  1. Create a new file (e.g., union.go) with a UnionBuilder struct embedding BaseBuilder (union.go)
  2. Implement the Sqlizer interface with a ToSql() method returning SQL and args (union.go)
  3. Export a constructor function (Union, With, CreateTable) in squirrel.go (squirrel.go)
  4. Create union_ctx.go with context-aware variant following the _ctx.go pattern (union_ctx.go)
  5. Write comprehensive tests in union_test.go and union_ctx_test.go (union_test.go)

🔧Why these technologies

  • Builder pattern (fluent API) — Enables readable, chainable SQL construction with compile-time type safety instead of string concatenation or variable SQL building.
  • Expression interface (Sqlizer) — Allows composable SQL fragments that can be mixed and matched (Eq, Lt, Like, custom), making WHERE/HAVING predicates extensible without modifying core code.
  • Placeholder token system — Supports multiple database drivers (MySQL, PostgreSQL, SQLite, Oracle) with different placeholder formats (?, $1, :1, @1) from a single builder API.
  • Context-aware variants (*_ctx files) — Modern Go applications require context propagation for timeouts, cancellation, and observability; separate builders avoid bloating the main API while providing opt-in support.
  • Statement caching (stmtcacher) — Wraps prepared statement execution, reducing query parsing overhead and improving performance for repeated statements across the application.

⚖️Trade-offs already made

  • NOT an ORM; generates SQL strings only

    • Why: Simplicity and zero magic; developers maintain explicit control over SQL; no reflection overhead or schema mapping.
    • Consequence: Applications must still handle row scanning, type conversions, and database execution manually; not suitable for rapid CRUD-heavy development.
  • *Separate _ctx variants instead of embedding context in main builders

    • Why: Backward compatibility and API simplicity; context is optional, not mandatory.
    • Consequence: Code duplication across select.go/select_ctx.go, insert.go/insert_ctx.go etc.; maintainers must keep both in sync.
  • Placeholder format is post-generation via ReplacePlaceholders()

    • Why: Single builder generates dialect-agnostic SQL; conversion happens at the boundary (database.Prepare step).
    • Consequence: Slight performance overhead for placeholder substitution; cannot catch placeholder mismatches until runtime.
  • No SQL validation or type checking

    • Why: Avoids strong coupling to schema definitions; builder generates syntactically correct SQL but doesn't validate column names, types, or constraints.
    • Consequence: Errors surface only at database execution time, not during builder construction.

🚫Non-goals (don't propose these)

  • Does not validate column names, table names, or schema constraints at build time.
  • Does not map database rows to Go structs (see Structable for that); row scanning is manual.
  • Does not provide transaction or connection pooling management; use database/sql directly.
  • Does not support all SQL dialects equally; some features (window functions, CTEs) may need manual string building for edge cases.
  • Not a query optimizer or execution planner; generates SQL strings that the database engine optimizes.

🪤Traps & gotchas

Placeholder escaping: question marks must be doubled (??) in raw SQL strings to avoid being interpreted as placeholders—mentioned in README but easy to miss. Context timeout semantics differ between *_ctx variants and non-ctx versions; be careful mixing them. PlaceholderFormat is not thread-safe if modified after builder creation; set it early. Prepared statement cache (StmtCache) must be closed; it wraps the underlying DB connection semantics.

🏗️Architecture

💡Concepts to learn

  • Builder Pattern — Squirrel's entire API (Select().From().Where().ToSql()) is built on method chaining and immutable builder state managed by lann/builder struct tags; understanding this is essential to extending Squirrel.
  • Parameterized Queries / Prepared Statements — Squirrel's core value is separating SQL structure from data via placeholders (?/$1/:name) and args arrays to prevent SQL injection; this is critical to understanding why ToSql() returns (string, []interface{}).
  • Placeholder Format Abstraction — Squirrel's placeholder.go translates ? to $N (PostgreSQL) or :name (Oracle) at query time; this abstraction lets you write database-agnostic builders and swap syntax on deployment.
  • Fluent Interface — Squirrel methods return the builder itself (or a modified copy via lann/builder immutability) to enable readable chaining; this is a UX pattern, not a SQL concept, but defines how you'll write every query.
  • Statement Caching — StmtCache (stmtcacher.go) pre-compiles SQL into prepared statements to avoid repeated parsing overhead; critical for high-throughput applications where the same query shape runs many times with different args.
  • Context-Aware Database Operations — The *_ctx.go files (select_ctx.go, insert_ctx.go, etc.) support context.Context for cancellation and timeouts; this is Go idiomatic and required for production servers handling concurrent requests.
  • Expression Escaping in DSLs — Squirrel's Expr type (expr.go) allows embedding raw SQL when the builder doesn't support a feature (e.g., window functions, CTEs); knowing when and how to use Expr vs. composition is key to avoiding XSS-like mistakes or maintaining flexibility.
  • Masterminds/structable — Official companion repo: table-struct mapper built on top of Squirrel for ORM-lite use cases.
  • jmoiron/sqlc — Alternative approach: generates type-safe query code from SQL, avoiding builder pattern but trading flexibility for compile-time guarantees.
  • uptrace/bun — Modern successor in the Go SQL space: ORM with query builder syntax, actively developed, targets Go 1.18+ with generics.
  • lib/pq — PostgreSQL driver for Go; Squirrel queries are commonly executed via pq connections, often used with Dollar placeholder format.
  • go-sql-driver/mysql — MySQL driver for Go; Squirrel queries with Question placeholder format run on this driver.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add context cancellation tests for statement cacher implementations

The repo has stmtcacher_ctx.go and stmtcacher_noctx.go implementations but stmtcacher_ctx_test.go lacks comprehensive tests for context deadline exceeded, cancellation, and timeout scenarios. This is critical for production use where context handling prevents resource leaks.

  • [ ] Review stmtcacher_ctx.go to understand context propagation in Prepare, PreparContext, and Exec methods
  • [ ] Add test cases in stmtcacher_ctx_test.go for context.WithCancel, context.WithTimeout, and context.WithDeadline scenarios
  • [ ] Verify that cancelled contexts properly cleanup prepared statements and don't leak connections
  • [ ] Compare test patterns with existing delete_ctx_test.go, select_ctx_test.go, and update_ctx_test.go for consistency

Add integration tests for edge cases in WHERE clause building

The where.go file implements complex WHERE clause composition logic with Eq, NotEq, Lt, Gt, And, Or operations. The integration/integration_test.go appears minimal. Add comprehensive tests for nested conditions, NULL handling, and operator combinations against real databases.

  • [ ] Examine where.go and expr.go to identify all operator combinations (AND/OR nesting, comparison operators with NULL)
  • [ ] Expand integration/integration_test.go with test cases for complex WHERE scenarios like (A=1 AND (B IS NULL OR C>5))
  • [ ] Add tests for edge cases: empty WHERE clauses, multiple nested conditions, NULL comparisons
  • [ ] Test against SQLite in integration test to ensure actual SQL generation correctness

Add placeholder strategy tests for different SQL dialects

The placeholder.go file handles different placeholder modes ($1 for PostgreSQL, ? for MySQL, etc.) but placeholder_test.go only has basic unit tests. Add comprehensive tests validating correct placeholder generation across INSERT, UPDATE, DELETE, and SELECT statements with complex joins.

  • [ ] Review placeholder.go Mode enum (Dollar, Question, etc.) and placeholderFuncs mapping
  • [ ] Add test cases in placeholder_test.go for each Mode with actual SQL statement generation from insert.go, update.go, delete.go, select.go
  • [ ] Add edge cases: statements with many parameters (50+), mixed literal values and parameters, nested SELECT statements
  • [ ] Verify placeholder ordering is consistent across different statement types to prevent SQL injection vulnerabilities

🌿Good first issues

  • Add comprehensive test coverage for edge cases in case.go—currently case_test.go exists but complex nested CASE expressions are common in real queries and deserve stress testing.
  • Document the interaction between Suffix/Prefix methods and different SQL dialects (PostgreSQL RETURNING, MySQL LIMIT, etc.) in a new examples or docs file.
  • Add benchmark tests comparing ToSql() performance vs. string concatenation for typical query patterns (5-10 WHERE clauses, multi-join scenarios) to guide users on when Squirrel overhead is negligible.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 1ded578 — Nit: Fix InsertBuilder .Into() argument name (#375) (VojtechVitek)
  • d8eb51b — [Masterminds#82] Added FROM clause to update builder (#256) (mlaflamm)
  • e1c3903 — Change to get GitHub to recognize the license (#339) (mikeschinkel)
  • 49f2683 — feat: add remove select builder columns method (#331) (PatricPippi)
  • 9b18b54 — #316 JoinClause with subquery produces wrong dollar parameter placeholders (#317) (strider2038)
  • 75b018d — Typo in comment (#304) (ivorscott)
  • def598c — #301 Conjunction produces wrong dollar parameter placeholders (#302) (strider2038)
  • 84ae2bc — Fix Select subquery with DollarPlaceholder (#298) (lann)
  • cd1fe0a — Add missing MustSql methods (#288) (swithek)
  • 2499a26 — doc: fix deprecated usage of NewStmtCache (#274) (elvizlai)

🔒Security observations

The Squirrel SQL query builder has a moderate security posture. Primary concerns are outdated Go runtime version (1.14, EOL since 2021) and outdated test dependencies that should be updated immediately. As a query builder library, the design appears sound for preventing SQL injection through parameterized queries, but users must be educated on proper usage. The project's maintenance-only status poses long-term risk for security updates. No hardcoded secrets, exposed credentials, or infrastructure misconfigurations were detected in the provided materials. Immediate action recommended: upgrade Go version and update dependencies.

  • Medium · Outdated Go Version — go.mod. The project specifies 'go 1.14' in go.mod, which is significantly outdated. Go 1.14 reached end-of-life in August 2021 and no longer receives security updates. This exposes the project to known vulnerabilities in the Go runtime and standard library. Fix: Update to a currently supported Go version (1.21 or later). Review the project's compatibility requirements and update go.mod accordingly.
  • Medium · Outdated Testing Dependency — go.mod. This is an indirect security concern as it may contain bugs or vulnerabilities in test infrastructure, though the impact is limited to development/testing phases. Fix: Update github.com/stretchr/testify to the latest stable version (v1.8.4 or later).
  • Low · SQL Injection Risk Pattern — select.go, insert.go, delete.go, update.go, where.go. As a SQL query builder library, Squirrel constructs SQL queries programmatically. While the library itself appears designed to use parameterized queries, users of this library could misuse it by concatenating strings or using unsafe patterns. The file structure suggests raw SQL handling in multiple files (select.go, insert.go, delete.go, update.go). Fix: Ensure comprehensive documentation warning users against string concatenation. Review code to verify all query building properly uses parameterized placeholders. Add security examples to README.
  • Low · Maintenance Status - Security Updates Risk — README.md. The README explicitly states the project is in 'Maintenance' status with bug fixes merged slowly and the maintainer not necessarily responding to issues. This reduces the likelihood of timely security patches if vulnerabilities are discovered. Fix: Consider forking and maintaining the codebase internally if used in security-critical applications, or monitor for community forks with active maintenance. Implement regular dependency audits using 'go mod audit' or tools like Dependabot.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · Masterminds/squirrel — RepoPilot