Add full text search support using TSV indexes

This commit is contained in:
Vikram Rangnekar
2019-04-05 01:44:30 -04:00
parent 907ada9263
commit d1bf87e19c
8 changed files with 134 additions and 8 deletions

View File

@ -397,12 +397,28 @@ func (v *selectBlock) renderRelationship(w io.Writer, schema *DBSchema) {
func (v *selectBlock) renderWhere(w io.Writer) error {
if v.sel.Where.Op == qcode.OpEqID {
col, ok := v.schema.PCols[v.sel.Table]
if !ok {
return fmt.Errorf("no primary key defined for %s", v.sel.Table)
t, err := v.schema.GetTable(v.sel.Table)
if err != nil {
return err
}
if len(t.PrimaryCol) == 0 {
return fmt.Errorf("no primary key column defined for %s", v.sel.Table)
}
fmt.Fprintf(w, `(("%s") = ('%s'))`, col.Name, v.sel.Where.Val)
fmt.Fprintf(w, `(("%s") = ('%s'))`, t.PrimaryCol, v.sel.Where.Val)
return nil
}
if v.sel.Where.Op == qcode.OpTsQuery {
t, err := v.schema.GetTable(v.sel.Table)
if err != nil {
return err
}
if len(t.TSVCol) == 0 {
return fmt.Errorf("no tsv column defined for %s", v.sel.Table)
}
fmt.Fprintf(w, `(("%s") @@ to_tsquery('%s'))`, t.TSVCol, v.sel.Where.Val)
return nil
}

View File

@ -337,6 +337,26 @@ func fetchByID(t *testing.T) {
}
}
func searchQuery(t *testing.T) {
gql := `query {
products(search: "Amazing") {
id
name
}
}`
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "products" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((("tsv") @@ to_tsquery('Amazing'))) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
resSQL, err := compileGQLToPSQL(gql)
if err != nil {
t.Fatal(err)
}
if resSQL != sql {
t.Fatal(errNotExpected)
}
}
func aggFunction(t *testing.T) {
gql := `query {
products {
@ -383,6 +403,7 @@ func TestCompileGQL(t *testing.T) {
t.Run("withWhereIsNull", withWhereIsNull)
t.Run("withWhereMultiOr", withWhereMultiOr)
t.Run("fetchByID", fetchByID)
t.Run("searchQuery", searchQuery)
t.Run("belongsTo", belongsTo)
t.Run("oneToMany", oneToMany)
t.Run("manyToMany", manyToMany)

View File

@ -18,11 +18,16 @@ type TTKey struct {
type DBSchema struct {
ColMap map[TCKey]*DBColumn
ColIDMap map[int]*DBColumn
PCols map[string]*DBColumn
Tables map[string]*DBTableInfo
RelMap map[TTKey]*DBRel
}
type DBTableInfo struct {
PrimaryCol string
TSVCol string
}
type RelType int
const (
@ -63,7 +68,7 @@ func initSchema() *DBSchema {
return &DBSchema{
ColMap: make(map[TCKey]*DBColumn),
ColIDMap: make(map[int]*DBColumn),
PCols: make(map[string]*DBColumn),
Tables: make(map[string]*DBTableInfo),
RelMap: make(map[TTKey]*DBRel),
}
}
@ -71,6 +76,7 @@ func initSchema() *DBSchema {
func updateSchema(schema *DBSchema, t *DBTable, cols []*DBColumn) {
// Current table
ct := strings.ToLower(t.Name)
schema.Tables[ct] = &DBTableInfo{}
// Foreign key columns in current table
var jcols []*DBColumn
@ -82,8 +88,11 @@ func updateSchema(schema *DBSchema, t *DBTable, cols []*DBColumn) {
for _, c := range cols {
switch {
case c.Type == "tsvector":
schema.Tables[ct].TSVCol = c.Name
case c.PrimaryKey:
schema.PCols[ct] = c
schema.Tables[ct].PrimaryCol = c.Name
case len(c.FKeyTable) != 0:
if len(c.FKeyColID) == 0 {
@ -244,3 +253,11 @@ WHERE c.relkind = 'r'::char
return t, nil
}
func (s *DBSchema) GetTable(table string) (*DBTableInfo, error) {
t, ok := s.Tables[table]
if !ok {
return nil, fmt.Errorf("table info not found '%s'", table)
}
return t, nil
}