opaleye 0.6.7002.0 → 0.6.7003.0
raw patch · 9 files changed
+314/−268 lines, 9 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Opaleye.Internal.Table: data Zip a
+ Opaleye: NonNullable :: Nullability
+ Opaleye: Nullable :: Nullability
+ Opaleye: data Cursor haskells
+ Opaleye: data Nullability
+ Opaleye: runSelect :: Default FromFields fields haskells => Connection -> Select fields -> IO [haskells]
+ Opaleye: runSelectExplicit :: FromFields fields haskells -> Connection -> Select fields -> IO [haskells]
+ Opaleye: runSelectFold :: Default FromFields fields haskells => Connection -> Select fields -> b -> (b -> haskells -> IO b) -> IO b
+ Opaleye: runSelectFoldExplicit :: FromFields fields haskells -> Connection -> Select fields -> b -> (b -> haskells -> IO b) -> IO b
+ Opaleye: runSelectTF :: Default FromFields (rec O) (rec H) => Connection -> Select (rec O) -> IO [rec H]
+ Opaleye: type Field a = Field_ 'NonNullable a
+ Opaleye: type FieldNullable a = Field_ 'Nullable a
+ Opaleye: type FromField = QueryRunnerColumn
+ Opaleye: type FromFields = QueryRunner
+ Opaleye.Internal.Table: newtype Zip a
+ Opaleye.Internal.Table: tableField :: TableColumn writeType sqlType => String -> TableFields writeType (Column sqlType)
+ Opaleye.Internal.Table: type TableFields = TableProperties
+ Opaleye.RunSelect: runSelectTF :: Default FromFields (rec O) (rec H) => Connection -> Select (rec O) -> IO [rec H]
+ Opaleye.Table: tableField :: TableColumn writeType sqlType => String -> TableFields writeType (Column sqlType)
+ Opaleye.Table: type TableFields = TableProperties
- Opaleye.Internal.Table: Table :: String -> (TableColumns writerColumns viewColumns) -> Table writerColumns viewColumns
+ Opaleye.Internal.Table: Table :: String -> (TableFields writerColumns viewColumns) -> Table writerColumns viewColumns
- Opaleye.Internal.Table: TableWithSchema :: String -> String -> (TableColumns writerColumns viewColumns) -> Table writerColumns viewColumns
+ Opaleye.Internal.Table: TableWithSchema :: String -> String -> (TableFields writerColumns viewColumns) -> Table writerColumns viewColumns
- Opaleye.Internal.Table: optional :: String -> TableColumns (Maybe (Column a)) (Column a)
+ Opaleye.Internal.Table: optional :: String -> TableFields (Maybe (Column a)) (Column a)
- Opaleye.Internal.Table: required :: String -> TableColumns (Column a) (Column a)
+ Opaleye.Internal.Table: required :: String -> TableFields (Column a) (Column a)
- Opaleye.Internal.Table: tableColumn :: TableColumn writeType sqlType => String -> TableColumns writeType (Column sqlType)
+ Opaleye.Internal.Table: tableColumn :: TableColumn writeType sqlType => String -> TableFields writeType (Column sqlType)
- Opaleye.Internal.Table: tableColumns :: Table writeColumns viewColumns -> TableColumns writeColumns viewColumns
+ Opaleye.Internal.Table: tableColumns :: Table writeColumns viewColumns -> TableFields writeColumns viewColumns
- Opaleye.Internal.Table: tableColumnsView :: TableColumns writeColumns viewColumns -> View viewColumns
+ Opaleye.Internal.Table: tableColumnsView :: TableFields writeColumns viewColumns -> View viewColumns
- Opaleye.Internal.Table: tableColumnsWriter :: TableColumns writeColumns viewColumns -> Writer writeColumns viewColumns
+ Opaleye.Internal.Table: tableColumnsWriter :: TableFields writeColumns viewColumns -> Writer writeColumns viewColumns
- Opaleye.Internal.Table: tableProperties :: Table writeColumns viewColumns -> TableColumns writeColumns viewColumns
+ Opaleye.Internal.Table: tableProperties :: Table writeColumns viewColumns -> TableFields writeColumns viewColumns
- Opaleye.Table: Table :: String -> (TableColumns writerColumns viewColumns) -> Table writerColumns viewColumns
+ Opaleye.Table: Table :: String -> (TableFields writerColumns viewColumns) -> Table writerColumns viewColumns
- Opaleye.Table: TableWithSchema :: String -> String -> (TableColumns writerColumns viewColumns) -> Table writerColumns viewColumns
+ Opaleye.Table: TableWithSchema :: String -> String -> (TableFields writerColumns viewColumns) -> Table writerColumns viewColumns
- Opaleye.Table: optional :: String -> TableColumns (Maybe (Column a)) (Column a)
+ Opaleye.Table: optional :: String -> TableFields (Maybe (Column a)) (Column a)
- Opaleye.Table: required :: String -> TableColumns (Column a) (Column a)
+ Opaleye.Table: required :: String -> TableFields (Column a) (Column a)
- Opaleye.Table: table :: String -> TableColumns writeFields viewFields -> Table writeFields viewFields
+ Opaleye.Table: table :: String -> TableFields writeFields viewFields -> Table writeFields viewFields
- Opaleye.Table: tableColumn :: TableColumn writeType sqlType => String -> TableColumns writeType (Column sqlType)
+ Opaleye.Table: tableColumn :: TableColumn writeType sqlType => String -> TableFields writeType (Column sqlType)
- Opaleye.Table: tableWithSchema :: String -> String -> TableColumns writeFields viewFields -> Table writeFields viewFields
+ Opaleye.Table: tableWithSchema :: String -> String -> TableFields writeFields viewFields -> Table writeFields viewFields
Files
- CHANGELOG.md +8/−0
- Doc/Tutorial/TutorialBasic.lhs +120/−120
- Doc/Tutorial/TutorialBasicMonomorphic.lhs +79/−79
- Doc/Tutorial/TutorialBasicTypeFamilies.lhs +46/−44
- opaleye.cabal +2/−2
- src/Opaleye.hs +14/−0
- src/Opaleye/Internal/Table.hs +23/−15
- src/Opaleye/RunSelect.hs +12/−0
- src/Opaleye/Table.hs +10/−8
CHANGELOG.md view
@@ -1,3 +1,11 @@+## 0.6.7003.0++* Add `tableField` as a future replacement for `tableColumn`++* Export `Opaleye.Field` and `Opaleye.RunSelect` from `Opaleye`++* Use new nomenclature in tutorials+ ## 0.6.7002.0 This is a breaking release that doesn't follow the PVP but because
Doc/Tutorial/TutorialBasic.lhs view
@@ -8,12 +8,12 @@ > > import Prelude hiding (sum) >-> import Opaleye (Column, Nullable, matchNullable, isNull,-> Table, table, tableColumn, queryTable,-> Query, QueryArr, restrict, (.==), (.<=), (.&&), (.<),+> import Opaleye (Field, FieldNullable, matchNullable, isNull,+> Table, table, tableField, selectTable,+> Select, SelectArr, restrict, (.==), (.<=), (.&&), (.<), > (.===), > (.++), ifThenElse, sqlString, aggregate, groupBy,-> count, avg, sum, leftJoin, runQuery,+> count, avg, sum, leftJoin, runSelect, > showSqlForPostgres, Unpackspec, > SqlInt4, SqlInt8, SqlText, SqlDate, SqlFloat8, SqlBool) >@@ -59,17 +59,17 @@ `Table` types will have the same type argument repeated twice. In the manipulation tutorial you can see an example of when they might differ. -> personTable :: Table (Column SqlText, Column SqlInt4, Column SqlText)-> (Column SqlText, Column SqlInt4, Column SqlText)-> personTable = table "personTable" (p3 ( tableColumn "name"-> , tableColumn "age"-> , tableColumn "address" ))+> personTable :: Table (Field SqlText, Field SqlInt4, Field SqlText)+> (Field SqlText, Field SqlInt4, Field SqlText)+> personTable = table "personTable" (p3 ( tableField "name"+> , tableField "age"+> , tableField "address" )) By default, the table `"personTable"` is looked up in PostgreSQL's default `"public"` schema. If we wanted to specify a different schema we could have used the `tableWithSchema` function instead of `table`. -To query a table we use `queryTable`.+To query a table we use `selectTable`. (Here and in a few other places in Opaleye there is some typeclass magic going on behind the scenes to reduce boilerplate. However, you@@ -79,13 +79,13 @@ because they are simpler to read and the typeclass magic is essentially invisible.) -> personQuery :: Query (Column SqlText, Column SqlInt4, Column SqlText)-> personQuery = queryTable personTable+> personSelect :: Select (Field SqlText, Field SqlInt4, Field SqlText)+> personSelect = selectTable personTable -A `Query` corresponds to an SQL SELECT that we can run. Here is the-SQL generated for `personQuery`.+A `Select` corresponds to an SQL SELECT that we can run. Here is the+SQL generated for `personSelect`. -ghci> printSql personQuery+ghci> printSql personSelect SELECT name0_1 as result1, age1_1 as result2, address2_1 as result3@@ -126,7 +126,7 @@ > data Birthday' a b = Birthday { bdName :: a, bdDay :: b } > type Birthday = Birthday' String Day-> type BirthdayColumn = Birthday' (Column SqlText) (Column SqlDate)+> type BirthdayField = Birthday' (Field SqlText) (Field SqlDate) To get user defined types to work with the typeclass magic they must have instances defined for them. The instances are derivable with@@ -141,15 +141,15 @@ Then we can use 'table' to make a table on our record type in exactly the same way as before. -> birthdayTable :: Table BirthdayColumn BirthdayColumn+> birthdayTable :: Table BirthdayField BirthdayField > birthdayTable = table "birthdayTable"-> (pBirthday Birthday { bdName = tableColumn "name"-> , bdDay = tableColumn "birthday" })+> (pBirthday Birthday { bdName = tableField "name"+> , bdDay = tableField "birthday" }) >-> birthdayQuery :: Query BirthdayColumn-> birthdayQuery = queryTable birthdayTable+> birthdaySelect :: Select BirthdayField+> birthdaySelect = selectTable birthdayTable -ghci> printSql birthdayQuery+ghci> printSql birthdaySelect SELECT name0_1 as result1, birthday1_1 as result2 FROM (SELECT *@@ -169,7 +169,7 @@ "Projection" means discarding some of the columns of our query, for example we might want to discard the "address" column of our-`personQuery`.+`personSelect`. Projection gives us our first example of using "arrow notation" to write Opaleye queries. Arrow notation is essentially a restricted@@ -177,13 +177,13 @@ computations, and do notation allows you to write monadic computations. -Here we run the `personQuery` passing in () to signify "zero+Here we run the `personSelect` passing in () to signify "zero arguments". We pattern match on the results and return only the columns we are interested in. -> nameAge :: Query (Column SqlText, Column SqlInt4)+> nameAge :: Select (Field SqlText, Field SqlInt4) > nameAge = proc () -> do-> (name, age, _) <- personQuery -< ()+> (name, age, _) <- personSelect -< () > returnA -< (name, age) ghci> printSql nameAge@@ -205,14 +205,14 @@ ======= "Product" means taking the Cartesian product of two queries. This is-simple in arrow notation. Here we take the product of `personQuery`-and `birthdayQuery`.+simple in arrow notation. Here we take the product of `personSelect`+and `birthdaySelect`. > personBirthdayProduct ::-> Query ((Column SqlText, Column SqlInt4, Column SqlText), BirthdayColumn)+> Select ((Field SqlText, Field SqlInt4, Field SqlText), BirthdayField) > personBirthdayProduct = proc () -> do-> personRow <- personQuery -< ()-> birthdayRow <- birthdayQuery -< ()+> personRow <- personSelect -< ()+> birthdayRow <- birthdaySelect -< () > > returnA -< (personRow, birthdayRow) @@ -253,12 +253,12 @@ "Restriction" means restricting the rows of the result of a query to only those where some condition holds. -We can restrict `personQuery` to the rows where the person is up to 18+We can restrict `personSelect` to the rows where the person is up to 18 years old. -> youngPeople :: Query (Column SqlText, Column SqlInt4, Column SqlText)+> youngPeople :: Select (Field SqlText, Field SqlInt4, Field SqlText) > youngPeople = proc () -> do-> row@(_, age, _) <- personQuery -< ()+> row@(_, age, _) <- personSelect -< () > restrict -< age .<= 18 > > returnA -< row@@ -286,9 +286,9 @@ We can use a variety of operators to form more complex restriction conditions. -> twentiesAtAddress :: Query (Column SqlText, Column SqlInt4, Column SqlText)+> twentiesAtAddress :: Select (Field SqlText, Field SqlInt4, Field SqlText) > twentiesAtAddress = proc () -> do-> row@(_, age, address) <- personQuery -< ()+> row@(_, age, address) <- personSelect -< () > > restrict -< (20 .<= age) .&& (age .< 30) > restrict -< address .== sqlString "1 My Street, My Town"@@ -327,10 +327,10 @@ such. > personAndBirthday ::-> Query (Column SqlText, Column SqlInt4, Column SqlText, Column SqlDate)+> Select (Field SqlText, Field SqlInt4, Field SqlText, Field SqlDate) > personAndBirthday = proc () -> do-> (name, age, address) <- personQuery -< ()-> birthday <- birthdayQuery -< ()+> (name, age, address) <- personSelect -< ()+> birthday <- birthdaySelect -< () > > restrict -< name .== bdName birthday >@@ -380,17 +380,17 @@ of each employee and the name of their boss. If their boss is recorded as NULL then that means they have no boss! -> employeeTable :: Table (Column SqlText, Column (Nullable SqlText))-> (Column SqlText, Column (Nullable SqlText))-> employeeTable = table "employeeTable" (p2 ( tableColumn "name"-> , tableColumn "boss" ))+> employeeTable :: Table (Field SqlText, FieldNullable SqlText)+> (Field SqlText, FieldNullable SqlText)+> employeeTable = table "employeeTable" (p2 ( tableField "name"+> , tableField "boss" )) We can write a query that returns as string indicating for each employee whether they have a boss. -> hasBoss :: Query (Column SqlText)+> hasBoss :: Select (Field SqlText) > hasBoss = proc () -> do-> (name, nullableBoss) <- queryTable employeeTable -< ()+> (name, nullableBoss) <- selectTable employeeTable -< () > > let aOrNo = ifThenElse (isNull nullableBoss) (sqlString "no") (sqlString "a") >@@ -419,8 +419,8 @@ returns its first argument. If not it passes the non-NULL value to the function that is the second argument. -> bossQuery :: QueryArr (Column SqlText, Column (Nullable SqlText)) (Column SqlText)-> bossQuery = proc (name, nullableBoss) -> do+> bossSelect :: SelectArr (Field SqlText, FieldNullable SqlText) (Field SqlText)+> bossSelect = proc (name, nullableBoss) -> do > returnA -< matchNullable (name .++ sqlString " has no boss") > (\boss -> sqlString "The boss of " .++ name > .++ sqlString " is " .++ boss)@@ -440,7 +440,7 @@ Then we get the following SQL. -ghci> printSql (bossQuery <<< queryTable employeeTable)+ghci> printSql (bossSelect <<< selectTable employeeTable) SELECT CASE WHEN boss1_1 IS NULL THEN (name0_1) || ' has no boss' ELSE (('The boss of ' || (name0_1)) || ' is ') || (boss1_1) END as result1@@ -469,28 +469,28 @@ twenties" and the restriction to the one's address being "1 My Street, My Town". -The types are of the form `QueryArr a ()`. This means that they read-columns of type `a` but do not return any columns. (Note: `Query` is-just a synonym for `QueryArr ()` which means that it is a `QueryArr`+The types are of the form `SelectArr a ()`. This means that they read+columns of type `a` but do not return any columns. (Note: `Select` is+just a synonym for `SelectArr ()` which means that it is a `SelectArr` that does not read any columns.) -> restrictIsTwenties :: QueryArr (Column SqlInt4) ()+> restrictIsTwenties :: SelectArr (Field SqlInt4) () > restrictIsTwenties = proc age -> do > restrict -< (20 .<= age) .&& (age .< 30) >-> restrictAddressIs1MyStreet :: QueryArr (Column SqlText) ()+> restrictAddressIs1MyStreet :: SelectArr (Field SqlText) () > restrictAddressIs1MyStreet = proc address -> do > restrict -< address .== sqlString "1 My Street, My Town" We can't generate "the SQL of" these combinators. They are not-`Query`s so they don't have any SQL! (This corresponds to the+`Select`s so they don't have any SQL! (This corresponds to the observation that in Haskell typically values can be "shown", but functions cannot be "shown".) Instead we use them to reimplement `twentiesAtAddress` in a more neatly-factored way. -> twentiesAtAddress' :: Query (Column SqlText, Column SqlInt4, Column SqlText)+> twentiesAtAddress' :: Select (Field SqlText, Field SqlInt4, Field SqlText) > twentiesAtAddress' = proc () -> do-> row@(_, age, address) <- personQuery -< ()+> row@(_, age, address) <- personSelect -< () > > restrictIsTwenties -< age > restrictAddressIs1MyStreet -< address@@ -516,12 +516,12 @@ ---------------------- We can perform a similar transformation for `personAndBirthday` by-pulling out a `QueryArr` which perform the mapping of a person's name-to their date of birth by looking up in `birthdayQuery`.+pulling out a `SelectArr` which perform the mapping of a person's name+to their date of birth by looking up in `birthdaySelect`. -> birthdayOfPerson :: QueryArr (Column SqlText) (Column SqlDate)+> birthdayOfPerson :: SelectArr (Field SqlText) (Field SqlDate) > birthdayOfPerson = proc name -> do-> birthday <- birthdayQuery -< ()+> birthday <- birthdaySelect -< () > > restrict -< name .== bdName birthday >@@ -530,9 +530,9 @@ We can then reimplement `personAndBirthday` as follows > personAndBirthday' ::-> Query (Column SqlText, Column SqlInt4, Column SqlText, Column SqlDate)+> Select (Field SqlText, Field SqlInt4, Field SqlText, Field SqlDate) > personAndBirthday' = proc () -> do-> (name, age, address) <- personQuery -< ()+> (name, age, address) <- personSelect -< () > birthday <- birthdayOfPerson -< name > > returnA -< (name, age, address, birthday)@@ -580,16 +580,16 @@ For the purposes of this example the style, color and location will be strings, but in practice they might have been a different data type. -> widgetTable :: Table (Widget (Column SqlText) (Column SqlText) (Column SqlText)-> (Column SqlInt4) (Column SqlFloat8))-> (Widget (Column SqlText) (Column SqlText) (Column SqlText)-> (Column SqlInt4) (Column SqlFloat8))+> widgetTable :: Table (Widget (Field SqlText) (Field SqlText) (Field SqlText)+> (Field SqlInt4) (Field SqlFloat8))+> (Widget (Field SqlText) (Field SqlText) (Field SqlText)+> (Field SqlInt4) (Field SqlFloat8)) > widgetTable = table "widgetTable"-> (pWidget Widget { style = tableColumn "style"-> , color = tableColumn "color"-> , location = tableColumn "location"-> , quantity = tableColumn "quantity"-> , radius = tableColumn "radius" })+> (pWidget Widget { style = tableField "style"+> , color = tableField "color"+> , location = tableField "location"+> , quantity = tableField "quantity"+> , radius = tableField "radius" }) Say we want to group by the style and color of widgets, calculating@@ -597,14 +597,14 @@ of such widgets and their average radius. `aggregateWidgets` shows us how to do this. -> aggregateWidgets :: Query (Widget (Column SqlText) (Column SqlText) (Column SqlInt8)-> (Column SqlInt4) (Column SqlFloat8))+> aggregateWidgets :: Select (Widget (Field SqlText) (Field SqlText) (Field SqlInt8)+> (Field SqlInt4) (Field SqlFloat8)) > aggregateWidgets = aggregate (pWidget Widget { style = groupBy > , color = groupBy > , location = count > , quantity = sum > , radius = avg })-> (queryTable widgetTable)+> (selectTable widgetTable) The generated SQL is @@ -644,8 +644,8 @@ uses of our Template Haskell derived code. We use the 'pWidget' "adaptor" to specify how columns are aggregated. Note that this is yet another example of avoiding a headache by keeping your datatype-fully polymorphic, because the 'count' aggregator changes a 'Column-String' into a 'Column Int64'.+fully polymorphic, because the 'count' aggregator changes a 'Field+String' into a 'Field Int64'. Outer join ==========@@ -659,15 +659,15 @@ nullability. We introduce the following type synonym for this purpose, which is just a notational convenience. -> type ColumnNullableBirthday = Birthday' (Column (Nullable SqlText))-> (Column (Nullable SqlDate))+> type FieldNullableBirthday = Birthday' (FieldNullable SqlText)+> (FieldNullable SqlDate) A left join is expressed by specifying the two tables to join and the join condition. -> personBirthdayLeftJoin :: Query ((Column SqlText, Column SqlInt4, Column SqlText),-> ColumnNullableBirthday)-> personBirthdayLeftJoin = leftJoin personQuery birthdayQuery eqName+> personBirthdayLeftJoin :: Select ((Field SqlText, Field SqlInt4, Field SqlText),+> FieldNullableBirthday)+> personBirthdayLeftJoin = leftJoin personSelect birthdaySelect eqName > where eqName ((name, _, _), birthdayRow) = name .== bdName birthdayRow The generated SQL is@@ -747,21 +747,21 @@ We could represent the integer ID in Opaleye as a `SqlInt4` -> type BadWarehouseColumn = Warehouse' (Column SqlInt4)-> (Column SqlText)-> (Column SqlInt4)+> type BadWarehouseField = Warehouse' (Field SqlInt4)+> (Field SqlText)+> (Field SqlInt4) >-> badWarehouseTable :: Table BadWarehouseColumn BadWarehouseColumn+> badWarehouseTable :: Table BadWarehouseField BadWarehouseField > badWarehouseTable = table "warehouse_table"-> (pWarehouse Warehouse { wId = tableColumn "id"-> , wLocation = tableColumn "location"-> , wNumGoods = tableColumn "num_goods" })+> (pWarehouse Warehouse { wId = tableField "id"+> , wLocation = tableField "location"+> , wNumGoods = tableField "num_goods" }) but that would expose us to the following sorts of errors, where we can meaninglessly relate the warehouse ID with the quantity of goods it holds. -> badComparison :: BadWarehouseColumn -> Column SqlBool+> badComparison :: BadWarehouseField -> Field SqlBool > badComparison w = wId w .== wNumGoods w On the other hand we can make a newtype for the warehouse ID@@ -769,30 +769,30 @@ > newtype WarehouseId' a = WarehouseId a > $(makeAdaptorAndInstance "pWarehouseId" ''WarehouseId') >-> type WarehouseIdColumn = WarehouseId' (Column SqlInt4)+> type WarehouseIdField = WarehouseId' (Field SqlInt4) >-> type GoodWarehouseColumn = Warehouse' WarehouseIdColumn-> (Column SqlText)-> (Column SqlInt4)+> type GoodWarehouseField = Warehouse' WarehouseIdField+> (Field SqlText)+> (Field SqlInt4) >-> goodWarehouseTable :: Table GoodWarehouseColumn GoodWarehouseColumn+> goodWarehouseTable :: Table GoodWarehouseField GoodWarehouseField > goodWarehouseTable = table "warehouse_table"-> (pWarehouse Warehouse { wId = pWarehouseId (WarehouseId (tableColumn "id"))-> , wLocation = tableColumn "location"-> , wNumGoods = tableColumn "num_goods" })+> (pWarehouse Warehouse { wId = pWarehouseId (WarehouseId (tableField "id"))+> , wLocation = tableField "location"+> , wNumGoods = tableField "num_goods" }) Now the comparison will not pass the type checker -> -- forbiddenComparison :: GoodWarehouseColumn -> Column SqlBool+> -- forbiddenComparison :: GoodWarehouseField -> Field SqlBool > -- forbiddenComparison w = wId w .== wNumGoods w > ---> -- => Couldn't match type `WarehouseId' (Column SqlInt4)' with `Column SqlInt4'+> -- => Couldn't match type `WarehouseId' (Field SqlInt4)' with `Field SqlInt4' -but we can compare two `WarehouseIdColumn`s.+but we can compare two `WarehouseIdField`s. -> permittedComparison :: GoodWarehouseColumn-> -> GoodWarehouseColumn-> -> Column SqlBool+> permittedComparison :: GoodWarehouseField+> -> GoodWarehouseField+> -> Field SqlBool > permittedComparison w1 w2 = wId w1 .=== wId w2 (Currently we use `.===`, a more polymorphic version of `.==`, but@@ -803,47 +803,47 @@ Opaleye provides simple facilities for running queries on Postgres.-`runQuery` is a typeclass polymorphic function that effectively has+`runSelect` is a typeclass polymorphic function that effectively has the following type -> -- runQuery :: Database.PostgreSQL.Simple.Connection-> -- -> Query columns -> IO [haskells]+> -- runSelect :: Database.PostgreSQL.Simple.Connection+> -- -> Select columns -> IO [haskells] It converts a "record" of Opaleye columns to a list of "records" of Haskell values. Like `leftJoin` this particular formulation uses typeclasses so please put type signatures on everything in sight to minimize the number of confusing error messages! -For example, for the 'twentiesAtAddress' query `runQuery` would have+For example, for the 'twentiesAtAddress' query `runSelect` would have the following type: -> runTwentiesQuery :: PGS.Connection-> -> Query (Column SqlText, Column SqlInt4, Column SqlText)+> runTwentiesSelect :: PGS.Connection+> -> Select (Field SqlText, Field SqlInt4, Field SqlText) > -> IO [(String, Int, String)]-> runTwentiesQuery = runQuery+> runTwentiesSelect = runSelect Note that nullable columns are indicated with the Nullable type constructor, and these are converted to Maybe when executed. If we have a table with a nullable column then Nullable columns turn into-Maybes. We could run the query `queryTable employeeTable` like this.+Maybes. We could run the query `selectTable employeeTable` like this. -> runEmployeesQuery :: PGS.Connection-> -> Query (Column SqlText, Column (Nullable SqlText))+> runEmployeesSelect :: PGS.Connection+> -> Select (Field SqlText, FieldNullable SqlText) > -> IO [(String, Maybe String)]-> runEmployeesQuery = runQuery+> runEmployeesSelect = runSelect Newtypes are taken care of automatically by the typeclass instance that was generated by `makeAdaptorAndInstance`. A `WarehouseId'-(Column SqlInt4)` becomes a `WarehouseId' Int` when the query is run.-We could run the query `queryTable goodWarehouseTable` like this.+(Field SqlInt4)` becomes a `WarehouseId' Int` when the query is run.+We could run the query `selectTable goodWarehouseTable` like this. > type WarehouseId = WarehouseId' Int > type GoodWarehouse = Warehouse' WarehouseId String Int >-> runWarehouseQuery :: PGS.Connection-> -> Query GoodWarehouseColumn+> runWarehouseSelect :: PGS.Connection+> -> Select GoodWarehouseField > -> IO [GoodWarehouse]-> runWarehouseQuery = runQuery+> runWarehouseSelect = runSelect Conclusion@@ -856,5 +856,5 @@ This is a little utility function to help with printing generated SQL. -> printSql :: Default Unpackspec a a => Query a -> IO ()+> printSql :: Default Unpackspec a a => Select a -> IO () > printSql = putStrLn . maybe "Empty query" id . showSqlForPostgres
Doc/Tutorial/TutorialBasicMonomorphic.lhs view
@@ -6,12 +6,12 @@ > > import Prelude hiding (sum) >-> import Opaleye (Column, Nullable,-> Table, table, queryTable,-> tableColumn,-> Query, (.==),+> import Opaleye (Field, FieldNullable,+> Table, table, selectTable,+> tableField,+> Select, (.==), > aggregate, groupBy,-> count, avg, sum, leftJoin, runQuery,+> count, avg, sum, leftJoin, runSelect, > showSqlForPostgres, Unpackspec, > SqlInt4, SqlInt8, SqlText, SqlDate, SqlFloat8) >@@ -61,23 +61,23 @@ `Table` types will have the same type argument repeated twice. In the manipulation tutorial you can see an example of when they might differ. -> personTable :: Table (Column SqlText, Column SqlInt4, Column SqlText)-> (Column SqlText, Column SqlInt4, Column SqlText)-> personTable = table "personTable" (p3 ( tableColumn "name"-> , tableColumn "age"-> , tableColumn "address" ))+> personTable :: Table (Field SqlText, Field SqlInt4, Field SqlText)+> (Field SqlText, Field SqlInt4, Field SqlText)+> personTable = table "personTable" (p3 ( tableField "name"+> , tableField "age"+> , tableField "address" )) -> personTable' :: Table (Column SqlText, Column SqlInt4, Column SqlText)-> (Column SqlText, Column SqlInt4, Column SqlText)-> personTable' = table "personTable" (p3 ( tableColumn "name"-> , tableColumn "age"-> , tableColumn "address" ))+> personTable' :: Table (Field SqlText, Field SqlInt4, Field SqlText)+> (Field SqlText, Field SqlInt4, Field SqlText)+> personTable' = table "personTable" (p3 ( tableField "name"+> , tableField "age"+> , tableField "address" )) By default, the table `"personTable"` is looked up in PostgreSQL's default `"public"` schema. If we wanted to specify a different schema we could have used the `tableWithSchema` constructor instead of `table`. -To query a table we use `queryTable`.+To query a table we use `selectTable`. (Here and in a few other places in Opaleye there is some typeclass magic going on behind the scenes to reduce boilerplate. However, you@@ -87,13 +87,13 @@ because they are simpler to read and the typeclass magic is essentially invisible.) -> personQuery :: Query (Column SqlText, Column SqlInt4, Column SqlText)-> personQuery = queryTable personTable+> personSelect :: Select (Field SqlText, Field SqlInt4, Field SqlText)+> personSelect = selectTable personTable -A `Query` corresponds to an SQL SELECT that we can run. Here is the-SQL generated for `personQuery`.+A `Select` corresponds to an SQL SELECT that we can run. Here is the+SQL generated for `personSelect`. -ghci> printSql personQuery+ghci> printSql personSelect SELECT name0_1 as result1, age1_1 as result2, address2_1 as result3@@ -132,22 +132,22 @@ mean that you have to define more datatypes and more instances for them. -> data BirthdayColumn = BirthdayColumn { bdNameColumn :: Column SqlText-> , bdDayColumn :: Column SqlDate }+> data BirthdayField = BirthdayField { bdNameField :: Field SqlText+> , bdDayField :: Field SqlDate } > > data Birthday = Birthday { bdName :: String, bdDay :: Day } >-> birthdayColumnDef ::-> (Applicative (p BirthdayColumn),+> birthdayFieldDef ::+> (Applicative (p BirthdayField), > P.Profunctor p,-> Default p (Column SqlText) (Column SqlText),-> Default p (Column SqlDate) (Column SqlDate)) =>-> p BirthdayColumn BirthdayColumn-> birthdayColumnDef = BirthdayColumn <$> P.lmap bdNameColumn D.def-> <*> P.lmap bdDayColumn D.def+> Default p (Field SqlText) (Field SqlText),+> Default p (Field SqlDate) (Field SqlDate)) =>+> p BirthdayField BirthdayField+> birthdayFieldDef = BirthdayField <$> P.lmap bdNameField D.def+> <*> P.lmap bdDayField D.def >-> instance Default Unpackspec BirthdayColumn BirthdayColumn where-> def = birthdayColumnDef+> instance Default Unpackspec BirthdayField BirthdayField where+> def = birthdayFieldDef Naturally this is all derivable using `Generic` or Template Haskell, but no one's bothered to implement that yet. Would you like to?@@ -155,16 +155,16 @@ Then we can use 'table' to make a table on our record type in exactly the same way as before. -> birthdayTable :: Table BirthdayColumn BirthdayColumn+> birthdayTable :: Table BirthdayField BirthdayField > birthdayTable = > table "birthdayTable"-> (BirthdayColumn <$> P.lmap bdNameColumn (tableColumn "name")-> <*> P.lmap bdDayColumn (tableColumn "birthday"))+> (BirthdayField <$> P.lmap bdNameField (tableField "name")+> <*> P.lmap bdDayField (tableField "birthday")) >-> birthdayQuery :: Query BirthdayColumn-> birthdayQuery = queryTable birthdayTable+> birthdaySelect :: Select BirthdayField+> birthdaySelect = selectTable birthdayTable -ghci> printSql birthdayQuery+ghci> printSql birthdaySelect SELECT name0_1 as result1, birthday1_1 as result2 FROM (SELECT *@@ -192,15 +192,15 @@ style, color, location, quantity and radius of widgets. We can model this information with the following datatype. -> data WidgetColumn = WidgetColumn { style :: Column SqlText-> , color :: Column SqlText-> , location :: Column SqlText-> , quantity :: Column SqlInt4-> , radius :: Column SqlFloat8+> data WidgetField = WidgetField { style :: Field SqlText+> , color :: Field SqlText+> , location :: Field SqlText+> , quantity :: Field SqlInt4+> , radius :: Field SqlFloat8 > } >-> instance Default Unpackspec WidgetColumn WidgetColumn where-> def = WidgetColumn <$> P.lmap style D.def+> instance Default Unpackspec WidgetField WidgetField where+> def = WidgetField <$> P.lmap style D.def > <*> P.lmap color D.def > <*> P.lmap location D.def > <*> P.lmap quantity D.def@@ -209,13 +209,13 @@ For the purposes of this example the style, color and location will be strings, but in practice they might have been a different data type. -> widgetTable :: Table WidgetColumn WidgetColumn+> widgetTable :: Table WidgetField WidgetField > widgetTable = table "widgetTable"-> (WidgetColumn <$> P.lmap style (tableColumn "style")-> <*> P.lmap color (tableColumn "color")-> <*> P.lmap location (tableColumn "location")-> <*> P.lmap quantity (tableColumn "quantity")-> <*> P.lmap radius (tableColumn "radius"))+> (WidgetField <$> P.lmap style (tableField "style")+> <*> P.lmap color (tableField "color")+> <*> P.lmap location (tableField "location")+> <*> P.lmap quantity (tableField "quantity")+> <*> P.lmap radius (tableField "radius")) Say we want to group by the style and color of widgets, calculating@@ -223,14 +223,14 @@ of such widgets and their average radius. `aggregateWidgets` shows us how to do this. -> aggregateWidgets :: Query (Column SqlText, Column SqlText, Column SqlInt8,-> Column SqlInt4, Column SqlFloat8)+> aggregateWidgets :: Select (Field SqlText, Field SqlText, Field SqlInt8,+> Field SqlInt4, Field SqlFloat8) > aggregateWidgets = aggregate ((,,,,) <$> P.lmap style groupBy > <*> P.lmap color groupBy > <*> P.lmap location count > <*> P.lmap quantity sum > <*> P.lmap radius avg)-> (queryTable widgetTable)+> (selectTable widgetTable) The generated SQL is @@ -270,8 +270,8 @@ uses of our Template Haskell derived code. We use the 'pWidget' "adaptor" to specify how columns are aggregated. Note that this is yet another example of avoiding a headache by keeping your datatype-fully polymorphic, because the 'count' aggregator changes a 'Column-String' into a 'Column Int64'.+fully polymorphic, because the 'count' aggregator changes a 'Field+String' into a 'Field Int64'. Outer join ==========@@ -285,17 +285,17 @@ nullability. We introduce the following type synonym for this purpose, which is just a notational convenience. -> data BirthdayColumnNullable =-> BirthdayColumnNullable { bdNameColumnNullable :: Column (Nullable SqlText)-> , bdDayColumnNullable :: Column (Nullable SqlDate) }+> data BirthdayFieldNullable =+> BirthdayFieldNullable { bdNameFieldNullable :: FieldNullable SqlText+> , bdDayFieldNullable :: FieldNullable SqlDate } >-> instance Default O.Unpackspec BirthdayColumnNullable BirthdayColumnNullable where-> def = BirthdayColumnNullable <$> P.lmap bdNameColumnNullable D.def-> <*> P.lmap bdDayColumnNullable D.def+> instance Default O.Unpackspec BirthdayFieldNullable BirthdayFieldNullable where+> def = BirthdayFieldNullable <$> P.lmap bdNameFieldNullable D.def+> <*> P.lmap bdDayFieldNullable D.def >-> instance Default Opaleye.Internal.Join.NullMaker BirthdayColumn BirthdayColumnNullable where-> def = BirthdayColumnNullable <$> P.lmap bdNameColumn D.def-> <*> P.lmap bdDayColumn D.def+> instance Default Opaleye.Internal.Join.NullMaker BirthdayField BirthdayFieldNullable where+> def = BirthdayFieldNullable <$> P.lmap bdNameField D.def+> <*> P.lmap bdDayField D.def Again, this is all derivable using `Generic` or Template Haskell, if someone would take the time to implement it.@@ -303,11 +303,11 @@ A left join is expressed by specifying the two tables to join and the join condition. -> personBirthdayLeftJoin :: Query ((Column SqlText, Column SqlInt4, Column SqlText),-> BirthdayColumnNullable)-> personBirthdayLeftJoin = leftJoin personQuery birthdayQuery eqName+> personBirthdayLeftJoin :: Select ((Field SqlText, Field SqlInt4, Field SqlText),+> BirthdayFieldNullable)+> personBirthdayLeftJoin = leftJoin personSelect birthdaySelect eqName > where eqName ((name, _, _), birthdayRow) =-> name .== bdNameColumn birthdayRow+> name .== bdNameField birthdayRow The generated SQL is @@ -371,25 +371,25 @@ Opaleye provides simple facilities for running queries on Postgres.-`runQuery` is a typeclass polymorphic function that effectively has+`runSelect` is a typeclass polymorphic function that effectively has the following type -> -- runQuery :: Database.PostgreSQL.Simple.Connection-> -- -> Query columns -> IO [haskells]+> -- runSelect :: Database.PostgreSQL.Simple.Connection+> -- -> Select fields -> IO [haskells] It converts a "record" of Opaleye columns to a list of "records" of Haskell values. Like `leftJoin` this particular formulation uses typeclasses so please put type signatures on everything in sight to minimize the number of confusing error messages! -> instance Default O.QueryRunner BirthdayColumn Birthday where-> def = Birthday <$> P.lmap bdNameColumn D.def-> <*> P.lmap bdDayColumn D.def+> instance Default O.FromFields BirthdayField Birthday where+> def = Birthday <$> P.lmap bdNameField D.def+> <*> P.lmap bdDayField D.def >-> runBirthdayQuery :: PGS.Connection-> -> Query BirthdayColumn+> runBirthdaySelect :: PGS.Connection+> -> Select BirthdayField > -> IO [Birthday]-> runBirthdayQuery = runQuery+> runBirthdaySelect = runSelect Again, this is derivable using `Generic` or Template Haskell, if someone would take the time to implement it.@@ -404,5 +404,5 @@ This is a little utility function to help with printing generated SQL. -> printSql :: Default Unpackspec a a => Query a -> IO ()+> printSql :: Default Unpackspec a a => Select a -> IO () > printSql = putStrLn . maybe "Empty query" id . showSqlForPostgres
Doc/Tutorial/TutorialBasicTypeFamilies.lhs view
@@ -14,10 +14,10 @@ > > import Prelude hiding (sum) >-> import Opaleye (Column,-> Table, table, tableColumn, queryTable,-> Query, (.==), aggregate, groupBy,-> count, avg, sum, leftJoin, runQuery,+> import Opaleye (Field,+> Table, table, tableField, selectTable,+> Select, (.==), aggregate, groupBy,+> count, avg, sum, leftJoin, runSelect, runSelectTF, > showSqlForPostgres, Unpackspec, > SqlInt4, SqlInt8, SqlText, SqlDate, SqlFloat8) >@@ -67,17 +67,17 @@ we can read from the table. In this case all columns are required, so the write and read types will be the same. -> personTable :: Table (Column SqlText, Column SqlInt4, Column SqlText)-> (Column SqlText, Column SqlInt4, Column SqlText)-> personTable = table "personTable" (p3 ( tableColumn "name"-> , tableColumn "age"-> , tableColumn "address" ))+> personTable :: Table (Field SqlText, Field SqlInt4, Field SqlText)+> (Field SqlText, Field SqlInt4, Field SqlText)+> personTable = table "personTable" (p3 ( tableField "name"+> , tableField "age"+> , tableField "address" )) By default, the table `"personTable"` is looked up in PostgreSQL's default `"public"` schema. If we wanted to specify a different schema we could have used the `tableWithSchema` function instead of `table`. -To query a table we use `queryTable`.+To query a table we use `selectTable`. (Here and in a few other places in Opaleye there is some typeclass magic going on behind the scenes to reduce boilerplate. However, you@@ -87,15 +87,15 @@ because they are simpler to read and the typeclass magic is essentially invisible.) -> personQuery :: Query (Column SqlText, Column SqlInt4, Column SqlText)-> personQuery = queryTable personTable+> personSelect :: Select (Field SqlText, Field SqlInt4, Field SqlText)+> personSelect = selectTable personTable -A `Query` corresponds to an SQL SELECT that we can run. Here is the-SQL generated for `personQuery`. (`printSQL` is just a convenient+A `Select` corresponds to an SQL SELECT that we can run. Here is the+SQL generated for `personSelect`. (`printSQL` is just a convenient utility function for the purposes of this example file. See below for its definition.) - ghci> printSql personQuery+ ghci> printSql personSelect SELECT name0_1 as result1, age1_1 as result2, address2_1 as result3@@ -131,10 +131,6 @@ using type families that reduces boiler plate and has always been compatible with Opaleye! -> -- Cryptic remark: If we were willing to only support 7.8 and up we-> -- could even have a symbol field containing the table name and use-> -- https://hackage.haskell.org/package/base-4.8.2.0/docs/GHC-TypeLits.html#v:symbolVal-> > data Birthday f = Birthday { bdName :: TableField f String SqlText NN Req > , bdDay :: TableField f Day SqlDate NN Req > }@@ -164,14 +160,14 @@ > birthdayTable :: Table (Birthday W) (Birthday O) > birthdayTable = table "birthdayTable" $ pBirthday $ Birthday {-> bdName = tableColumn "name"-> , bdDay = tableColumn "birthday"+> bdName = tableField "name"+> , bdDay = tableField "birthday" > } >-> birthdayQuery :: Query (Birthday O)-> birthdayQuery = queryTable birthdayTable+> birthdaySelect :: Select (Birthday O)+> birthdaySelect = selectTable birthdayTable - ghci> printSql birthdayQuery+ ghci> printSql birthdaySelect SELECT name0_1 as result1, birthday1_1 as result2 FROM (SELECT *@@ -235,11 +231,11 @@ > widgetTable :: Table (Widget W) (Widget O) > widgetTable = table "widgetTable" $ pWidget $ Widget {-> style = tableColumn "style"-> , color = tableColumn "color"-> , location = tableColumn "location"-> , quantity = tableColumn "quantity"-> , radius = tableColumn "radius"+> style = tableField "style"+> , color = tableField "color"+> , location = tableField "location"+> , quantity = tableField "quantity"+> , radius = tableField "radius" > } Say we want to group by the style and color of widgets, calculating@@ -247,14 +243,14 @@ of such widgets and their average radius. `aggregateWidgets` shows us how to do this. -> aggregateWidgets :: Query (Column SqlText, Column SqlText, Column SqlInt8,-> Column SqlInt4, Column SqlFloat8)+> aggregateWidgets :: Select (Field SqlText, Field SqlText, Field SqlInt8,+> Field SqlInt4, Field SqlFloat8) > aggregateWidgets = aggregate ((,,,,) <$> P.lmap style groupBy > <*> P.lmap color groupBy > <*> P.lmap location count > <*> P.lmap quantity sum > <*> P.lmap radius avg)-> (queryTable widgetTable)+> (selectTable widgetTable) The generated SQL is @@ -301,9 +297,9 @@ outer joins). An outer join is expressed by specifying the two tables to join and the join condition. -> personBirthdayLeftJoin :: Query ((Column SqlText, Column SqlInt4, Column SqlText),+> personBirthdayLeftJoin :: Select ((Field SqlText, Field SqlInt4, Field SqlText), > Birthday Nulls)-> personBirthdayLeftJoin = leftJoin personQuery birthdayQuery eqName+> personBirthdayLeftJoin = leftJoin personSelect birthdaySelect eqName > where eqName ((name, _, _), birthdayRow) = name .== bdName birthdayRow The generated SQL is@@ -356,10 +352,10 @@ > typeInferred = > O.fullJoinInferrable (O.fullJoinInferrable-> birthdayQuery-> (queryTable widgetTable)+> birthdaySelect+> (selectTable widgetTable) > (const (O.pgBool True)))-> birthdayQuery+> birthdaySelect > (const (O.pgBool True)) Running queries on Postgres@@ -367,22 +363,28 @@ Opaleye provides simple facilities for running queries on Postgres.-`runQuery` is a typeclass polymorphic function that effectively has+`runSelect` is a typeclass polymorphic function that effectively has the following type -> -- runQuery :: Database.PostgreSQL.Simple.Connection-> -- -> Query columns -> IO [haskells]+> -- runSelect :: Database.PostgreSQL.Simple.Connection+> -- -> Select columns -> IO [haskells] It converts a "record" of Opaleye columns to a list of "records" of Haskell values. Like `leftJoin` this particular formulation uses typeclasses so please put type signatures on everything in sight to minimize the number of confusing error messages! -> runBirthdayQuery :: PGS.Connection-> -> Query (Birthday O)+> runBirthdaySelect :: PGS.Connection+> -> Select (Birthday O) > -> IO [Birthday H]-> runBirthdayQuery = runQuery+> runBirthdaySelect = runSelect +The type of selects can be inferred if you use the `runSelectTF`+function.++> -- printNames :: PGS.Connection -> Select (Birthday O) -> IO ()+> printNames conn select = mapM_ (print . bdName) =<< runSelectTF conn select+ Conclusion ========== @@ -393,5 +395,5 @@ This is a little utility function to help with printing generated SQL. -> printSql :: Default Unpackspec a a => Query a -> IO ()+> printSql :: Default Unpackspec a a => Select a -> IO () > printSql = putStrLn . maybe "Empty query" id . showSqlForPostgres
opaleye.cabal view
@@ -1,6 +1,6 @@ name: opaleye copyright: Copyright (c) 2014-2018 Purely Agile Limited-version: 0.6.7002.0+version: 0.6.7003.0 synopsis: An SQL-generating DSL targeting PostgreSQL description: An SQL-generating DSL targeting PostgreSQL. Allows Postgres queries to be written within Haskell in a@@ -99,7 +99,7 @@ Opaleye.Internal.HaskellDB.Sql.Default, Opaleye.Internal.HaskellDB.Sql.Generate, Opaleye.Internal.HaskellDB.Sql.Print- ghc-options: -Wall+ ghc-options: -Wall -Wcompat test-suite test default-language: Haskell2010
src/Opaleye.hs view
@@ -18,6 +18,7 @@ , module Opaleye.Column , module Opaleye.Constant , module Opaleye.Distinct+ , module Opaleye.Field , module Opaleye.FunctionalJoin , module Opaleye.Join , module Opaleye.Label@@ -27,6 +28,7 @@ , module Opaleye.PGTypes , module Opaleye.QueryArr , module Opaleye.RunQuery+ , module Opaleye.RunSelect , module Opaleye.Sql , module Opaleye.Select , module Opaleye.SqlTypes@@ -39,6 +41,13 @@ import Opaleye.Column import Opaleye.Constant import Opaleye.Distinct+import Opaleye.Field+ hiding (null,+ isNull,+ matchNullable,+ fromNullable,+ toNullable,+ maybeToNullable) import Opaleye.FunctionalJoin import Opaleye.Join import Opaleye.Label@@ -48,6 +57,11 @@ import Opaleye.PGTypes import Opaleye.QueryArr import Opaleye.RunQuery+import Opaleye.RunSelect+ hiding (foldForward,+ closeCursor,+ declareCursor,+ declareCursorExplicit) import Opaleye.Select import Opaleye.Sql import Opaleye.SqlTypes
src/Opaleye/Internal/Table.hs view
@@ -52,10 +52,10 @@ -- The constructors of Table are internal only and will be -- deprecated in version 0.7. data Table writerColumns viewColumns- = Table String (TableColumns writerColumns viewColumns)+ = Table String (TableFields writerColumns viewColumns) -- ^ For unqualified table names. Do not use the constructor. It -- is internal and will be deprecated in version 0.7.- | TableWithSchema String String (TableColumns writerColumns viewColumns)+ | TableWithSchema String String (TableFields writerColumns viewColumns) -- ^ Schema name, table name, table properties. Do not use the -- constructor. It is internal and will be deprecated in version 0.7. @@ -63,29 +63,33 @@ tableIdentifier (Table t _) = PQ.TableIdentifier Nothing t tableIdentifier (TableWithSchema s t _) = PQ.TableIdentifier (Just s) t -tableColumns :: Table writeColumns viewColumns -> TableColumns writeColumns viewColumns+tableColumns :: Table writeColumns viewColumns -> TableFields writeColumns viewColumns tableColumns (Table _ p) = p tableColumns (TableWithSchema _ _ p) = p -- | Use 'tableColumns' instead. Will be deprecated soon.-tableProperties :: Table writeColumns viewColumns -> TableColumns writeColumns viewColumns+tableProperties :: Table writeColumns viewColumns -> TableFields writeColumns viewColumns tableProperties = tableColumns --- | Use 'TableColumns' instead. 'TableProperties' will be deprecated+-- | Use 'TableFields' instead. 'TableProperties' will be deprecated -- in version 0.7. data TableProperties writeColumns viewColumns = TableProperties { tablePropertiesWriter :: Writer writeColumns viewColumns , tablePropertiesView :: View viewColumns } --- | The new name for 'TableColumns' which will replace--- 'TableColumn' in version 0.7.+-- | Use 'TableFields' instead. 'TableColumns' will be deprecated in+-- version 0.7. type TableColumns = TableProperties -tableColumnsWriter :: TableColumns writeColumns viewColumns+-- | The new name for 'TableColumns' and 'TableProperties' which will+-- replace them in version 0.7.+type TableFields = TableProperties++tableColumnsWriter :: TableFields writeColumns viewColumns -> Writer writeColumns viewColumns tableColumnsWriter = tablePropertiesWriter -tableColumnsView :: TableColumns writeColumns viewColumns+tableColumnsView :: TableFields writeColumns viewColumns -> View viewColumns tableColumnsView = tablePropertiesView @@ -111,14 +115,14 @@ -- | 'required' is for columns which are not 'optional'. You must -- provide them on writes.-required :: String -> TableColumns (Column a) (Column a)+required :: String -> TableFields (Column a) (Column a) required columnName = TableProperties (requiredW columnName) (View (Column (HPQ.BaseTableAttrExpr columnName))) -- | 'optional' is for columns that you can omit on writes, such as -- columns which have defaults or which are SERIAL.-optional :: String -> TableColumns (Maybe (Column a)) (Column a)+optional :: String -> TableFields (Maybe (Column a)) (Column a) optional columnName = TableProperties (optionalW columnName) (View (Column (HPQ.BaseTableAttrExpr columnName)))@@ -128,7 +132,7 @@ -- the write type. It's generally more convenient to use this -- than 'required' or 'optional' but you do have to provide a type -- signature instead.- tableColumn :: String -> TableColumns writeType (Column sqlType)+ tableColumn :: String -> TableFields writeType (Column sqlType) instance TableColumn (Column a) a where tableColumn = required@@ -136,6 +140,10 @@ instance TableColumn (Maybe (Column a)) a where tableColumn = optional +tableField :: TableColumn writeType sqlType+ => String -> TableFields writeType (Column sqlType)+tableField = tableColumn+ queryTable :: U.Unpackspec viewColumns columns -> Table writeColumns viewColumns -> Tag.Tag@@ -177,15 +185,15 @@ where (outColumns, ()) = f extract columns extract (pes, s) = ((Zip (fmap return pes), [s]), ()) -data Zip a = Zip { unZip :: NEL.NonEmpty [a] }+newtype Zip a = Zip { unZip :: NEL.NonEmpty [a] } instance Semigroup (Zip a) where- (<>) = mappend+ Zip xs <> Zip ys = Zip (NEL.zipWith (++) xs ys) instance Monoid (Zip a) where mempty = Zip mempty' where mempty' = [] `NEL.cons` mempty'- Zip xs `mappend` Zip ys = Zip (NEL.zipWith (++) xs ys)+ mappend = (<>) requiredW :: String -> Writer (Column a) (Column a) requiredW columnName =
src/Opaleye/RunSelect.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeFamilies #-} module Opaleye.RunSelect@@ -18,6 +19,7 @@ import qualified Opaleye.Select as S import qualified Opaleye.RunQuery as RQ import qualified Opaleye.Sql as S+import qualified Opaleye.TypeFamilies as TF import Opaleye.Internal.RunQuery (FromFields) import qualified Opaleye.Internal.RunQuery as IRQ import qualified Opaleye.Internal.QueryArr as Q@@ -51,6 +53,16 @@ -- ^ -> IO [haskells] runSelect = RQ.runQuery++-- | 'runSelectTF' has better type inference than 'runSelect' but only+-- works with "higher-kinded data" types.+runSelectTF :: D.Default FromFields (rec TF.O) (rec TF.H)+ => PGS.Connection+ -- ^+ -> S.Select (rec TF.O)+ -- ^+ -> IO [rec TF.H]+runSelectTF = RQ.runQuery -- | @runSelectFold@ streams the results of a query incrementally and consumes -- the results with a left fold.
src/Opaleye/Table.hs view
@@ -12,7 +12,7 @@ 'required' and gives rise to a @- TableColumns (Column SqlInt4) (Column SqlInt4)+ TableFields (Column SqlInt4) (Column SqlInt4) @ The leftmost argument is the type of writes. When you insert or@@ -23,7 +23,7 @@ to a @- TableColumns (Column (Nullable SqlInt4)) (Column (Nullable SqlInt4))+ TableFields (Column (Nullable SqlInt4)) (Column (Nullable SqlInt4)) @ When you insert or update into this column you must give it a @Column@@ -35,7 +35,7 @@ rise to a @- TableColumns (Maybe (Column SqlInt4)) (Column SqlInt4)+ TableFields (Maybe (Column SqlInt4)) (Column SqlInt4) @ Optional columns are those that can be omitted on writes, such as@@ -49,7 +49,7 @@ rise to a @- TableColumns (Maybe (Column (Nullable SqlInt4))) (Column (Nullable SqlInt4))+ TableFields (Maybe (Column (Nullable SqlInt4))) (Column (Nullable SqlInt4)) @ Optional columns are those that can be omitted on writes, such as@@ -66,12 +66,14 @@ tableWithSchema, T.Table, T.tableColumn,+ T.tableField, T.optional, T.required, -- * Querying tables selectTable, -- * Other- TableColumns,+ T.TableColumns,+ TableFields, -- * Deprecated View, Writer,@@ -82,7 +84,7 @@ import qualified Opaleye.Internal.QueryArr as Q import qualified Opaleye.Internal.Table as T import Opaleye.Internal.Table (View, Table, Writer,- TableColumns)+ TableFields) import qualified Opaleye.Internal.Tag as Tag import qualified Opaleye.Internal.Unpackspec as U@@ -114,7 +116,7 @@ -- | Create a table with unqualified names. table :: String -- ^ Table name- -> TableColumns writeFields viewFields+ -> TableFields writeFields viewFields -> Table writeFields viewFields table = T.Table @@ -123,7 +125,7 @@ -- ^ Schema name -> String -- ^ Table name- -> TableColumns writeFields viewFields+ -> TableFields writeFields viewFields -> Table writeFields viewFields tableWithSchema = T.TableWithSchema