diff --git a/README.md b/README.md index 10c95ca..e4998a7 100644 --- a/README.md +++ b/README.md @@ -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). -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]. The purspgpp preprocessor has been replaced by [sqltopurs], which is a code diff --git a/bower.json b/bower.json index 2f2c61f..44a0875 100644 --- a/bower.json +++ b/bower.json @@ -16,7 +16,8 @@ "purescript-datetime": "^3.0.0", "purescript-bifunctors": "^3.0.0", "purescript-eff": "^3.1.0", - "purescript-exceptions": "^3.0.0" + "purescript-exceptions": "^3.0.0", + "purescript-decimals": "^3.4.0" }, "repository": { "type": "git", diff --git a/package.json b/package.json index 0f4f7af..c0ef474 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "purescript-postgresql-client", "dependencies": { + "decimal.js": "^10.0.0", "pg": "^6.1.2" } } diff --git a/src/Database/PostgreSQL/Value.purs b/src/Database/PostgreSQL/Value.purs index f1cf5df..9b6838c 100644 --- a/src/Database/PostgreSQL/Value.purs +++ b/src/Database/PostgreSQL/Value.purs @@ -1,5 +1,7 @@ module Database.PostgreSQL.Value where +import Prelude + import Control.Monad.Eff (kind Effect) import Control.Monad.Error.Class (throwError) import Control.Monad.Except (runExcept) @@ -7,13 +9,14 @@ import Data.Array as Array import Data.Bifunctor (lmap) import Data.ByteString (ByteString) 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.List (List) import Data.List as List import Data.Maybe (Maybe(..)) import Data.Traversable (traverse) -import Prelude -- | Convert things to SQL values. class ToSQLValue a where @@ -90,6 +93,14 @@ instance toSQLValueForeign :: ToSQLValue Foreign where instance fromSQLValueForeign :: FromSQLValue Foreign where 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 instantToString :: Instant -> Foreign foreign import unsafeIsBuffer :: ∀ a. a -> Boolean diff --git a/test/Main.purs b/test/Main.purs index 5060f0b..02fc0a0 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -9,8 +9,9 @@ import Control.Monad.Eff (Eff) import Control.Monad.Eff.Class (liftEff) import Control.Monad.Eff.Exception (EXCEPTION, error) import Control.Monad.Error.Class (throwError, try) +import Data.Decimal as D 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) main :: ∀ eff. Eff (assert :: ASSERT, exception :: EXCEPTION, postgreSQL :: POSTGRESQL | eff) Unit @@ -21,14 +22,18 @@ main = void $ launchAff do CREATE TEMPORARY TABLE foods ( name text NOT NULL, delicious boolean NOT NULL, + price NUMERIC(4,2) NOT NULL, PRIMARY KEY (name) ) """) Row0 execute conn (Query """ - INSERT INTO foods (name, delicious) - VALUES ($1, $2), ($3, $4), ($5, $6) - """) (Row6 "pork" true "sauerkraut" false "rookworst" true) + INSERT INTO foods (name, delicious, price) + VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9) + """) (Row9 + "pork" true (D.fromString "8.30") + "sauerkraut" false (D.fromString "3.30") + "rookworst" true (D.fromString "5.60")) names <- query conn (Query """ SELECT name @@ -39,6 +44,14 @@ main = void $ launchAff do 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 testTransactionRollback conn @@ -48,9 +61,9 @@ main = void $ launchAff do deleteAll conn withTransaction conn do execute conn (Query """ - INSERT INTO foods (name, delicious) - VALUES ($1, $2) - """) (Row2 "pork" true) + INSERT INTO foods (name, delicious, price) + VALUES ($1, $2, $3) + """) (Row3 "pork" true (D.fromString "8.30")) testCount conn 1 testCount conn 1 @@ -58,9 +71,9 @@ main = void $ launchAff do deleteAll conn _ <- try $ withTransaction conn do execute conn (Query """ - INSERT INTO foods (name, delicious) - VALUES ($1, $2) - """) (Row2 "pork" true) + INSERT INTO foods (name, delicious, price) + VALUES ($1, $2, $3) + """) (Row3 "pork" true (D.fromString "8.30")) testCount conn 1 throwError $ error "fail" testCount conn 0