ihp-1.5.0: Haskell Web Framework
Copyright(c) digitally induced GmbH 2020
Safe HaskellNone
LanguageGHC2021

IHP.QueryBuilder

Description

QueryBuilder is mainly used for doing simple SELECT sql queries. It allows dynamic creation of sql queries in a type safe way.

For more complex sql queries, use sqlQuery.

This module re-exports all QueryBuilder submodules for backward compatibility.

Synopsis

Starting a Query

query :: forall model (table :: Symbol). (table ~ GetTableName model, Table model, DefaultScope table) => QueryBuilder table Source #

Represent's a SELECT * FROM .. query. It's the starting point to build a query. Used together with the other functions to compose a sql query.

Example: Fetching all users

allUsers <- query @User |> fetch
-- Runs a 'SELECT * FROM users' query

You can use it together with filterWhere:

activeUsers :: [User] <-
   query @User
    |> filterWhere (#active, True)
    |> fetch

Core Types

newtype QueryBuilder (table :: Symbol) Source #

The QueryBuilder is a flat newtype over SQLQuery. Each combinator directly modifies fields of the underlying SQLQuery, avoiding any recursive tree traversal.

Constructors

QueryBuilder 

Instances

Instances details
Table (GetModelByTableName table) => Default (QueryBuilder table) Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

def :: QueryBuilder table Source #

Show (QueryBuilder table) Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

showsPrec :: Int -> QueryBuilder table -> ShowS #

show :: QueryBuilder table -> String #

showList :: [QueryBuilder table] -> ShowS #

Eq (QueryBuilder table) Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

(==) :: QueryBuilder table -> QueryBuilder table -> Bool #

(/=) :: QueryBuilder table -> QueryBuilder table -> Bool #

KnownSymbol table => ToHtml (QueryBuilder table) Source #

Display QueryBuilder's as their sql query inside HSX

Instance details

Defined in IHP.QueryBuilder.Types

Methods

toHtml :: QueryBuilder table -> Markup

(model ~ GetModelByTableName table, KnownSymbol table) => Fetchable (QueryBuilder table) model Source # 
Instance details

Defined in IHP.Fetch

Associated Types

type FetchResult (QueryBuilder table) model 
Instance details

Defined in IHP.Fetch

type FetchResult (QueryBuilder table) model = [model]

Methods

fetch :: QueryBuilder table -> IO (FetchResult (QueryBuilder table) model) Source #

fetchOneOrNothing :: QueryBuilder table -> IO (Maybe model) Source #

fetchOne :: QueryBuilder table -> IO model Source #

type FetchResult (QueryBuilder table) model Source # 
Instance details

Defined in IHP.Fetch

type FetchResult (QueryBuilder table) model = [model]

data Condition Source #

Represents a WHERE condition

Instances

Instances details
Show Condition Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Eq Condition Source # 
Instance details

Defined in IHP.QueryBuilder.Types

SetField "whereCondition" SQLQuery (Maybe Condition) Source # 
Instance details

Defined in IHP.QueryBuilder.Types

data ConditionValue Source #

A condition value: either a parameterized encoder or a literal SQL fragment.

Constructors

Param !(Params ())

Parameterized value: compiler assigns $N

Literal !Text

Raw SQL text (for filterWhereSql, NULL comparisons, etc.)

data OrderByClause Source #

Represents an ORDER BY clause component

Instances

Instances details
NFData OrderByClause Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

rnf :: OrderByClause -> () #

Generic OrderByClause Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Associated Types

type Rep OrderByClause 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByClause = D1 ('MetaData "OrderByClause" "IHP.QueryBuilder.Types" "ihp-1.5.0-JkJMY5grI1LEXDOsW6DsRv" 'False) (C1 ('MetaCons "OrderByClause" 'PrefixI 'True) (S1 ('MetaSel ('Just "orderByColumn") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "orderByDirection") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 OrderByDirection)))
Show OrderByClause Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Eq OrderByClause Source # 
Instance details

Defined in IHP.QueryBuilder.Types

SetField "orderByClause" SQLQuery [OrderByClause] Source # 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByClause Source # 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByClause = D1 ('MetaData "OrderByClause" "IHP.QueryBuilder.Types" "ihp-1.5.0-JkJMY5grI1LEXDOsW6DsRv" 'False) (C1 ('MetaCons "OrderByClause" 'PrefixI 'True) (S1 ('MetaSel ('Just "orderByColumn") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "orderByDirection") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 OrderByDirection)))

data OrderByDirection Source #

ORDER BY direction

Constructors

Asc 
Desc 

Instances

Instances details
NFData OrderByDirection Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

rnf :: OrderByDirection -> () #

Generic OrderByDirection Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Associated Types

type Rep OrderByDirection 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByDirection = D1 ('MetaData "OrderByDirection" "IHP.QueryBuilder.Types" "ihp-1.5.0-JkJMY5grI1LEXDOsW6DsRv" 'False) (C1 ('MetaCons "Asc" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Desc" 'PrefixI 'False) (U1 :: Type -> Type))
Show OrderByDirection Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Eq OrderByDirection Source # 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByDirection Source # 
Instance details

Defined in IHP.QueryBuilder.Types

type Rep OrderByDirection = D1 ('MetaData "OrderByDirection" "IHP.QueryBuilder.Types" "ihp-1.5.0-JkJMY5grI1LEXDOsW6DsRv" 'False) (C1 ('MetaCons "Asc" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Desc" 'PrefixI 'False) (U1 :: Type -> Type))

data FilterOperator Source #

Operators used in WHERE clause conditions

Constructors

EqOp
col = val
NotEqOp
col != val
InOp
col IN (set)
NotInOp
col NOT IN (set)
IsOp
col IS val
IsNotOp
col IS NOT val
LikeOp !MatchSensitivity
col LIKE val
NotLikeOp !MatchSensitivity
col NOT LIKE val
MatchesOp !MatchSensitivity
col ~ pattern
GreaterThanOp
col > val
GreaterThanOrEqualToOp
col >= val
LessThanOp
col < val
LessThanOrEqualToOp
col <= val
SqlOp

Used by filterWhereSql

data MatchSensitivity Source #

Represents whether string matching should be case-sensitive or not

Type Classes

class DefaultScope (table :: Symbol) where Source #

Type class for default scoping of queries

Methods

defaultScope :: QueryBuilder table -> QueryBuilder table Source #

Instances

Instances details
DefaultScope table Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

defaultScope :: QueryBuilder table -> QueryBuilder table Source #

class EqOrIsOperator value Source #

Helper to deal with some_field IS NULL and some_field = 'some value'

Minimal complete definition

toEqOrIsOperator

Instances

Instances details
EqOrIsOperator otherwise Source # 
Instance details

Defined in IHP.QueryBuilder.Types

Methods

toEqOrIsOperator :: otherwise -> FilterOperator Source #

EqOrIsOperator (Maybe something) Source # 
Instance details

Defined in IHP.QueryBuilder.Types

class FilterPrimaryKey (table :: Symbol) where Source #

Type class for filtering by primary key

Methods

filterWhereId :: Id' table -> QueryBuilder table -> QueryBuilder table Source #

SQL Compilation

buildQuery :: forall (table :: Symbol). KnownSymbol table => QueryBuilder table -> SQLQuery Source #

Extract the SQLQuery from a QueryBuilder.

Hasql Compilation

toSQL :: forall (table :: Symbol). KnownSymbol table => QueryBuilder table -> Text Source #

Compile a QueryBuilder to SQL text (for testing / error messages). Discards the encoder.

Filtering

filterWhere :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, EqOrIsOperator value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a simple WHERE x = y condition to the query.

Example: Only show projects where active is True.

activeProjects <- query @Project
    |> filterWhere (#active, True)
    |> fetch
-- SELECT * FROM projects WHERE active = True

Example: Find book with title Learn you a Haskell.

book <- query @Book
    |> filterWhere (#title, "Learn you a Haskell")
    |> fetchOne
-- SELECT * FROM books WHERE name = 'Learn you a Haskell' LIMIT 1

Example: Find active projects owned by the current user.

projects <- query @Project
    |> filterWhere (#active, True)
    |> filterWhere (#currentUserId, currentUserId)
    |> fetch
-- SELECT * FROM projects WHERE active = true AND current_user_id = '..'

For dynamic conditions (e.g. involving NOW()), see filterWhereSql.

For WHERE x IN (a, b, c) conditions, take a look at filterWhereIn and filterWhereNotIn.

For WHERE x LIKE a or WHERE x ~ a conditions, see filterWhereLike and filterWhereMatches respectively. For case-insensitive versions of these operators, see filterWhereILike and filterWhereIMatches.

When your condition is too complex, use a raw sql query with sqlQuery.

filterWhereCaseInsensitive :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, EqOrIsOperator value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE LOWER(x) = LOWER(y) condition to the query.

Example: Get a user by an email address, ignoring case

user <- query @User
    |> filterWhereCaseInsensitive (#email, "marc@digitallyinduced.com")
    |> fetchOne
-- SELECT * FROM users WHERE LOWER(email) = 'marc@digitallyinduced.com'

For high performance it's best to have an index for LOWER(field) in your Schema.sql

>>> CREATE UNIQUE INDEX users_email_index ON users ((LOWER(email)));

filterWhereNot :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, EqOrIsOperator value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Like filterWhere but negates the condition.

Example: Only show projects created by other users.

activeProjects <- query @Project
    |> filterWhereNot (#userId, currentUserId)
    |> fetch
-- SELECT * FROM projects WHERE user_id != '23d5ea33-b28e-4f0a-99b3-77a3564a2546'

filterWhereIn :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder [value], DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, EqOrIsOperator value, Table model) => (Proxy name, [value]) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x IN (y) condition to the query.

Example: Only show projects where status is Draft or Active.

visibleProjects <- query @Project
    |> filterWhereIn (#status, [Draft, Active])
    |> fetch
-- SELECT * FROM projects WHERE status IN ('draft', 'active')

For negation use filterWhereNotIn

filterWhereInCaseInsensitive :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, EqOrIsOperator value, Table model) => (Proxy name, [Text]) -> QueryBuilder table -> QueryBuilder table Source #

filterWhereIdIn :: forall (table :: Symbol) model. (KnownSymbol table, Table model, model ~ GetModelByTableName table, DefaultParamEncoder [PrimaryKey (GetTableName model)]) => [Id model] -> QueryBuilder table -> QueryBuilder table Source #

filterWhereNotIn :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder [value], DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, EqOrIsOperator value) => (Proxy name, [value]) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x NOT IN (y) condition to the query.

Example: Only show projects where status is not Archived

visibleProjects <- query @Project
    |> filterWhereNotIn (#status, [Archived])
    |> fetch
-- SELECT * FROM projects WHERE status NOT IN ('archived')

The inclusive version of this function is called filterWhereIn.

filterWhereLike :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x LIKE y condition to the query.

Example: Find titles matching search term.

articles <- query @Article
    |> filterWhereLike (#title, "%" <> searchTerm <> "%")
    |> fetch
-- SELECT * FROM articles WHERE title LIKE '%..%'

filterWhereILike :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x ILIKE y condition to the query. Case-insensitive version of filterWhereLike.

Example: Find titles matching search term.

articles <- query @Article
    |> filterWhereILike (#title, "%" <> searchTerm <> "%")
    |> fetch
-- SELECT * FROM articles WHERE title ILIKE '%..%'

filterWhereMatches :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, table ~ GetTableName model, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x ~ y condition to the query.

Example: Find names with titles in front.

articles <- query @User
    |> filterWhereMatches (#name, "^(M(rs|r|iss)|Dr|Sir). ")
    |> fetch
-- SELECT * FROM articles WHERE title ~ '^(M(rs|r|iss)|Dr|Sir). '

filterWhereIMatches :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x ~* y condition to the query. Case-insensitive version of filterWhereMatches.

filterWherePast :: forall (table :: Symbol) (name :: Symbol) value. (KnownSymbol table, KnownSymbol name, HasField name (GetModelByTableName table) value, Table (GetModelByTableName table)) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Filter all rows by whether a field is in the past, determined by comparing 'NOW()' to the field's value.

Opposite of filterWhereFuture

Example: Fetch all posts scheduled for the past.

publicPosts <- query @Post
    |> filterWherePast #scheduledAt
    |> fetch
-- SELECT * FROM posts WHERE scheduled_at <= NOW()

filterWhereFuture :: forall (table :: Symbol) (name :: Symbol) value. (KnownSymbol table, KnownSymbol name, HasField name (GetModelByTableName table) value, Table (GetModelByTableName table)) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Filter all rows by whether a field is in the future, determined by comparing 'NOW()' to the field's value.

Opposite of filterWherePast

Example: Fetch all posts scheduled for the future.

hiddenPosts <- query @Post
    |> filterWhereFuture #scheduledAt
    |> fetch
-- SELECT * FROM posts WHERE scheduled_at > NOW()

filterWhereGreaterThan :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x > y condition to the query.

Example: Find assignments with grade greater than 80.

greatAssignments <- query @Assignment
    |> filterWhereGreaterThan (#grade, 80)
    |> fetch
-- SELECT * FROM assignments WHERE grade > 80

See also: filterWhereLarger, filterWhereGreaterThanOrEqualTo, filterWhereAtLeast

filterWhereLarger :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Alias for filterWhereGreaterThan. Adds a WHERE x > y condition to the query.

Example: Find assignments with grade larger than 80.

greatAssignments <- query @Assignment
    |> filterWhereLarger (#grade, 80)
    |> fetch
-- SELECT * FROM assignments WHERE grade > 80

filterWhereGreaterThanOrEqualTo :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x >= y condition to the query.

Example: Find assignments with grade at least 80.

greatAssignments <- query @Assignment
    |> filterWhereGreaterThanOrEqualTo (#grade, 80)
    |> fetch
-- SELECT * FROM assignments WHERE grade >= 80

See also: filterWhereAtLeast, filterWhereGreaterThan, filterWhereLarger

filterWhereAtLeast :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Alias for filterWhereGreaterThanOrEqualTo. Adds a WHERE x >= y condition to the query.

Example: Find assignments with grade at least 80.

greatAssignments <- query @Assignment
    |> filterWhereAtLeast (#grade, 80)
    |> fetch
-- SELECT * FROM assignments WHERE grade >= 80

filterWhereLessThan :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x < y condition to the query.

Example: Find assignments with grade less than 60.

poorAssignments <- query @Assignment
    |> filterWhereLessThan (#grade, 60)
    |> fetch
-- SELECT * FROM assignments WHERE grade < 60

See also: filterWhereSmaller, filterWhereLessThanOrEqualTo, filterWhereAtMost

filterWhereSmaller :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Alias for filterWhereLessThan. Adds a WHERE x < y condition to the query.

Example: Find assignments with grade smaller than 60.

poorAssignments <- query @Assignment
    |> filterWhereSmaller (#grade, 60)
    |> fetch
-- SELECT * FROM assignments WHERE grade < 60

filterWhereLessThanOrEqualTo :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Adds a WHERE x <= y condition to the query.

Example: Find assignments with grade at most 60.

poorAssignments <- query @Assignment
    |> filterWhereLessThanOrEqualTo (#grade, 60)
    |> fetch
-- SELECT * FROM assignments WHERE grade <= 60

See also: filterWhereAtMost, filterWhereLessThan, filterWhereSmaller

filterWhereAtMost :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, DefaultParamEncoder value, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, value) -> QueryBuilder table -> QueryBuilder table Source #

Alias for filterWhereLessThanOrEqualTo. Adds a WHERE x <= y condition to the query.

Example: Find assignments with grade at most 60.

poorAssignments <- query @Assignment
    |> filterWhereAtMost (#grade, 60)
    |> fetch
-- SELECT * FROM assignments WHERE grade <= 60

filterWhereSql :: forall (name :: Symbol) (table :: Symbol) model value. (KnownSymbol table, KnownSymbol name, HasField name model value, model ~ GetModelByTableName table, Table model) => (Proxy name, Text) -> QueryBuilder table -> QueryBuilder table Source #

Allows to add a custom raw sql where condition

If your query cannot be represented with filterWhereSql, take a look at sqlQuery.

Example: Fetching all projects created in the last 24 hours.

latestProjects <- query @Project
    |> filterWhereSql (#startedAt, "< current_timestamp - interval '1 day'")
    |> fetch
-- SELECT * FROM projects WHERE started_at < current_timestamp - interval '1 day'

Ordering

orderBy :: forall (table :: Symbol) (name :: Symbol) model value. (KnownSymbol table, KnownSymbol name, HasField name model value, model ~ GetModelByTableName table, Table model) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Alias for orderByAsc

orderByAsc :: forall (name :: Symbol) model (table :: Symbol) value. (KnownSymbol table, KnownSymbol name, HasField name model value, model ~ GetModelByTableName table, Table model) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Adds an ORDER BY .. ASC to your query.

Use orderByDesc for descending order.

Example: Fetch the 10 oldest books.

query @Book
    |> orderBy #createdAt -- >     |> limit 10
    |> fetch
-- SELECT * FROM books LIMIT 10 ORDER BY created_at ASC

orderByDesc :: forall (name :: Symbol) model (table :: Symbol) value. (KnownSymbol table, KnownSymbol name, HasField name model value, model ~ GetModelByTableName table, Table model) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Adds an ORDER BY .. DESC to your query.

Use orderBy for ascending order.

Example: Fetch the 10 newest projects (ordered by creation time).

query @Project
    |> orderByDesc #createdAt
    |> limit 10
    |> fetch
-- SELECT * FROM projects LIMIT 10 ORDER BY created_at DESC

Pagination

limit :: forall (model :: Symbol). Int -> QueryBuilder model -> QueryBuilder model Source #

Adds an LIMIT .. to your query.

Example: Fetch 10 posts

query @Post
    |> limit 10
    |> fetch
-- SELECT * FROM posts LIMIT 10

offset :: forall (model :: Symbol). Int -> QueryBuilder model -> QueryBuilder model Source #

Adds an OFFSET .. to your query. Most often used together with LIMIT...

Example: Fetch posts 10-20

query @Post
    |> limit 10
    |> offset 10
    |> fetch
-- SELECT * FROM posts LIMIT 10 OFFSET 10

Deduplication

distinct :: forall (table :: Symbol). QueryBuilder table -> QueryBuilder table Source #

Adds a DISTINCT to your query.

Use distinct to remove all duplicate rows from the result

Example: Fetch distinct books

query @Book
    |> distinct
    |> fetch
-- SELECT DISTINCT * FROM books

distinctOn :: forall (name :: Symbol) model value (table :: Symbol). (KnownSymbol table, KnownSymbol name, HasField name model value, model ~ GetModelByTableName table, Table model) => Proxy name -> QueryBuilder table -> QueryBuilder table Source #

Adds an @DISTINCT ON .. to your query.

Use distinctOn to return a single row for each distinct value provided.

Example: Fetch one book for each categoryId field

query @Book
    |> distinctOn #categoryId
    |> fetch
-- SELECT DISTINCT ON (category_id) * FROM books

Unions

queryUnion :: forall (model :: Symbol). QueryBuilder model -> QueryBuilder model -> QueryBuilder model Source #

Merges the results of two query builders by ORing their WHERE conditions.

Take a look at queryOr as well, as this might be a bit shorter.

Example: Return all pages owned by the user or owned by the users team.

let userPages = query @Page |> filterWhere (#ownerId, currentUserId)
let teamPages = query @Page |> filterWhere (#teamId, currentTeamId)
pages <- queryUnion userPages teamPages |> fetch
-- SELECT * FROM pages WHERE (owner_id = '..') OR (team_id = '..')

queryUnionList :: forall (table :: Symbol). (Table (GetModelByTableName table), KnownSymbol table, GetTableName (GetModelByTableName table) ~ table) => [QueryBuilder table] -> QueryBuilder table Source #

Like queryUnion, but applied on all the elements on the list

 action ProjectsAction = do
     let values :: [(ProjectType, Int)] = [(ProjectTypeOngoing, 3), (ProjectTypeNotStarted, 2)]

         valuePairToCondition :: (ProjectType, Int) -> QueryBuilder "projects"
         valuePairToCondition (projectType, participants) =
             query @Project
                 |> filterWhere (#projectType, projectType)
                 |> filterWhere (#participants, participants)

         theQuery = queryUnionList (map valuePairToCondition values)

     projects <- fetch theQuery
     render IndexView { .. }

queryOr :: forall (model :: Symbol). (QueryBuilder model -> QueryBuilder model) -> (QueryBuilder model -> QueryBuilder model) -> QueryBuilder model -> QueryBuilder model Source #

Adds an a OR b condition

Example: Return all pages owned by the user or public.

query @Page
    |> queryOr
        (filterWhere (#createdBy, currentUserId))
        (filterWhere (#public, True))
    |> fetch
-- SELECT * FROM pages WHERE created_by = '..' OR public = True

Operators

compileOperator :: FilterOperator -> Text Source #

Compiles a FilterOperator to its SQL representation

negateFilterOperator :: FilterOperator -> FilterOperator Source #

Returns the NOT version of an operator

>>> negateFilterOperator EqOp
NotEqOp