go-query
A modular, production-ready query library for Golang with a powerful, Google-like search syntax. Features CBOR-encoded cursors, rich operators, and a clean GORM-style API.
π€ AI-Generated Code: This entire library was generated by AI (Claude Sonnet 4.5 and Cursor Auto) as a collaborative programming exercise. While comprehensive testing has been included, please review and test thoroughly before using in production environments.
β¨ Key Features
- π Google-like Search: Type bare words and they'll be searched automatically
- π― GORM-style API: Pass a pointer to your result slice, just like GORM
- π¦ CBOR Cursors: 50% smaller than JSON, faster encoding
- π§© Modular: MongoDB and GORM executors are separate, optional modules
- π SQL Injection Protection: Built-in validation and parameterized queries
- π¨ Rich Operators: String matching (LIKE, CONTAINS, REGEX) + array operations (IN, NOT IN)
- π Smart Parentheses: Full support for complex nested expressions
- β‘ Parser Cache: Thread-safe cache for maximum performance
Installation
# Core library
go get github.com/hadi77ir/go-query
# MongoDB executor (optional - separate module)
go get github.com/hadi77ir/go-query/executors/mongodb
# GORM executor for SQL databases (optional - separate module)
go get github.com/hadi77ir/go-query/executors/gorm
# Memory executor for in-memory slices/maps (optional - separate module)
go get github.com/hadi77ir/go-query/executors/memory
Quick Start
Performance Tip: For best performance, use ParserCache to cache parsed queries. This is especially important in production environments where the same queries are parsed repeatedly.
import (
"github.com/hadi77ir/go-query/executors/mongodb"
"github.com/hadi77ir/go-query/parser"
"github.com/hadi77ir/go-query/query"
)
// Create parser cache (recommended for production)
// Cache size: 0 = no caching, >0 = cache last N queries
cache := parser.NewParserCache(100) // Cache up to 100 queries
MongoDB Example
// Connect and create executor
collection := client.Database("mydb").Collection("users")
executor := mongodb.NewExecutor(collection, query.DefaultExecutorOptions())
// Parse query using cache (recommended) - notice the bare "wireless" search term!
q, _ := cache.Parse(`wireless mouse price < 100`)
// Execute - results go directly into your slice
var products []bson.M
result, _ := executor.Execute(ctx, q, "", &products)
fmt.Printf("Found %d products\n", result.TotalItems)
GORM/SQL Example
executor := gorm.NewExecutor(db, &User{}, query.DefaultExecutorOptions())
// Create parser cache for performance
cache := parser.NewParserCache(100)
// Bare search terms automatically search the default field (name)
q, _ := cache.Parse(`john active`) // Searches name for "john" and "active"
var users []User
result, _ := executor.Execute(ctx, q, "", &users)
Memory/In-Memory Example
// Perfect for testing or filtering in-memory data
products := []Product{
{Name: "Wireless Mouse", Price: 29.99, Category: "electronics"},
{Name: "USB Cable", Price: 9.99, Category: "accessories"},
}
executor := memory.NewExecutor(products, query.DefaultExecutorOptions())
// Use parser cache for better performance
cache := parser.NewParserCache(50)
q, _ := cache.Parse(`price < 50 and category = electronics`)
var results []Product
result, _ := executor.Execute(ctx, q, "", &results)
// No database needed!
Quick Query Examples
// Google-style bare search
"wireless mouse" // Searches name for "wireless" AND "mouse"
"price < 100 category = electronics" // Mix field queries with bare terms
// Complex expressions
"(status = active and age > 18) or premium = true"
"category IN [electronics, computers] and price < 500"
// Pagination and sorting
"page_size = 20 sort_by = price sort_order = desc"
See Query Syntax Guide for complete syntax documentation.
Supported Operators
Comparison
String Matching
LIKE, NOT LIKE - SQL-style with % and _ wildcards
CONTAINS, ICONTAINS - Substring match (case-sensitive/insensitive)
STARTS_WITH, ENDS_WITH - Prefix/suffix match
REGEX - Regular expression
Array
IN, NOT IN - Value in/not in array
Logical
AND, OR - With proper precedence
() - Parentheses for grouping (fully nestable)
- Implicit AND - Bare terms are automatically AND'ed
Documentation
π Complete documentation is available in the docs/ folder:
Module Structure
Each executor is a separate Go module:
go-query/ # Core library
βββ parser/ # Query parser with cache
βββ query/ # Core types
βββ executor/ # Interface
βββ internal/cursor/ # CBOR cursors
executors/mongodb/ # Separate module!
executors/gorm/ # Separate module!
executors/memory/ # Separate module! (zero deps)
Benefits:
- Only import what you need
- No unnecessary dependencies
- Smaller binary sizes
- Memory executor has ZERO external dependencies
Result Structure
type Result struct {
NextPageCursor string // Cursor for next page
PrevPageCursor string // Cursor for previous page
TotalItems int64 // Total matching items
ShowingFrom int // Start index (1-based)
ShowingTo int // End index (1-based)
ItemsReturned int // Items in this page
Error error // Any error
}
// Data is stored directly in your slice variable!
var users []User
result, _ := executor.Execute(ctx, q, "", &users)
// users now contains the results
// Use cursor for pagination
if result.NextPageCursor != "" {
var nextPage []User
executor.Execute(ctx, q, result.NextPageCursor, &nextPage)
}
Count Method
Get the total number of matching items without fetching data:
// Parse query
q, _ := cache.Parse("category = electronics and price > 100")
// Get count (ignores pagination)
count, err := executor.Count(ctx, q)
if err != nil {
// Handle error
}
fmt.Printf("Found %d matching products\n", count)
// Count matches result.TotalItems from Execute
var products []Product
result, _ := executor.Execute(ctx, q, "", &products)
fmt.Printf("TotalItems: %d (same as count: %d)\n", result.TotalItems, count)
Key Points:
- Returns total count of all matching items (ignores pagination)
- Always matches
result.TotalItems from Execute with the same query
- More efficient when you only need the count without data
- Available on all executors (GORM, MongoDB, Memory, Wrapper)
License
This project is licensed under the Apache License, Version 2.0. See the LICENSE file for details.
Support
Open an issue on GitHub for bugs or feature requests.