Safe HaskellNone

IHP.ModelSupport

Synopsis

Documentation

data ModelContext Source #

Provides the db connection and some IHP-specific db configuration

Constructors

ModelContext 

Fields

notConnectedModelContext :: ModelContext Source #

Provides a mock ModelContext to be used when a database connection is not available

type family GetModelById id :: Type where ... Source #

Equations

GetModelById (Maybe (Id' tableName)) = Maybe (GetModelByTableName tableName) 
GetModelById (Id' tableName) = GetModelByTableName tableName 

type family GetTableName model :: Symbol Source #

type family GetModelByTableName (tableName :: Symbol) :: Type Source #

class CanCreate a where Source #

Methods

create :: (?modelContext :: ModelContext) => a -> IO a Source #

createMany :: (?modelContext :: ModelContext) => [a] -> IO [a] Source #

class CanUpdate a where Source #

Methods

updateRecord :: (?modelContext :: ModelContext) => a -> IO a Source #

createRecord :: (?modelContext :: ModelContext, CanCreate model) => model -> IO model Source #

class InputValue a where Source #

Methods

inputValue :: a -> Text Source #

Instances

Instances details
InputValue Bool Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Bool -> Text Source #

InputValue Double Source # 
Instance details

Defined in IHP.ModelSupport

InputValue Float Source # 
Instance details

Defined in IHP.ModelSupport

InputValue Int Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Int -> Text Source #

InputValue Integer Source # 
Instance details

Defined in IHP.ModelSupport

InputValue () Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: () -> Text Source #

InputValue Text Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Text -> Text Source #

InputValue Day Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Day -> Text Source #

InputValue UTCTime Source # 
Instance details

Defined in IHP.ModelSupport

InputValue UUID Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: UUID -> Text Source #

InputValue value => InputValue [value] Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: [value] -> Text Source #

InputValue fieldType => InputValue (Maybe fieldType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Maybe fieldType -> Text Source #

InputValue (PrimaryKey model') => InputValue (Id' model') Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Id' model' -> Text Source #

isNew :: forall model id. (HasField "id" model id, Default id, Eq id) => model -> Bool Source #

Returns True when the record has not been saved to the database yet. Returns False otherwise.

Example: Returns False when a record has not been inserted yet.

>>> let project = newRecord @Project
>>> isNew project
False

Example: Returns True after inserting a record.

>>> project <- createRecord project
>>> isNew project
True

Example: Returns True for records which have been fetched from the database.

>>> book <- query @Book |> fetchOne
>>> isNew book
False

type family GetModelName model :: Symbol Source #

type family PrimaryKey (tableName :: Symbol) Source #

Provides the primary key type for a given table. The instances are usually declared by the generated haskell code in Generated.Types

Example: Defining the primary key for a users table

type instance PrimaryKey "users" = UUID

Example: Defining the primary key for a table with a SERIAL pk

type instance PrimaryKey "projects" = Int

getModelName :: forall model. KnownSymbol (GetModelName model) => Text Source #

Returns the model name of a given model as Text

Example:

>>> modelName @User
"User"
>>> modelName @Project
"Project"

newtype Id' table Source #

Constructors

Id (PrimaryKey table) 

Instances

Instances details
Eq (PrimaryKey table) => Eq (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: Id' table -> Id' table -> Bool #

(/=) :: Id' table -> Id' table -> Bool #

(KnownSymbol table, Data (PrimaryKey table)) => Data (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Id' table -> c (Id' table) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Id' table) #

toConstr :: Id' table -> Constr #

dataTypeOf :: Id' table -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Id' table)) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Id' table)) #

gmapT :: (forall b. Data b => b -> b) -> Id' table -> Id' table #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Id' table -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Id' table -> r #

gmapQ :: (forall d. Data d => d -> u) -> Id' table -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Id' table -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Id' table -> m (Id' table) #

Ord (PrimaryKey table) => Ord (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

compare :: Id' table -> Id' table -> Ordering #

(<) :: Id' table -> Id' table -> Bool #

(<=) :: Id' table -> Id' table -> Bool #

(>) :: Id' table -> Id' table -> Bool #

(>=) :: Id' table -> Id' table -> Bool #

max :: Id' table -> Id' table -> Id' table #

min :: Id' table -> Id' table -> Id' table #

Show (PrimaryKey model) => Show (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> Id' model -> ShowS #

show :: Id' model -> String

showList :: [Id' model] -> ShowS #

(Read (PrimaryKey model), ParsePrimaryKey (PrimaryKey model)) => IsString (Id' model) Source #

Sometimes you have a hardcoded UUID value which represents some record id. This instance allows you to write the Id like a string:

let projectId = "ca63aace-af4b-4e6c-bcfa-76ca061dbdc6" :: Id Project
Instance details

Defined in IHP.ModelSupport

Methods

fromString :: String -> Id' model #

Hashable (PrimaryKey table) => Hashable (Id' table) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

hashWithSalt :: Int -> Id' table -> Int #

hash :: Id' table -> Int #

Default (PrimaryKey model) => Default (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: Id' model #

FromField (PrimaryKey model) => FromField (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

fromField :: FieldParser (Id' model)

ToField (PrimaryKey model) => ToField (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: Id' model -> Action

ToJSON (PrimaryKey a) => ToJSON (Id' a) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toJSON :: Id' a -> Value #

toEncoding :: Id' a -> Encoding #

toJSONList :: [Id' a] -> Value #

toEncodingList :: [Id' a] -> Encoding #

Newtype (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

Associated Types

type O (Id' model)

Methods

pack :: O (Id' model) -> Id' model

unpack :: Id' model -> O (Id' model)

InputValue (PrimaryKey model') => InputValue (Id' model') Source # 
Instance details

Defined in IHP.ModelSupport

Methods

inputValue :: Id' model' -> Text Source #

ParamReader (PrimaryKey model') => ParamReader (Id' model') Source # 
Instance details

Defined in IHP.Controller.Param

(model ~ GetModelById (Id' table), value ~ Id' table, HasField "id" model value, ToField (PrimaryKey table), GetModelByTableName (GetTableName model) ~ model) => Fetchable [Id' table] model Source # 
Instance details

Defined in IHP.QueryBuilder

Associated Types

type FetchResult [Id' table] model Source #

Methods

fetch :: [Id' table] -> IO (FetchResult [Id' table] model) Source #

fetchOneOrNothing :: [Id' table] -> IO (Maybe model) Source #

fetchOne :: [Id' table] -> IO model Source #

(model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Maybe (Id' table)) model Source # 
Instance details

Defined in IHP.QueryBuilder

Associated Types

type FetchResult (Maybe (Id' table)) model Source #

Methods

fetch :: Maybe (Id' table) -> IO (FetchResult (Maybe (Id' table)) model) Source #

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

fetchOne :: Maybe (Id' table) -> IO model Source #

(model ~ GetModelById (Id' table), GetTableName model ~ table, FilterPrimaryKey table) => Fetchable (Id' table) model Source # 
Instance details

Defined in IHP.QueryBuilder

Associated Types

type FetchResult (Id' table) model Source #

Methods

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

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

fetchOne :: Id' table -> IO model Source #

(TypeError (('Text "Looks like you forgot to pass a " :<>: 'ShowType (GetModelByTableName record)) :<>: 'Text " id to this data constructor.") :: Constraint) => Eq (Id' record -> controller) Source # 
Instance details

Defined in IHP.ViewSupport

Methods

(==) :: (Id' record -> controller) -> (Id' record -> controller) -> Bool #

(/=) :: (Id' record -> controller) -> (Id' record -> controller) -> Bool #

type O (Id' model) Source # 
Instance details

Defined in IHP.ModelSupport

type O (Id' model) = PrimaryKey model
type FetchResult [Id' table] model Source # 
Instance details

Defined in IHP.QueryBuilder

type FetchResult [Id' table] model = [model]
type FetchResult (Maybe (Id' table)) model Source # 
Instance details

Defined in IHP.QueryBuilder

type FetchResult (Maybe (Id' table)) model = [model]
type FetchResult (Id' table) model Source # 
Instance details

Defined in IHP.QueryBuilder

type FetchResult (Id' table) model = model

type Id model = Id' (GetTableName model) Source #

We need to map the model to it's table name to prevent infinite recursion in the model data definition E.g. `type Project = Project' { id :: Id Project }` will not work But `type Project = Project' { id :: Id "projects" }` will

recordToInputValue :: (HasField "id" entity (Id entity), Show (PrimaryKey (GetTableName entity))) => entity -> Text Source #

class ParsePrimaryKey primaryKey where Source #

Methods

parsePrimaryKey :: Text -> Maybe primaryKey Source #

Instances

Instances details
ParsePrimaryKey Text Source # 
Instance details

Defined in IHP.ModelSupport

ParsePrimaryKey UUID Source # 
Instance details

Defined in IHP.ModelSupport

textToId :: (ParsePrimaryKey (PrimaryKey model), ConvertibleStrings text Text) => text -> Id' model Source #

Transforms a text, bytestring or string into an Id. Throws an exception if the input is invalid.

Example:

let projectIdText = "7cbc76e2-1c4f-49b6-a7d9-5015e7575a9b" :: Text
let projectId = (textToId projectIdText) :: Id Project

In case your UUID value is hardcoded, there is also an IsString instance, so you can just write it like:

let projectId = "ca63aace-af4b-4e6c-bcfa-76ca061dbdc6" :: Id Project

sqlQuery :: (?modelContext :: ModelContext) => (ToRow q, FromRow r) => Query -> q -> IO [r] Source #

Runs a raw sql query

Example:

users <- sqlQuery "SELECT id, firstname, lastname FROM users" ()

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

sqlExec :: (?modelContext :: ModelContext) => ToRow q => Query -> q -> IO Int64 Source #

Runs a sql statement (like a CREATE statement)

Example:

sqlExec "CREATE TABLE users ()" ()

withDatabaseConnection :: (?modelContext :: ModelContext) => (Connection -> IO a) -> IO a Source #

sqlQueryScalar :: (?modelContext :: ModelContext) => (ToRow q, FromField value) => Query -> q -> IO value Source #

Runs a raw sql query which results in a single scalar value such as an integer or string

Example:

usersCount <- sqlQuery "SELECT COUNT(*) FROM users"

Take a look at IHP.QueryBuilder for a typesafe approach on building simple queries.

tableName :: forall model. KnownSymbol (GetTableName model) => Text Source #

Returns the table name of a given model.

Example:

>>> tableName @User
"users"

logQuery :: (?modelContext :: ModelContext, Show query, Show parameters) => query -> parameters -> IO () Source #

deleteRecord :: forall model id. (?modelContext :: ModelContext, Show id, KnownSymbol (GetTableName model), HasField "id" model id, ToField id) => model -> IO () Source #

Runs a DELETE query for a record.

>>> let project :: Project = ...
>>> deleteRecord project
DELETE FROM projects WHERE id = '..'

Use deleteRecords if you want to delete multiple records.

deleteRecords :: forall record id. (?modelContext :: ModelContext, Show id, KnownSymbol (GetTableName record), HasField "id" record id, record ~ GetModelById id, ToField id) => [record] -> IO () Source #

Runs a DELETE query for a list of records.

>>> let projects :: [Project] = ...
>>> deleteRecords projects
DELETE FROM projects WHERE id IN (..)

deleteAll :: forall record. (?modelContext :: ModelContext, KnownSymbol (GetTableName record)) => IO () Source #

Runs a DELETE query to delete all rows in a table.

>>> deleteAll @Project
DELETE FROM projects

type family Include (name :: Symbol) model Source #

type family Include' (name :: [Symbol]) model where ... Source #

Equations

Include' '[] model = model 
Include' (x ': xs) model = Include' xs (Include x model) 

class Record model where Source #

Methods

newRecord :: model Source #

type NormalizeModel model = GetModelByTableName (GetTableName model) Source #

Helper type to deal with models where relations are included or that are only partially fetched Examples:

>>> NormalizeModel (Include "author_id" Post)
Post
>>> NormalizeModel Post
Post

ids :: HasField "id" record id => [record] -> [id] Source #

Returns the ids for a list of models

Shorthand for map (get #id) records.

>>> users <- query @User |> fetch
>>> ids users
[227fbba3-0578-4eb8-807d-b9b692c3644f, 9d7874f2-5343-429b-bcc4-8ee62a5a6895, ...] :: [Id User]

data MetaBag Source #

Constructors

MetaBag 

Fields

Instances

Instances details
Eq MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: MetaBag -> MetaBag -> Bool #

(/=) :: MetaBag -> MetaBag -> Bool #

Show MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> MetaBag -> ShowS #

show :: MetaBag -> String

showList :: [MetaBag] -> ShowS #

Default MetaBag Source # 
Instance details

Defined in IHP.ModelSupport

Methods

def :: MetaBag #

SetField "annotations" MetaBag [(Text, Text)] Source # 
Instance details

Defined in IHP.ModelSupport

Methods

setField :: [(Text, Text)] -> MetaBag -> MetaBag Source #

SetField "touchedFields" MetaBag [Text] Source # 
Instance details

Defined in IHP.ModelSupport

Methods

setField :: [Text] -> MetaBag -> MetaBag Source #

didChangeRecord :: HasField "meta" record MetaBag => record -> Bool Source #

Returns True if any fields of the record have unsaved changes

Example: Returns False for freshly fetched records

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> didChangeRecord project
False

Example: Returns True after setting a field

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> project |> set #name "New Name" |> didChangeRecord
True

didChange :: (KnownSymbol fieldName, HasField fieldName record fieldValue, HasField "meta" record MetaBag) => Proxy fieldName -> record -> Bool Source #

Returns True if the specific field of the record has unsaved changes

Example: Returns False for freshly fetched records

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> didChange #name project
False

Example: Returns True after setting a field

>>> let projectId = "227fbba3-0578-4eb8-807d-b9b692c3644f" :: Id Project
>>> project <- fetch projectId
>>> project |> set #name "New Name" |> didChange #name
True

Example: Setting a flash message after updating the profile picture

when (user |> didChange #profilePictureUrl) (setSuccessMessage "Your Profile Picture has been updated. It might take a few minutes until it shows up everywhere")

data FieldWithDefault valueType Source #

Represents fields that have a default value in an SQL schema

The Default constructor represents the default value from the schema, while the NonDefault constructor holds some other value for the field

Constructors

Default 
NonDefault valueType 

Instances

Instances details
Eq valueType => Eq (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: FieldWithDefault valueType -> FieldWithDefault valueType -> Bool #

(/=) :: FieldWithDefault valueType -> FieldWithDefault valueType -> Bool #

Show valueType => Show (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> FieldWithDefault valueType -> ShowS #

show :: FieldWithDefault valueType -> String

showList :: [FieldWithDefault valueType] -> ShowS #

ToField valueType => ToField (FieldWithDefault valueType) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: FieldWithDefault valueType -> Action

fieldWithDefault :: (KnownSymbol name, HasField name model value, HasField "meta" model MetaBag) => Proxy name -> model -> FieldWithDefault value Source #

Construct a FieldWithDefault

Use the default SQL value when the field hasn't been touched since the record was created. This information is stored in the $sel:touchedFields:MetaBag attribute of the meta field.

data FieldWithUpdate name value Source #

Represents fields that may have been updated

The NoUpdate constructor represents the existing value in the database, while the Update constructor holds some new value for the field

Constructors

NoUpdate (Proxy name) 
Update value 

Instances

Instances details
Eq value => Eq (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

(==) :: FieldWithUpdate name value -> FieldWithUpdate name value -> Bool #

(/=) :: FieldWithUpdate name value -> FieldWithUpdate name value -> Bool #

Show value => Show (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

showsPrec :: Int -> FieldWithUpdate name value -> ShowS #

show :: FieldWithUpdate name value -> String

showList :: [FieldWithUpdate name value] -> ShowS #

(KnownSymbol name, ToField value) => ToField (FieldWithUpdate name value) Source # 
Instance details

Defined in IHP.ModelSupport

Methods

toField :: FieldWithUpdate name value -> Action

fieldWithUpdate :: (KnownSymbol name, HasField name model value, HasField "meta" model MetaBag) => Proxy name -> model -> FieldWithUpdate name value Source #

Construct a FieldWithUpdate

Use the current database value when the field hasn't been touched since the record was accessed. This information is stored in the $sel:touchedFields:MetaBag attribute of the meta field.

trackTableRead :: (?modelContext :: ModelContext) => Text -> IO () Source #

withTableReadTracker :: (?modelContext :: ModelContext) => ((?modelContext :: ModelContext, ?touchedTables :: IORef (Set Text)) => IO ()) -> IO () Source #

Track all tables in SELECT queries executed within the given IO action.

You can read the touched tables by this function by accessing the variable ?touchedTables inside your given IO action.

Example:

withTableReadTracker do
    project <- query @Project |> fetchOne
    user <- query @User |> fetchOne
    
    tables <- readIORef ?touchedTables
    -- tables = Set.fromList ["projects", "users"]

Orphan instances

Default Bool Source # 
Instance details

Methods

def :: Bool #

Default Text Source # 
Instance details

Methods

def :: Text #

Default Day Source # 
Instance details

Methods

def :: Day #

Default UTCTime Source # 
Instance details

Methods

def :: UTCTime #

Default LocalTime Source # 
Instance details

Methods

def :: LocalTime #

Default Value Source # 
Instance details

Methods

def :: Value #

Default (Binary ByteString) Source # 
Instance details

Methods

def :: Binary ByteString #

(FromField value, Typeable value) => FromField [value] Source #

This instancs allows us to avoid wrapping lists with PGArray when using sql types such as INT[]

Instance details

Methods

fromField :: FieldParser [value]

ToField value => ToField [value] Source #

This instancs allows us to avoid wrapping lists with PGArray when using sql types such as INT[]

Instance details

Methods

toField :: [value] -> Action

Newtype (Binary payload) Source # 
Instance details

Associated Types

type O (Binary payload)

Methods

pack :: O (Binary payload) -> Binary payload

unpack :: Binary payload -> O (Binary payload)