@@ -45,6 +45,11 @@ module Yoga.SQLite.ClientOm
45 , findWhereOrdered
45 , findWhereOrdered
46 , findWhereLimited
46 , findWhereLimited
47 , findAfter
47 , findAfter
48 , countWhere
53 , countWhere
49 , countAll
54 , countAll
50 , module Schema
55 , module Schema
@@ -52,7 +57,7 @@ module Yoga.SQLite.ClientOm
53import Prelude
58import Prelude
55−import Data.Array (head, intercalate, length, take)
60+import Data.Array (head, intercalate, length, mapWithIndex, take)
56import Data.Either (Either(..))
61import Data.Either (Either(..))
57import Data.Maybe (Maybe(..))
62import Data.Maybe (Maybe(..))
58import Data.Symbol (class IsSymbol, reflectSymbol)
63import Data.Symbol (class IsSymbol, reflectSymbol)
@@ -67,12 +72,11 @@ import Prim.TypeError (class Fail, Text)
67import Record as Record
72import Record as Record
68import Type.Proxy (Proxy(..))
73import Type.Proxy (Proxy(..))
69import Type.RowList (class ListToRow)
74import Type.RowList (class ListToRow)
70−import Unsafe.Coerce (unsafeCoerce)
71import Yoga.JSON (class ReadForeign)
75import Yoga.JSON (class ReadForeign)
72import Yoga.JSON as JSON
76import Yoga.JSON as JSON
73import Yoga.Om as Om
77import Yoga.Om as Om
74import Yoga.SQLite.Schema as Schema
78import Yoga.SQLite.Schema as Schema
75−import Yoga.SQLite.Schema (class ExtractType, class FieldToSQLiteValue, class InsertableColumnsRL, class ParamsToArray, class StripColumnsRL, AutoIncrement, Default, ForeignKey, Nullable, PrimaryKey, References, Table, Unique, fieldToSQLiteValue)
79+import Yoga.SQLite.Schema (class ExtractType, class FieldToSQLiteValue, class InsertableColumnsRL, class ParamsToArray, class RecordValuesRL, class SetClauseRL, class StripColumnsRL, AutoIncrement, Default, ForeignKey, Nullable, PrimaryKey, Table, Unique, fieldToSQLiteValue, setClauseRL)
76import Yoga.SQLite.SQLite (Connection)
80import Yoga.SQLite.SQLite (Connection)
77import Yoga.SQLite.SQLite as SQLite
81import Yoga.SQLite.SQLite as SQLite
@@ -470,7 +474,7 @@ findWhereLimited whereRec dir opts _ = do
470 <> " ORDER BY " <> reflectSymbol (Proxy :: Proxy col) <> " " <> orderDirSQL dir
474 <> " ORDER BY " <> reflectSymbol (Proxy :: Proxy col) <> " " <> orderDirSQL dir
471 <> " LIMIT ?" <> show limitIdx
475 <> " LIMIT ?" <> show limitIdx
472 <> " OFFSET ?" <> show offsetIdx
476 <> " OFFSET ?" <> show offsetIdx
473− values = whereResult.values <> [ unsafeCoerce opts.limit, unsafeCoerce opts.offset ]
477+ values = whereResult.values <> [ fieldToSQLiteValue opts.limit, fieldToSQLiteValue opts.offset ]
476 :: forall @col name cols colEntry rest row colType r err
480 :: forall @col name cols colEntry rest row colType r err
@@ -487,7 +491,7 @@ findAfter
487 -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) (PageRecord row)
491 -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) (PageRecord row)
488findAfter cursor limit _ = do
492findAfter cursor limit _ = do
489 { sqlite } <- Om.ask
493 { sqlite } <- Om.ask
490− result <- SQLite.query (SQLite.SQL sql) [ fieldToSQLiteValue cursor, unsafeCoerce (limit + 1) ] sqlite # liftAff
494+ result <- SQLite.query (SQLite.SQL sql) [ fieldToSQLiteValue cursor, fieldToSQLiteValue (limit + 1) ] sqlite # liftAff
491 allRows <- traverse parseRow result.rows
495 allRows <- traverse parseRow result.rows
492 pure { items: take limit allRows, hasMore: length allRows > limit }
496 pure { items: take limit allRows, hasMore: length allRows > limit }
@@ -496,7 +500,113 @@ findAfter cursor limit _ = do
496 <> " ORDER BY " <> reflectSymbol (Proxy :: Proxy col) <> " ASC"
500 <> " ORDER BY " <> reflectSymbol (Proxy :: Proxy col) <> " ASC"
497 <> " LIMIT ?2"
501 <> " LIMIT ?2"
499−countWhere
503+findAfterWithKey
504+ :: forall @col @key name cols colEntry keyEntry colRest keyRest row colType keyType r err
508+ => Row.Cons col colEntry colRest cols
509+ => Row.Cons key keyEntry keyRest cols
510+ => ExtractType colEntry colType
511+ => ExtractType keyEntry keyType
512+ => FieldToSQLiteValue colType
513+ => FieldToSQLiteValue keyType
514+ => TableRow (Table name cols) row
515+ => ReadForeign { | row }
516+ => { cursor :: colType, key :: keyType }
518+ -> Proxy (Table name cols)
519+ -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) (PageRecord row)
520+findAfterWithKey cursor limit _ = do
521+ { sqlite } <- Om.ask
522+ result <- SQLite.query (SQLite.SQL sql) [ fieldToSQLiteValue cursor.cursor, fieldToSQLiteValue cursor.cursor, fieldToSQLiteValue cursor.key, fieldToSQLiteValue (limit + 1) ] sqlite # liftAff
523+ allRows <- traverse parseRow result.rows
524+ pure { items: take limit allRows, hasMore: length allRows > limit }
526+ table = reflectSymbol (Proxy :: Proxy name)
527+ orderColumn = reflectSymbol (Proxy :: Proxy col)
528+ keyColumn = reflectSymbol (Proxy :: Proxy key)
529+ sql = "SELECT * FROM " <> table
530+ <> " WHERE (" <> orderColumn <> " > ?1 OR (" <> orderColumn <> " = ?2 AND " <> keyColumn <> " > ?3))"
531+ <> " ORDER BY " <> orderColumn <> " ASC, " <> keyColumn <> " ASC"
535+ :: forall name cols tables row rowRL r err
537+ => Row.Cons name cols () tables
538+ => RowToList row rowRL
539+ => InsertableRow (Table name cols) row
540+ => RecordValuesRL rowRL row
541+ => Schema.ColumnNamesRL rowRL
543+ -> Proxy (Table name cols)
544+ -> Om.Om { sqlite :: Connection | r } err Int
546+ { sqlite } <- Om.ask
547+ SQLite.execute (SQLite.SQL sql) values sqlite # liftAff
549+ tableName = reflectSymbol (Proxy :: Proxy name)
550+ colNames = Schema.columnNamesRL (Proxy :: Proxy rowRL)
551+ placeholders = mapWithIndex (\i _ -> "?" <> show (i + 1)) colNames
553+ if length colNames == 0 then "INSERT INTO " <> tableName <> " DEFAULT VALUES"
554+ else "INSERT INTO " <> tableName <> " (" <> intercalate ", " colNames <> ") VALUES (" <> intercalate ", " placeholders <> ")"
555+ values = Schema.recordValuesRL (Proxy :: Proxy rowRL) row
558+ :: forall name cols tables row rowRL result r err
560+ => Row.Cons name cols () tables
561+ => RowToList row rowRL
562+ => InsertableRow (Table name cols) row
563+ => RecordValuesRL rowRL row
564+ => Schema.ColumnNamesRL rowRL
565+ => TableRow (Table name cols) result
566+ => ReadForeign { | result }
568+ -> Proxy (Table name cols)
569+ -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) (Maybe { | result })
570+createReturningAll row _ = do
571+ { sqlite } <- Om.ask
572+ maybeRow <- SQLite.queryOne (SQLite.SQL sql) values sqlite # liftAff
573+ traverse parseRow maybeRow
575+ tableName = reflectSymbol (Proxy :: Proxy name)
576+ colNames = Schema.columnNamesRL (Proxy :: Proxy rowRL)
577+ placeholders = mapWithIndex (\i _ -> "?" <> show (i + 1)) colNames
579+ if length colNames == 0 then "INSERT INTO " <> tableName <> " DEFAULT VALUES"
580+ else "INSERT INTO " <> tableName <> " (" <> intercalate ", " colNames <> ") VALUES (" <> intercalate ", " placeholders <> ")"
581+ sql = insertSql <> " RETURNING *"
582+ values = Schema.recordValuesRL (Proxy :: Proxy rowRL) row
585+ :: forall name cols setRow setRL whereRow whereRL r err
587+ => RowToList setRow setRL
588+ => RowToList whereRow whereRL
589+ => Schema.ValidateSetColumnsRL setRL cols
590+ => SetClauseRL setRL
591+ => RecordValuesRL setRL setRow
592+ => ValidateWhereColumnsRL whereRL cols
593+ => OmWhereClauseRL whereRL whereRow
596+ -> Proxy (Table name cols)
597+ -> Om.Om { sqlite :: Connection | r } err Int
598+updateWhere whereRec setRec _ = do
599+ { sqlite } <- Om.ask
600+ SQLite.execute (SQLite.SQL sql) (setValues <> whereResult.values) sqlite # liftAff
602+ tableName = reflectSymbol (Proxy :: Proxy name)
603+ setValues = Schema.recordValuesRL (Proxy :: Proxy setRL) setRec
604+ whereResult = whereClauseFragments (Proxy :: Proxy whereRL) whereRec (length setValues + 1)
605+ sql = "UPDATE " <> tableName
606+ <> " SET " <> intercalate ", " (setClauseRL (Proxy :: Proxy setRL) 1)
607+ <> " WHERE " <> intercalate " AND " whereResult.sql
500 :: forall name cols whereRow whereRL r err
610 :: forall name cols whereRow whereRL r err
501 . IsSymbol name
611 . IsSymbol name
502 => RowToList whereRow whereRL
612 => RowToList whereRow whereRL
@@ -505,12 +615,27 @@ countWhere
505 => { | whereRow }
615 => { | whereRow }
506 -> Proxy (Table name cols)
616 -> Proxy (Table name cols)
507 -> Om.Om { sqlite :: Connection | r } err Int
617 -> Om.Om { sqlite :: Connection | r } err Int
618+deleteWhere whereRec _ = do
619+ { sqlite } <- Om.ask
620+ SQLite.execute (SQLite.SQL sql) whereResult.values sqlite # liftAff
622+ whereResult = whereClauseFragments (Proxy :: Proxy whereRL) whereRec 1
623+ sql = "DELETE FROM " <> reflectSymbol (Proxy :: Proxy name)
624+ <> " WHERE " <> intercalate " AND " whereResult.sql
627+ :: forall name cols whereRow whereRL r err
629+ => RowToList whereRow whereRL
630+ => ValidateWhereColumnsRL whereRL cols
631+ => OmWhereClauseRL whereRL whereRow
633+ -> Proxy (Table name cols)
634+ -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) Int
508countWhere whereRec _ = do
635countWhere whereRec _ = do
509 { sqlite } <- Om.ask
636 { sqlite } <- Om.ask
510 maybeRow <- SQLite.queryOne (SQLite.SQL sql) whereResult.values sqlite # liftAff
637 maybeRow <- SQLite.queryOne (SQLite.SQL sql) whereResult.values sqlite # liftAff
511− pure case maybeRow of
638+ countFrom maybeRow
513− Just row -> (unsafeCoerce row).result
515 whereResult = whereClauseFragments (Proxy :: Proxy whereRL) whereRec 1
640 whereResult = whereClauseFragments (Proxy :: Proxy whereRL) whereRec 1
516 sql = "SELECT COUNT(*) AS result FROM " <> reflectSymbol (Proxy :: Proxy name)
641 sql = "SELECT COUNT(*) AS result FROM " <> reflectSymbol (Proxy :: Proxy name)
@@ -520,12 +645,15 @@ countAll
520 :: forall name cols r err
645 :: forall name cols r err
521 . IsSymbol name
646 . IsSymbol name
522 => Proxy (Table name cols)
647 => Proxy (Table name cols)
523− -> Om.Om { sqlite :: Connection | r } err Int
648+ -> Om.Om { sqlite :: Connection | r } (parseError :: MultipleErrors | err) Int
524countAll _ = do
649countAll _ = do
525 { sqlite } <- Om.ask
650 { sqlite } <- Om.ask
526 maybeRow <- SQLite.queryOne (SQLite.SQL sql) [] sqlite # liftAff
651 maybeRow <- SQLite.queryOne (SQLite.SQL sql) [] sqlite # liftAff
527− pure case maybeRow of
652+ countFrom maybeRow
529− Just row -> (unsafeCoerce row).result
531 sql = "SELECT COUNT(*) AS result FROM " <> reflectSymbol (Proxy :: Proxy name)
654 sql = "SELECT COUNT(*) AS result FROM " <> reflectSymbol (Proxy :: Proxy name)
656+countFrom :: forall ctx err. Maybe Foreign -> Om.Om ctx (parseError :: MultipleErrors | err) Int
657+countFrom = case _ of
659+ Just row -> _.result <$> (parseRow row :: Om.Om ctx (parseError :: MultipleErrors | err) { result :: Int })