Skip to content

A pure go lucene parser with no dependencies.

License

grindlemire/go-lucene

Repository files navigation

go-lucene

Go Reference

A zero-dependency Lucene query parser for Go that converts Lucene syntax into SQL queries.

Features

  • Full Lucene syntax support (compatible with Apache Lucene 9.4.2)
  • SQL injection safe with parameterized queries
  • Zero dependencies
  • Extensible with custom SQL drivers
  • PostgreSQL support out of the box

Installation

go get github.com/grindlemire/go-lucene

Basic Usage

query := `name:"John Doe" AND age:[25 TO 35]`
filter, err := lucene.ToPostgres(query)
// Result: (("name" = 'John Doe') AND ("age" >= 25 AND "age" <= 35))

API Methods

Direct SQL Generation

filter, err := lucene.ToPostgres(query)

Parameterized Queries (Recommended)

filter, params, err := lucene.ToParameterizedPostgres(query)
db.Query(sql, params...)

Default Fields

filter, err := lucene.ToPostgres("red OR green", lucene.WithDefaultField("color"))
// Result: ("color" = 'red') OR ("color" = 'green')

Lucene to SQL Operator Mapping

Lucene Query SQL Output Description
field:value "field" = 'value' Exact match
field:"phrase with spaces" "field" = 'phrase with spaces' Quoted phrase
field1:value1 AND field2:value2 ("field1" = 'value1') AND ("field2" = 'value2') Boolean AND
field1:value1 OR field2:value2 ("field1" = 'value1') OR ("field2" = 'value2') Boolean OR
NOT field:value NOT("field" = 'value') Boolean NOT
+field:value "field" = 'value' Required (equivalent to no operator)
-field:value NOT("field" = 'value') Prohibited (equivalent to NOT)
field:[min TO max] "field" >= min AND "field" <= max Inclusive range
field:{min TO max} "field" BETWEEN 'min' AND 'max' (strings) or "field" > min AND "field" < max (numbers) Exclusive range
field:[min TO *] "field" >= min Open-ended range (min to infinity)
field:[* TO max] "field" <= max Open-ended range (negative infinity to max)
field:* "field" SIMILAR TO '%' Wildcard match (matches anything)
field:pattern* "field" SIMILAR TO 'pattern%' Wildcard suffix
field:pattern? "field" SIMILAR TO 'pattern_' Single character wildcard
field:/regex/ "field" ~ '/regex/' Regular expression match
(field1:value1 OR field2:value2) AND field3:value3 (("field1" = 'value1') OR ("field2" = 'value2')) AND ("field3" = 'value3') Grouping

Examples

Complex Query

query := `name:"John Doe" AND age:[25 TO 35] AND NOT status:inactive`
// SQL: (("name" = 'John Doe') AND ("age" >= 25 AND "age" <= 35)) AND (NOT("status" = 'inactive'))

Parameterized Output

filter, params, err := lucene.ToParameterizedPostgres(`color:red AND type:"gala"`)
// SQL: ("color" = $1) AND ("type" = $2)
// Params: ["red", "gala"]

Wildcard Queries

filter, err := lucene.ToPostgres(`name:John* AND email:*@example.com`)
// SQL: ("name" SIMILAR TO 'John%') AND ("email" SIMILAR TO '%@example.com')

Regular Expression Queries

filter, err := lucene.ToPostgres(`url:/example\.com\/.*\/`)
// SQL: "url" ~ '/example\.com\/.*\/'

Custom SQL Drivers

Extend the library for different SQL dialects by creating custom drivers:

import (
    "github.com/grindlemire/go-lucene/pkg/driver"
    "github.com/grindlemire/go-lucene/pkg/lucene/expr"
)

type MySQLDriver struct {
    driver.Base
}

func NewMySQLDriver() MySQLDriver {
    fns := map[expr.Operator]driver.RenderFN{
        expr.Equals: func(left, right string) (string, error) {
            return fmt.Sprintf("`%s` = %s", left, right), nil
        },
    }

    // Use shared functions for other operators
    for op, sharedFN := range driver.Shared {
        if _, exists := fns[op]; !exists {
            fns[op] = sharedFN
        }
    }

    return MySQLDriver{Base: driver.Base{RenderFNs: fns}}
}

// Usage
mysqlDriver := NewMySQLDriver()
expr, _ := lucene.Parse(`color:red`)
filter, _ := mysqlDriver.Render(expr)
// Result: `color` = 'red'

About

A pure go lucene parser with no dependencies.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 9

Languages