# Text Search

Often, you'll want queries to load models based on field similarity instead of ID matching. This is particularly common when trying to implement search functionality. Botanist is not a search engine, nor are any of the underlying supported databases. However, Botanist has support for basic searching which can often be good enough for simple model filtering and matching.

In your botanist_query declaration, update your type to contain a searchable key mapping to a tuple of text (VARCHAR, TEXT etc.) fields that you'd like to enable searching for. For example, updating the Hero type to support searching on the name field and the hometown field would look like:

#[botanist_query(
    Hero(
        searchable = (name, hometown)
        all = true
    )

    Context = Context,
    PrimaryKey = Uuid,
)]

Note

You must set the all key to true here. This will enable your models to be fetched without knowing the exact ID. This is enforced for searching as models are returned based on field matches instead of ID matches.

If you fire up your application and inspect your schema, you'll see that the multi-select query for Hero (i.e heros(...)) now has an optional query argument:

heros(ids: [Uuid!], limit: Int, offset: Int, query: HerosQuery): [Hero!]!

Inspecting the schema further, you'll see the definition for HerosQuery looks like:

input HerosQuery {
    name: String
    hometown: String
}

Any field specified in the searchable tuple will appear in the query input type. Fields in this query are optional and as many or as few as you'd like may be set for any given query.

# Basic Queries

In general, search queries are implemented using basic, case insensitive like queries. These results are returned in any order the database sees fit. Queries will generally take the form of:

WHERE field1 ILIKE "<query>"
   OR field2 ILIKE "<query>"
   ...

If you're using Postgres as your backing database, it's recommended that you read on to the following section for an improved search experience.

# Postgres Prefix Queries

Warning

These queries are only generated for Postgres. This section will not work on for any other database.

As Postgres supports full text search, Botanist can generate some more useful queries when operating on a Postgres database. In particular, Botanist contains a basic prefix match search implementation. To get started with prefix search, enable the postgres_prefix_search feature for both botanist and botanist_codegen. Queries will now perform prefix matching and will not rely exclusively on case-insensitive like (ILIKE) anymore.

In general, Botanist will utilize the to_tsvector, to_tsquery and position functions with the @@ (match) operator. A query on a single field will look something like:

WHERE
	to_tsvector(field1) @@ to_tsquery('<query>:*')
ORDER BY
	field1 ILIKE '<query>%' DESC,
	position('<query>' in field1) ASC
  • First, the field in question (field1) is converted to a text-search vector.
  • The vector is then matched against the text-search query (the user provided query with :* to indicate it should be treated as a prefix)
  • The results are then ordered:
    • First, by results with an exact prefix match (the string starts with the prefix)
    • Next, by the position of the match within the result. Matches where the position is closer to the front rank higher.