Handle numeric values using purescript-decimals

This commit is contained in:
Tomasz Rybarczyk 2018-04-21 13:12:20 +02:00
parent 63c21fb220
commit 9c006c72ce
5 changed files with 40 additions and 14 deletions

View File

@ -4,7 +4,7 @@ purescript-postgresql-client is a PostgreSQL client library for PureScript.
## NOTE: I WILL NO LONGER BE MAINTAINING THIS LIBRARY. DUE TO THE COUNTLESS PROBLEMS AND PITFALLS IN THE NODE.JS POSTGRESQL LIBRARY IT IS NO MORE FUN BUT JUST A MASSIVE PITA. IF ANYBODY WANTS TO VOLUNTEER, PLEASE LET ME KNOW, AND I WILL TRANSFER OWNERSHIP OF THE REPO. I THINK THE ONLY TWO REAL SOLUTIONS WOULD BE TO EITHER WRITE A NEW LIBPQ BINDING FOR NODE OR TO WRITE A PSC BACKEND FOR A DECENT PLATFORM (NOT NODE.JS). ## NOTE: I WILL NO LONGER BE MAINTAINING THIS LIBRARY. DUE TO THE COUNTLESS PROBLEMS AND PITFALLS IN THE NODE.JS POSTGRESQL LIBRARY IT IS NO MORE FUN BUT JUST A MASSIVE PITA. IF ANYBODY WANTS TO VOLUNTEER, PLEASE LET ME KNOW, AND I WILL TRANSFER OWNERSHIP OF THE REPO. I THINK THE ONLY TWO REAL SOLUTIONS WOULD BE TO EITHER WRITE A NEW LIBPQ BINDING FOR NODE OR TO WRITE A PSC BACKEND FOR A DECENT PLATFORM (NOT NODE.JS).
To use this library, you need to add `pg` as an npm dependency. You can also To use this library, you need to add `pg` and `decimal.js` as an npm dependency. You can also
find this npm library on [https://github.com/brianc/node-postgres][pg]. find this npm library on [https://github.com/brianc/node-postgres][pg].
The purspgpp preprocessor has been replaced by [sqltopurs], which is a code The purspgpp preprocessor has been replaced by [sqltopurs], which is a code

View File

@ -16,7 +16,8 @@
"purescript-datetime": "^3.0.0", "purescript-datetime": "^3.0.0",
"purescript-bifunctors": "^3.0.0", "purescript-bifunctors": "^3.0.0",
"purescript-eff": "^3.1.0", "purescript-eff": "^3.1.0",
"purescript-exceptions": "^3.0.0" "purescript-exceptions": "^3.0.0",
"purescript-decimals": "^3.4.0"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -1,6 +1,7 @@
{ {
"name": "purescript-postgresql-client", "name": "purescript-postgresql-client",
"dependencies": { "dependencies": {
"decimal.js": "^10.0.0",
"pg": "^6.1.2" "pg": "^6.1.2"
} }
} }

View File

@ -1,5 +1,7 @@
module Database.PostgreSQL.Value where module Database.PostgreSQL.Value where
import Prelude
import Control.Monad.Eff (kind Effect) import Control.Monad.Eff (kind Effect)
import Control.Monad.Error.Class (throwError) import Control.Monad.Error.Class (throwError)
import Control.Monad.Except (runExcept) import Control.Monad.Except (runExcept)
@ -7,13 +9,14 @@ import Data.Array as Array
import Data.Bifunctor (lmap) import Data.Bifunctor (lmap)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.DateTime.Instant (Instant) import Data.DateTime.Instant (Instant)
import Data.Either (Either) import Data.Decimal (Decimal)
import Data.Decimal as Decimal
import Data.Either (Either, note)
import Data.Foreign (Foreign, isNull, readArray, readBoolean, readChar, readInt, readNumber, readString, toForeign, unsafeFromForeign) import Data.Foreign (Foreign, isNull, readArray, readBoolean, readChar, readInt, readNumber, readString, toForeign, unsafeFromForeign)
import Data.List (List) import Data.List (List)
import Data.List as List import Data.List as List
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Data.Traversable (traverse) import Data.Traversable (traverse)
import Prelude
-- | Convert things to SQL values. -- | Convert things to SQL values.
class ToSQLValue a where class ToSQLValue a where
@ -90,6 +93,14 @@ instance toSQLValueForeign :: ToSQLValue Foreign where
instance fromSQLValueForeign :: FromSQLValue Foreign where instance fromSQLValueForeign :: FromSQLValue Foreign where
fromSQLValue = pure fromSQLValue = pure
instance toSQLValueDecimal :: ToSQLValue Decimal where
toSQLValue = Decimal.toString >>> toForeign
instance fromSQLValueDecimal :: FromSQLValue Decimal where
fromSQLValue v = do
s lmap show $ runExcept (readString v)
note ("Decimal literal parsing failed: " <> s) (Decimal.fromString s)
foreign import null :: Foreign foreign import null :: Foreign
foreign import instantToString :: Instant -> Foreign foreign import instantToString :: Instant -> Foreign
foreign import unsafeIsBuffer :: a. a -> Boolean foreign import unsafeIsBuffer :: a. a -> Boolean

View File

@ -9,8 +9,9 @@ import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Class (liftEff) import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Exception (EXCEPTION, error) import Control.Monad.Eff.Exception (EXCEPTION, error)
import Control.Monad.Error.Class (throwError, try) import Control.Monad.Error.Class (throwError, try)
import Data.Decimal as D
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Database.PostgreSQL (POSTGRESQL, Query(..), PoolConfiguration, execute, newPool, query, Row0(..), Row1(..), Row2(..), Row6(..), scalar, withConnection, withTransaction) import Database.PostgreSQL (POSTGRESQL, PoolConfiguration, Query(Query), Row0(Row0), Row1(Row1), Row2(Row2), Row3(Row3), Row9(Row9), execute, newPool, query, scalar, withConnection, withTransaction)
import Test.Assert (ASSERT, assert) import Test.Assert (ASSERT, assert)
main :: eff. Eff (assert :: ASSERT, exception :: EXCEPTION, postgreSQL :: POSTGRESQL | eff) Unit main :: eff. Eff (assert :: ASSERT, exception :: EXCEPTION, postgreSQL :: POSTGRESQL | eff) Unit
@ -21,14 +22,18 @@ main = void $ launchAff do
CREATE TEMPORARY TABLE foods ( CREATE TEMPORARY TABLE foods (
name text NOT NULL, name text NOT NULL,
delicious boolean NOT NULL, delicious boolean NOT NULL,
price NUMERIC(4,2) NOT NULL,
PRIMARY KEY (name) PRIMARY KEY (name)
) )
""") Row0 """) Row0
execute conn (Query """ execute conn (Query """
INSERT INTO foods (name, delicious) INSERT INTO foods (name, delicious, price)
VALUES ($1, $2), ($3, $4), ($5, $6) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9)
""") (Row6 "pork" true "sauerkraut" false "rookworst" true) """) (Row9
"pork" true (D.fromString "8.30")
"sauerkraut" false (D.fromString "3.30")
"rookworst" true (D.fromString "5.60"))
names <- query conn (Query """ names <- query conn (Query """
SELECT name SELECT name
@ -39,6 +44,14 @@ main = void $ launchAff do
liftEff <<< assert $ names == [Row1 "pork", Row1 "rookworst"] liftEff <<< assert $ names == [Row1 "pork", Row1 "rookworst"]
sour <- query conn (Query """
SELECT name, price
FROM foods
WHERE NOT delicious
ORDER BY name ASC
""") Row0
liftEff <<< assert $ sour == [Row2 "sauerkraut" (D.fromString "3.30")]
testTransactionCommit conn testTransactionCommit conn
testTransactionRollback conn testTransactionRollback conn
@ -48,9 +61,9 @@ main = void $ launchAff do
deleteAll conn deleteAll conn
withTransaction conn do withTransaction conn do
execute conn (Query """ execute conn (Query """
INSERT INTO foods (name, delicious) INSERT INTO foods (name, delicious, price)
VALUES ($1, $2) VALUES ($1, $2, $3)
""") (Row2 "pork" true) """) (Row3 "pork" true (D.fromString "8.30"))
testCount conn 1 testCount conn 1
testCount conn 1 testCount conn 1
@ -58,9 +71,9 @@ main = void $ launchAff do
deleteAll conn deleteAll conn
_ <- try $ withTransaction conn do _ <- try $ withTransaction conn do
execute conn (Query """ execute conn (Query """
INSERT INTO foods (name, delicious) INSERT INTO foods (name, delicious, price)
VALUES ($1, $2) VALUES ($1, $2, $3)
""") (Row2 "pork" true) """) (Row3 "pork" true (D.fromString "8.30"))
testCount conn 1 testCount conn 1
throwError $ error "fail" throwError $ error "fail"
testCount conn 0 testCount conn 0