Text search for postgres w/ ORM using Golang
- Based on Textacular
- Utilizes gorm
- Creates scopes that, in conjunction with gorm, find records and scan them into Go structs
- Offers equivalent of Textacular advanced search
- Offers equivalent of Textacular fuzzy search
- You can even make your own types of search
- Generated scopes have no state so they can be used repeatedly
import (
"github.com/jnfeinstein/gorm"
"github.com/jnfeinstein/gortex"
_ "github.com/lib/pq"
)
type Note struct {
Id int64
Contents string
Author string
}
DB, _ := gorm.Open("postgres", $POSTGRES_SRC)
DB.AutoMigrate(Note{})
var notes []Note
gortex.NewSearchScope(clause interface{}, opts ...map[string]interface{})
clause interface{}
May be a struct
or map[string]interface{}
which specifies the fields and values to search
opts map[string]interface{}
List of options which might include:
"language": string
Specify language for search
"exclusive": bool
Controls whether search fields should be AND'd or OR'd
Note: If clause
is a struct
, it will automatically set the table to the struct's type
searchScope1 := gortex.NewSearchScope(Note{Contents: "brown"}, map[string]interface{}{"language": "english"})
DB.Scopes(searchScope1).Select("*").Find(¬es)
//// Finds all records with 'brown' in the contents field
searchScope2 := gortex.NewSearchScope(map[string]interface{}{"contents": "brown", "author": "dog"}, map[string]interface{}{"exclusive": false})
DB.Scopes(searchScope2).Select("*").Find(¬es)
//// Using 'simple' language, finds all records with 'brown' in the contents field OR 'dog' in the author field
Note: You must include .Select("*"), which instructs gorm to select all fields in addition to the search rankings
gortex.NewFuzzySearchScope(clause interface{}, opts ...map[string]interface{})
clause interface{}
May be a struct
or map[string]interface{}
which specifies the fields and values to search
opts map[string]interface{}
List of options which might include:
"exclusive": bool
Controls whether search fields should be AND'd or OR'd
gortex.InitFuzzySearch(&DB) //// Creats pg_trgm extension
gortex.SetFuzzySearchLimit(&DB, limit) //// Optional, sets fuzzy search limit (default is 0.1)
//// Only need to be run once
searchScope3 := gortex.NewFuzzySearchScope(Note{Contents: "or"})
DB.Scopes(searchScope3).Select("*").Find(¬es)
//// Finds all records with something like 'or' in the contents, maybe 'organic' or 'boring'
All gortex searches use a series of condition queries to determine qualification, and a series of select queries to determine rank. These queries are defined by the following interface:
type SearchSqlFormat interface {
Rank(field string, opts map[string]interface{}) string
Condition(field string, opts map[string]interface{}) string
}
field string
: Name of the field
opts map[string]interface{}
The very same map passed into gortex.NewCustomSearchScope
gortex.NewCustomSearchScope(format SearchSqlFormat, clause interface{}, opts ...map[string]interface{})
clause interface{}
May be a struct
or map[string]interface{}
which specifies the fields and values to search
opts map[string]interface{}
List of options which might include:
"exclusive": bool
Controls whether search fields should be AND'd or OR'd
type customSearchFormat struct{}
func (c customSearchFormat) Rank(field string, opts map[string]interface{}) string {
return fmt.Sprintf("LENGTH(%s)", field)
}
func (c customSearchFormat) Condition(field string, opts map[string]interface{}) string {
return fmt.Sprintf("%s LIKE ?", field)
}
searchScope4 := gortex.NewCustomSearchScope(customSearchFormat{}, Note{Author: "L%"})
DB.Scopes(searchScope4).Select("*").Find(¬es)
//// Finds all records with an author beginning with 'L' and ranks them by length of author
gortex.AutoIndex(db *gorm.DB, language string, clause interface{}, table ...string)
db *gorm.DB
Instance of gorm.DB on which to add indexes (uses .Exec)
language string
Postgres language to be indexed
clause interface{}
May be a struct, string
, or []string
containing the fields to be indexed
table ...string
Specifies the table to migrate if clause
is a string
or []string
gortex.AutoIndex(&DB, "english", Note{})
//// Adds gin indexes idx_notes_content and idx_notes_author
gortex.AutoIndex(&DB, "english", "contents", "notes")
//// Adds gin index idx_notes_content
gortex.AutoIndex(&DB, "english", "contents", []string{"notes", "author"})
//// Adds gin indexes idx_notes_content and idx_notes_author
Note: This function is best-effort, and is not designed to be re-run. Therefore it will not return errors. You should verify the indexes manually if you care.
Feel free to do so!