@@ -2,1140 +2,790 @@ module Test.Main where
3import Prelude
3import Prelude
5−import Data.Array (head, drop)
5+import Control.Monad.Aff (Aff, launchAff, forkAff, delay, attempt)
6+import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', modifyVar, peekVar, putVar, takeVar)
7+import Control.Monad.Aff.Console (log)
8+import Control.Monad.Eff (Eff)
9+import Control.Monad.Eff.Class (liftEff)
10+import Control.Monad.Eff.Exception (EXCEPTION, message)
11+import Control.Monad.Eff.Now (NOW, now)
6−import Data.Date as Date
12+import Data.Date as Date
7−import Data.DateTime (DateTime(..), Time(..))
13+import Data.DateTime as DateTime
14+import Data.DateTime (DateTime(..), Time(..))
8−import Data.DateTime.Instant (toDateTime)
15+import Data.DateTime.Instant (toDateTime)
9−import Data.Either (Either(..))
16+import Data.Either (Either(..))
10−import Data.Enum (toEnum)
17+import Data.Enum (toEnum)
11−import Data.Maybe (Maybe(..), isNothing, maybe)
18+import Data.Maybe (Maybe(..), isNothing, maybe)
12−import Data.Time.Duration (Milliseconds(..))
19+import Data.Time.Duration (Milliseconds(..))
13−import Data.Traversable (traverse)
20+import Data.Traversable (traverse)
14−import Data.Tuple (Tuple(..), uncurry)
21+import Data.Tuple (Tuple(..), uncurry)
15−import Database.IndexedDB.Core (CursorDirection(..), Database, Index, ObjectStore, Transaction, TransactionMode(..))
22+import Test.Spec (describe, describe, it, it)
16−import Database.IndexedDB.IDBCursor as IDBCursor
17−import Database.IndexedDB.IDBDatabase as IDBDatabase
18−import Database.IndexedDB.IDBFactory as IDBFactory
19−import Database.IndexedDB.IDBIndex as IDBIndex
20−import Database.IndexedDB.IDBKey (Key, none, toKey)
21−import Database.IndexedDB.IDBKeyRange as IDBKeyRange
22−import Database.IndexedDB.IDBObjectStore as IDBObjectStore
23−import Database.IndexedDB.IDBTransaction as IDBTransaction
24−import Effect (Effect)
25−import Effect.Aff (Aff, attempt, delay, forkAff, launchAff, launchAff_)
26−import Effect.Aff.AVar (AVar)
27−import Effect.Aff.AVar as AVar
28−import Effect.Class (liftEffect)
29−import Effect.Console (log)
30−import Effect.Exception (name)
31−import Effect.Now (now)
32−import Test.Spec (describe, it)
33−import Test.Spec.Assertions (shouldEqual, fail)
23+import Test.Spec.Assertions (shouldEqual, fail)
34−import Test.Spec.Reporter (consoleReporter)
24+import Test.Spec.Mocha (MOCHA, runMocha)
35−import Test.Spec.Runner (runSpec)
25+
26+import Database.IndexedDB.Core
27+import Database.IndexedDB.IDBKey
28+import Database.IndexedDB.IDBCursor as IDBCursor
29+import Database.IndexedDB.IDBDatabase as IDBDatabase
30+import Database.IndexedDB.IDBFactory as IDBFactory
31+import Database.IndexedDB.IDBIndex as IDBIndex
32+import Database.IndexedDB.IDBKeyRange as IDBKeyRange
33+import Database.IndexedDB.IDBObjectStore as IDBObjectStore
34+import Database.IndexedDB.IDBTransaction as IDBTransaction
39−launchAff' :: forall a. Aff a -> Effect Unit
37+infixr 7 Tuple as :+:
43−modifyAVar :: forall a. (a -> a) -> AVar a -> Aff Unit
39+launchAff' :: forall a e. Aff e a -> Eff (exception :: EXCEPTION | e) Unit
44−modifyAVar fn v = do
40+launchAff' aff =
45− val <- AVar.take v
41+ pure unit <* (launchAff aff)
48−main :: Effect Unit
43+-- main :: forall eff. Eff (now :: NOW, mocha :: MOCHA, idb :: IDB, exception :: EXCEPTION, avar :: AVAR | eff) Unit
49−main = do
44+main = runMocha do
50− launchAff_ $ runSpec [ consoleReporter ] $ do
51− describe "IDBFactory" do
45+ describe "IDBFactory" do
53 tearDown name version db = do
47 tearDown name version db = do
54 IDBDatabase.close db
48 IDBDatabase.close db
55 version' <- IDBFactory.deleteDatabase name
49 version' <- IDBFactory.deleteDatabase name
56− liftEffect $ log $ show version'
57 version' `shouldEqual` version
50 version' `shouldEqual` version
59− it "open default" do
52+ it "open default" do
61− name = "db-default"
53+ let name = "db-default"
62 version = 1
54 version = 1
63− db <- IDBFactory.open name Nothing
55+ db <- IDBFactory.open name Nothing
64− { onUpgradeNeeded: Nothing
56+ { onUpgradeNeeded : Nothing
65− , onBlocked: Nothing
57+ , onBlocked : Nothing
67− IDBDatabase.name db `shouldEqual` name
59+ IDBDatabase.name db `shouldEqual` name
68− tearDown name version db
60+ tearDown name version db
70− it "open specific version" do
74− db <- IDBFactory.open name (Just version)
75− { onUpgradeNeeded: Nothing
78− IDBDatabase.name db `shouldEqual` name
79− tearDown name version db
81− it "open specific version -> close -> open latest" do
63+ it "open specific version" do
83− name = "db-latest"
64+ let name = "db-specific"
84 version = 14
65 version = 14
85− db01 <- IDBFactory.open name (Just version)
66+ db <- IDBFactory.open name (Just version)
86− { onUpgradeNeeded: Nothing
67+ { onUpgradeNeeded : Nothing
87− , onBlocked: Nothing
68+ , onBlocked : Nothing
89− IDBDatabase.name db01 `shouldEqual` name
70+ IDBDatabase.name db `shouldEqual` name
90− IDBDatabase.close db01
91− db02 <- IDBFactory.open name Nothing
92− { onUpgradeNeeded: Nothing
95− tearDown name version db02
71+ tearDown name version db
74+ it "open specific version -> close -> open latest" do
75+ let name = "db-latest"
77+ db <- IDBFactory.open name (Just version)
78+ { onUpgradeNeeded : Nothing
79+ , onBlocked : Nothing
81+ IDBDatabase.name db `shouldEqual` name
83+ db <- IDBFactory.open name Nothing
84+ { onUpgradeNeeded : Nothing
85+ , onBlocked : Nothing
87+ tearDown name version db
97− it "open + onUpgradeNeed" do
90+ it "open + onUpgradeNeed" do
99− name = "db-upgrade-needed"
91+ let name = "db-upgrade-needed"
100 version = 1
92 version = 1
101− callback (Tuple varName varVersion) db _ { oldVersion } = do
93+ callback var db _ = do
102− _ <- launchAff $ modifyAVar (const $ IDBDatabase.name db) varName
94+ _ <- launchAff $ modifyVar (const $ IDBDatabase.name db) var
103− _ <- launchAff $ modifyAVar (const $ oldVersion) varVersion
104 pure unit
95 pure unit
105− varName <- AVar.new "-"
96+ var <- makeVar' "-"
106− varVersion <- AVar.new (-1)
107− db <- IDBFactory.open name Nothing
97+ db <- IDBFactory.open name Nothing
108− { onUpgradeNeeded: Just (callback (Tuple varName varVersion))
98+ { onUpgradeNeeded : Just (callback var)
109− , onBlocked: Nothing
99+ , onBlocked : Nothing
111− name' <- AVar.read varName
101+ name <- peekVar var
112− version' <- AVar.read varVersion
113− name' `shouldEqual` name
102+ name `shouldEqual` name
114− version' `shouldEqual` 0
115− tearDown name version db
103+ tearDown name version db
117− it "open + onBlocked" do
106+ it "open + onBlocked" do
119− name = "db-blocked"
107+ let name = "db-blocked"
120 version = 14
108 version = 14
121 callback var = do
109 callback var = do
122− _ <- launchAff $ modifyAVar (const $ "db-blocked") var
110+ _ <- launchAff $ modifyVar (const $ "db-blocked") var
123 pure unit
111 pure unit
125− var <- AVar.new "-"
113+ var <- makeVar' "-"
126− db01 <- IDBFactory.open name Nothing
114+ db01 <- IDBFactory.open name Nothing
127− { onUpgradeNeeded: Nothing
115+ { onUpgradeNeeded : Nothing
128− , onBlocked: Nothing
116+ , onBlocked : Nothing
130− _ <- forkAff do
118+ _ <- forkAff do
131− delay (Milliseconds 100.0)
119+ delay (Milliseconds 100.0)
132− IDBDatabase.close db01
120+ IDBDatabase.close db01
134− db02 <- IDBFactory.open name (Just version)
122+ db02 <- IDBFactory.open name (Just version)
135− { onUpgradeNeeded: Nothing
123+ { onUpgradeNeeded : Nothing
136− , onBlocked: Just (callback var)
124+ , onBlocked : Just (callback var)
138− name' <- AVar.read var
126+ name <- peekVar var
139− name' `shouldEqual` name
127+ name `shouldEqual` name
140− tearDown name version db02
128+ tearDown name version db02
142− describe "IDBKeyRange" do
130+ describe "IDBKeyRange" do
143− it "only(int)" do
131+ it "only(int)" do
145− key = 14
132+ let key = 14
146 range = IDBKeyRange.only key
133 range = IDBKeyRange.only key
147− IDBKeyRange.includes range (toKey key) `shouldEqual` true
134+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
149− it "only(string)" do
136+ it "only(string)" do
151− key = "patate"
137+ let key = "patate"
152 range = IDBKeyRange.only key
138 range = IDBKeyRange.only key
153− IDBKeyRange.includes range (toKey key) `shouldEqual` true
139+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
155− it "only(float)" do
141+ it "only(float)" do
157− key = 14.42
142+ let key = 14.42
158 range = IDBKeyRange.only key
143 range = IDBKeyRange.only key
159− IDBKeyRange.includes range (toKey key) `shouldEqual` true
144+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
161− it "only(date)" do
146+ it "only(date)" do
163− mkey = DateTime
147+ let mkey = DateTime
164 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
148 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
165 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
149 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
167− case mkey of
151+ case mkey of
168− Nothing ->
152+ Nothing ->
169− fail "unable to create datetime"
153+ fail "unable to create datetime"
170− Just key -> do
154+ Just key -> do
171− let range = IDBKeyRange.only key
155+ let range = IDBKeyRange.only key
172− IDBKeyRange.includes range (toKey key) `shouldEqual` true
156+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
174− it "only([int])" do
158+ it "only([int])" do
176− key = [ 14, 42 ]
159+ let key = [14, 42]
177 range = IDBKeyRange.only key
160 range = IDBKeyRange.only key
178− IDBKeyRange.includes range (toKey key) `shouldEqual` true
161+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
180− it "only([string])" do
163+ it "only([string])" do
182− key = [ "patate", "autruche" ]
164+ let key = ["patate", "autruche"]
183 range = IDBKeyRange.only key
165 range = IDBKeyRange.only key
184− IDBKeyRange.includes range (toKey key) `shouldEqual` true
166+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
186− it "lowerBound(14, open)" do
168+ it "lowerBound(14, open)" do
188− key = 14
169+ let key = 14
189− open = true
170+ open = true
190 range = IDBKeyRange.lowerBound key open
171 range = IDBKeyRange.lowerBound key open
191− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
172+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
192− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
173+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
193− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
174+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
195− it "lowerBound(14, close)" do
176+ it "lowerBound(14, close)" do
197− key = 14
177+ let key = 14
198− open = false
178+ open = false
199 range = IDBKeyRange.lowerBound key open
179 range = IDBKeyRange.lowerBound key open
200− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
180+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
201− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
181+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
202− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
182+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
204− it "upperBound(14, open)" do
184+ it "upperBound(14, open)" do
206− key = 14
185+ let key = 14
207− open = true
186+ open = true
208 range = IDBKeyRange.upperBound key open
187 range = IDBKeyRange.upperBound key open
209− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
188+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
210− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
189+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
211− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
190+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
213− it "upperBound(14, close)" do
192+ it "upperBound(14, close)" do
215− key = 14
193+ let key = 14
216− open = false
194+ open = false
217 range = IDBKeyRange.upperBound key open
195 range = IDBKeyRange.upperBound key open
218− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
196+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
219− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
197+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
220− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
198+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
222− it "bound(42, 14, open, open) => Nothing" do
200+ it "bound(42, 14, open, open) => Nothing" do
224− lower = 42
201+ let lower = 42
225− upper = 14
202+ upper = 14
226 lowerOpen = true
203 lowerOpen = true
227 upperOpen = true
204 upperOpen = true
228− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
205+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
229− isNothing mrange `shouldEqual` true
206+ isNothing mrange `shouldEqual` true
231− it "bound(14, 42, open, open)" do
208+ it "bound(14, 42, open, open)" do
233− lower = 14
209+ let lower = 14
234− upper = 42
210+ upper = 42
235 lowerOpen = true
211 lowerOpen = true
236 upperOpen = true
212 upperOpen = true
237− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
213+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
238− case mrange of
214+ case mrange of
239− Nothing ->
215+ Nothing ->
240− fail "invalid range provided"
216+ fail "invalid range provided"
241− Just range -> do
217+ Just range -> do
242− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
218+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
243− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
219+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
244− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
220+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
245− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
221+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
246− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
222+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
247− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
223+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
249− it "bound(14, 42, open, close)" do
225+ it "bound(14, 42, open, close)" do
251− lower = 14
226+ let lower = 14
252− upper = 42
227+ upper = 42
253 lowerOpen = true
228 lowerOpen = true
254 upperOpen = false
229 upperOpen = false
255− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
230+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
256− case mrange of
231+ case mrange of
257− Nothing ->
232+ Nothing ->
258− fail "invalid range provided"
233+ fail "invalid range provided"
259− Just range -> do
234+ Just range -> do
260− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
235+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
261− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
236+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
262− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
237+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
263− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
238+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
264− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
239+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
265− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
240+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
267− it "bound(14, 42, close, open)" do
242+ it "bound(14, 42, close, open)" do
269− lower = 14
243+ let lower = 14
270− upper = 42
244+ upper = 42
271 lowerOpen = false
245 lowerOpen = false
272 upperOpen = true
246 upperOpen = true
273− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
247+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
274− case mrange of
248+ case mrange of
275− Nothing ->
249+ Nothing ->
276− fail "invalid range provided"
250+ fail "invalid range provided"
277− Just range -> do
251+ Just range -> do
278− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
252+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
279− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
253+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
280− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
254+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
281− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
255+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
282− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
256+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
283− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
257+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
285− it "bound(14, 42, close, close)" do
259+ it "bound(14, 42, close, close)" do
287− lower = 14
260+ let lower = 14
288− upper = 42
261+ upper = 42
289 lowerOpen = false
262 lowerOpen = false
290 upperOpen = false
263 upperOpen = false
291− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
264+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
292− case mrange of
265+ case mrange of
293− Nothing ->
266+ Nothing ->
294− fail "invalid range provided"
267+ fail "invalid range provided"
295− Just range -> do
268+ Just range -> do
296− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
269+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
297− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
270+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
298− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
271+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
299− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
272+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
300− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
273+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
301− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
274+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
303− it "can access attributes of a range" do
276+ it "can access attributes of a range" do
304− let range = IDBKeyRange.lowerBound 14 false
277+ let range = IDBKeyRange.lowerBound 14 false
305− IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
278+ IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
306− IDBKeyRange.upper range `shouldEqual` none
279+ IDBKeyRange.upper range `shouldEqual` (Nothing :: Maybe Key)
307− IDBKeyRange.lowerOpen range `shouldEqual` false
280+ IDBKeyRange.lowerOpen range `shouldEqual` false
308− IDBKeyRange.upperOpen range `shouldEqual` true
281+ IDBKeyRange.upperOpen range `shouldEqual` true
310− describe "IDBDatabase" do
283+ describe "IDBDatabase" do
312 tearDown db = do
285 tearDown db = do
313 IDBDatabase.close db
286 IDBDatabase.close db
314 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
287 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
315 pure unit
288 pure unit
317 setup storeParams = do
290 setup storeParams = do
319− onUpgradeNeeded var db _ _ = launchAff' do
291+ let onUpgradeNeeded var db _ = launchAff' do
320− store <- IDBDatabase.createObjectStore db "store" storeParams
292+ store <- IDBDatabase.createObjectStore db "store" storeParams
321− _ <- AVar.put { db, store } var
293+ _ <- putVar var { db, store }
322− pure unit
294+ pure unit
324− var <- AVar.empty
296+ var <- makeVar
325− _ <- IDBFactory.open "db" Nothing
297+ db <- IDBFactory.open "db" Nothing
326− { onUpgradeNeeded: Just (onUpgradeNeeded var)
298+ { onUpgradeNeeded : Just (onUpgradeNeeded var)
327− , onBlocked: Nothing
299+ , onBlocked : Nothing
330− AVar.take var
302+ takeVar var
332− it "createObjectStore (keyPath: [], autoIncrement: true)" do
304+ it "createObjectStore (keyPath: [], autoIncrement: true)" do
333− { db, store } <- setup { keyPath: [], autoIncrement: true }
305+ { db, store } <- setup { keyPath: [], autoIncrement: true }
334− IDBObjectStore.name store `shouldEqual` "store"
306+ IDBObjectStore.name store `shouldEqual` "store"
335− IDBObjectStore.keyPath store `shouldEqual` []
307+ IDBObjectStore.keyPath store `shouldEqual` []
336− IDBObjectStore.autoIncrement store `shouldEqual` true
308+ IDBObjectStore.autoIncrement store `shouldEqual` true
337− IDBObjectStore.indexNames store `shouldEqual` []
309+ IDBObjectStore.indexNames store `shouldEqual` []
338− tearDown db
310+ tearDown db
340− it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
312+ it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
341− { db, store } <- setup { keyPath: [ "patate" ], autoIncrement: true }
313+ { db, store } <- setup { keyPath: ["patate"], autoIncrement: true }
342− IDBObjectStore.name store `shouldEqual` "store"
314+ IDBObjectStore.name store `shouldEqual` "store"
343− IDBObjectStore.keyPath store `shouldEqual` [ "patate" ]
315+ IDBObjectStore.keyPath store `shouldEqual` ["patate"]
344− IDBObjectStore.autoIncrement store `shouldEqual` true
316+ IDBObjectStore.autoIncrement store `shouldEqual` true
345− IDBObjectStore.indexNames store `shouldEqual` []
317+ IDBObjectStore.indexNames store `shouldEqual` []
346− tearDown db
318+ tearDown db
348− it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
320+ it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
349− { db, store } <- setup { keyPath: [ "patate", "autruche" ], autoIncrement: false }
321+ { db, store } <- setup { keyPath: ["patate", "autruche"], autoIncrement: false }
350− IDBObjectStore.name store `shouldEqual` "store"
322+ IDBObjectStore.name store `shouldEqual` "store"
351− IDBObjectStore.keyPath store `shouldEqual` [ "patate", "autruche" ]
323+ IDBObjectStore.keyPath store `shouldEqual` ["patate", "autruche"]
352− IDBObjectStore.autoIncrement store `shouldEqual` false
324+ IDBObjectStore.autoIncrement store `shouldEqual` false
353− IDBObjectStore.indexNames store `shouldEqual` []
325+ IDBObjectStore.indexNames store `shouldEqual` []
354− tearDown db
326+ tearDown db
356− it "deleteObjectStore" do
328+ it "deleteObjectStore" do
358− onUpgradeNeeded var db _ _ = launchAff' do
329+ let onUpgradeNeeded var db _ = launchAff' do
359 _ <- IDBDatabase.deleteObjectStore db "store"
330 _ <- IDBDatabase.deleteObjectStore db "store"
360− AVar.put true var
331+ putVar var true
363− { db } <- setup IDBDatabase.defaultParameters
364− IDBDatabase.close db
365− db' <- IDBFactory.open "db" (Just 999)
366− { onUpgradeNeeded: Just (onUpgradeNeeded var)
367− , onBlocked: Nothing
369− deleted <- AVar.take var
370− deleted `shouldEqual` true
373− describe "IDBObjectStore" do
333+ var <- makeVar
374− let
334+ { db, store } <- setup IDBObjectStore.defaultParameters
376− IDBDatabase.close db
335+ IDBDatabase.close db
377− _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
380− setup { storeParams, onUpgradeNeeded } = do
382− onUpgradeNeeded' var db _ _ = launchAff' do
383− store <- IDBDatabase.createObjectStore db "store" storeParams
384− liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure store)
385− AVar.put { db, store } var
388− _ <- IDBFactory.open "db" Nothing
389− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
336+ db <- IDBFactory.open "db" (Just 999) { onUpgradeNeeded : Just (onUpgradeNeeded var)
390− , onBlocked: Nothing
337+ , onBlocked : Nothing
392−
339+ deleted <- takeVar var
393− AVar.take var
340+ deleted `shouldEqual` true
396− date <- liftEffect $ toDateTime <$> now
398− { storeParams: { autoIncrement: true, keyPath: [] }
399− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
401− key <- IDBObjectStore.add store "patate" none
402− (toKey 1) `shouldEqual` key
405− key' <- IDBObjectStore.add store "patate" (Just 14)
406− (toKey 14) `shouldEqual` key'
409− key'' <- IDBObjectStore.add store "patate" (Just 14.42)
410− (toKey 14.42) `shouldEqual` key''
413− key''' <- IDBObjectStore.add store "patate" (Just "key")
414− (toKey "key") `shouldEqual` key'''
417− key'''' <- IDBObjectStore.add store "patate" (Just date)
418− (toKey date) `shouldEqual` key''''
421− key''''' <- IDBObjectStore.add store "patate" (Just $ toKey [ 14, 42 ])
422− (toKey [ 14, 42 ]) `shouldEqual` key'''''
428− { storeParams: IDBDatabase.defaultParameters
429− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
430− key <- IDBObjectStore.add store "patate" (Just 14)
431− _ <- IDBObjectStore.clear store
432− val <- IDBObjectStore.get store (IDBKeyRange.only key)
433− val `shouldEqual` (Nothing :: Maybe String)
439− { storeParams: IDBDatabase.defaultParameters
440− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
441− _ <- IDBObjectStore.add store "patate" (Just 14)
442− _ <- IDBObjectStore.add store "autruche" (Just 42)
443− n <- IDBObjectStore.count store Nothing
450− { storeParams: IDBDatabase.defaultParameters
451− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
452− key <- IDBObjectStore.add store "patate" (Just 14)
453− mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 14)
454− mkey `shouldEqual` (Just key)
456− mkey' <- IDBObjectStore.getKey store (IDBKeyRange.only 42)
457− mkey' `shouldEqual` none
461− it "getAllKeys()" do
463− { storeParams: IDBDatabase.defaultParameters
464− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
465− key1 <- IDBObjectStore.add store "patate" (Just 14)
466− key2 <- IDBObjectStore.add store "autruche" (Just 42)
467− key3 <- IDBObjectStore.add store 14 (Just 1337)
470− keys <- IDBObjectStore.getAllKeys store Nothing Nothing
471− keys `shouldEqual` [ key1, key2, key3 ]
474− keys' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
475− keys' `shouldEqual` [ key2, key3 ]
478− keys'' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
479− keys'' `shouldEqual` [ key1, key2 ]
482− keys''' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
483− keys''' `shouldEqual` [ key1, key2 ]
487− it "openCursor()" do
490− { onSuccess: const $ pure unit
491− , onError: show >>> fail >>> launchAff'
492− , onComplete: pure unit
495− { storeParams: IDBDatabase.defaultParameters
496− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
497− _ <- IDBObjectStore.openCursor store Nothing Next cb
498− _ <- IDBObjectStore.openCursor store Nothing NextUnique cb
499− _ <- IDBObjectStore.openCursor store Nothing Prev cb
500− _ <- IDBObjectStore.openCursor store Nothing PrevUnique cb
501− _ <- IDBObjectStore.openCursor store (Just $ IDBKeyRange.upperBound 1 true) Next cb
506− it "openKeyCursor()" do
509− { onSuccess: const $ pure unit
510− , onError: show >>> fail >>> launchAff'
511− , onComplete: pure unit
514− { storeParams: IDBDatabase.defaultParameters
515− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
516− _ <- IDBObjectStore.openKeyCursor store Nothing Next cb
517− _ <- IDBObjectStore.openKeyCursor store Nothing NextUnique cb
518− _ <- IDBObjectStore.openKeyCursor store Nothing Prev cb
519− _ <- IDBObjectStore.openKeyCursor store Nothing PrevUnique cb
520− _ <- IDBObjectStore.openKeyCursor store (Just $ IDBKeyRange.lowerBound 1 true) Next cb
525− describe "IDBIndex" do
344+ describe "IDBObjectStore" do
527 tearDown db = do
346 tearDown db = do
528 IDBDatabase.close db
347 IDBDatabase.close db
529 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
348 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
530 pure unit
349 pure unit
532− setup
351+ setup { storeParams, onUpgradeNeeded } = do
534− . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
535− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
536− , values :: Array (Tuple value (Maybe Key))
537− , keyPath :: Array String
538− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
540− -> Aff { db :: Database, index :: Index, store :: ObjectStore }
541− setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
543− onUpgradeNeeded' var db tx _ = launchAff' do
352+ let onUpgradeNeeded' var db _ = launchAff' do
544− store <- IDBDatabase.createObjectStore db "store" storeParams
353+ store <- IDBDatabase.createObjectStore db "store" storeParams
545− _ <- traverse (uncurry (IDBObjectStore.add store)) values
546− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
547− liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
354+ liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure store)
548− AVar.put { db, index, store } var
355+ putVar var { db, store }
550− var <- AVar.empty
357+ var <- makeVar
551− _ <- IDBFactory.open "db" Nothing
358+ db <- IDBFactory.open "db" Nothing
552− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
359+ { onUpgradeNeeded : Just (onUpgradeNeeded' var)
553− , onBlocked: Nothing
360+ , onBlocked : Nothing
557− it "returns an IDBIndex and the properties are set correctly" do
558− { db, index } <- setup
559− { storeParams: IDBDatabase.defaultParameters
560− , indexParams: IDBObjectStore.defaultParameters
561− , onUpgradeNeeded: Nothing
565− IDBIndex.name index `shouldEqual` "index"
566− IDBIndex.keyPath index `shouldEqual` []
567− IDBIndex.unique index `shouldEqual` IDBObjectStore.defaultParameters.unique
568− IDBIndex.multiEntry index `shouldEqual` IDBObjectStore.defaultParameters.multiEntry
571− it "attempt to create an index that requires unique values on an object store already contains duplicates" do
572− let onAbort var = launchAff' (AVar.put true var)
575− res <- attempt $ setup
576− { storeParams: IDBDatabase.defaultParameters
581− , keyPath: [ "indexedProperty" ]
583− [ { indexedProperty: "bar" } :+: (Just $ toKey 1)
584− , { indexedProperty: "bar" } :+: (Just $ toKey 2)
586− , onUpgradeNeeded: Just $ \db tx _ -> launchAff' do
587− IDBTransaction.onAbort tx (onAbort txVar)
588− IDBDatabase.onAbort db (onAbort dbVar)
592− fail "expected abort"
594− shouldEqual true =<< AVar.take txVar
595− shouldEqual true =<< AVar.take dbVar
597− it "the index is usable right after being made" do
600− { keyPath: [ "key" ]
601− , autoIncrement: false
603− , indexParams: IDBObjectStore.defaultParameters
604− , keyPath: [ "indexedProperty" ]
606− [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
607− , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
608− , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
610− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
611− val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
612− ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
616− it "empty keyPath" do
618− { storeParams: IDBDatabase.defaultParameters
619− , indexParams: IDBObjectStore.defaultParameters
622− [ "object_1" :+: (Just $ toKey 1)
623− , "object_2" :+: (Just $ toKey 2)
624− , "object_3" :+: (Just $ toKey 3)
626− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
627− val <- IDBIndex.get index (IDBKeyRange.only "object_3")
628− val `shouldEqual` (Just "object_3")
632− it "index can be valid keys [date]" do
633− date <- liftEffect $ toDateTime <$> now
636− { keyPath: [ "key" ]
637− , autoIncrement: false
639− , indexParams: IDBObjectStore.defaultParameters
642− [ { key: "date", i: (toKey date) } :+: Nothing
644− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
645− val <- IDBIndex.get index (IDBKeyRange.only date)
646− ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
650− it "index can be valid keys [num]" do
654− { keyPath: [ "key" ]
655− , autoIncrement: false
657− , indexParams: IDBObjectStore.defaultParameters
660− [ { key: "num", i: (toKey num) } :+: Nothing
662− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
663− val <- IDBIndex.get index (IDBKeyRange.only num)
664− ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
668− it "index can be valid keys [array]" do
669− let array = [ "patate", "autruche" ]
672− { keyPath: [ "key" ]
673− , autoIncrement: false
675− , indexParams: IDBObjectStore.defaultParameters
678− [ { key: "array", i: (toKey array) } :+: Nothing
680− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
681− val <- IDBIndex.get index (IDBKeyRange.only array)
682− ((\r -> r.key) <$> val) `shouldEqual` (Just "array")
686− it "openKeyCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
687− res <- attempt $ setup
688− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
689− , indexParams: IDBObjectStore.defaultParameters
690− , keyPath: [ "indexedProperty" ]
692− [ { key: 14, indexedProperty: "patate" } :+: Nothing
694− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
697− { onSuccess: const $ pure unit
698− , onError: show >>> fail >>> launchAff'
699− , onComplete: pure unit
701− IDBTransaction.onAbort tx (pure unit)
702− IDBDatabase.onAbort db (pure unit)
703− IDBTransaction.abort tx
704− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
706− Right _ -> fail "expected InvalidStateError"
707− Left err -> name err `shouldEqual` "InvalidStateError"
710− Right _ -> fail "expected InvalidStateError"
713− it "openKeyCursor() - throw TransactionInactiveError on aborted transaction" do
715− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
716− , indexParams: IDBObjectStore.defaultParameters
717− , keyPath: [ "indexedProperty" ]
719− [ { key: 14, indexedProperty: "patate" } :+: Nothing
721− , onUpgradeNeeded: Nothing
725− { onSuccess: const $ pure unit
726− , onError: show >>> fail >>> launchAff'
727− , onComplete: pure unit
729− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
730− store <- IDBTransaction.objectStore tx "store"
731− index <- IDBObjectStore.index store "index"
732− IDBTransaction.onAbort tx (pure unit)
733− IDBTransaction.abort tx
734− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
736− Right _ -> fail "expected TransactionInactiveError"
737− Left err -> name err `shouldEqual` "TransactionInactiveError"
741− it "openKeyCursor() - throw InvalidStateError when the index is deleted" do
743− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
744− , indexParams: IDBObjectStore.defaultParameters
745− , keyPath: [ "indexedProperty" ]
747− [ { key: 14, indexedProperty: "patate" } :+: Nothing
749− , onUpgradeNeeded: Just $ \_ tx index -> launchAff' do
752− { onSuccess: const $ pure unit
753− , onError: show >>> fail >>> launchAff'
754− , onComplete: pure unit
756− store <- IDBTransaction.objectStore tx "store"
757− IDBObjectStore.deleteIndex store "index"
758− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
760− Right _ -> fail "expected InvalidStateError"
761− Left err -> name err `shouldEqual` "InvalidStateError"
766− it "openCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
767− res <- attempt $ setup
768− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
769− , indexParams: IDBObjectStore.defaultParameters
770− , keyPath: [ "indexedProperty" ]
772− [ { key: 14, indexedProperty: "patate" } :+: Nothing
774− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
777− { onSuccess: const $ pure unit
778− , onError: show >>> fail >>> launchAff'
779− , onComplete: pure unit
781− IDBTransaction.onAbort tx (pure unit)
782− IDBDatabase.onAbort db (pure unit)
783− IDBTransaction.abort tx
784− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
786− Right _ -> fail "expected InvalidStateError"
787− Left err -> name err `shouldEqual` "InvalidStateError"
790− Right _ -> fail "expected InvalidStateError"
793− it "openCursor() - throw TransactionInactiveError on aborted transaction" do
795− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
796− , indexParams: IDBObjectStore.defaultParameters
797− , keyPath: [ "indexedProperty" ]
799− [ { key: 14, indexedProperty: "patate" } :+: Nothing
801− , onUpgradeNeeded: Nothing
805− { onSuccess: const $ pure unit
806− , onError: show >>> fail >>> launchAff'
807− , onComplete: pure unit
809− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
810− store <- IDBTransaction.objectStore tx "store"
811− index <- IDBObjectStore.index store "index"
812− IDBTransaction.onAbort tx (pure unit)
813− IDBTransaction.abort tx
814− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
816− Right _ -> fail "expected TransactionInactiveError"
817− Left err -> name err `shouldEqual` "TransactionInactiveError"
821− it "openCursor() - throw InvalidStateError when the index is deleted" do
823− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
824− , indexParams: IDBObjectStore.defaultParameters
825− , keyPath: [ "indexedProperty" ]
827− [ { key: 14, indexedProperty: "patate" } :+: Nothing
829− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
832− { onSuccess: const $ pure unit
833− , onError: show >>> fail >>> launchAff'
834− , onComplete: pure unit
836− store <- IDBTransaction.objectStore tx "store"
837− IDBObjectStore.deleteIndex store "index"
838− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
840− Right _ -> fail "expected InvalidStateError"
841− Left err -> name err `shouldEqual` "InvalidStateError"
844− tearDown db
363+ takeVar var
846− it "getKey() - multiEntry - adding keys" do
365+ it "add()" do
847− { db } <- setup
366+ date <- liftEff $ toDateTime <$> now
848− { storeParams: IDBDatabase.defaultParameters
849− , indexParams: { unique: false, multiEntry: true }
850− , keyPath: [ "name" ]
852− [ { name: [ "patate", "autruche" ] } :+: (Just $ toKey 1)
853− , { name: [ "bob" ] } :+: (Just $ toKey 2)
855− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
856− key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
857− key `shouldEqual` (Just $ toKey 1)
859− key' <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
860− key' `shouldEqual` (Just $ toKey 1)
862− key'' <- IDBIndex.getKey index (IDBKeyRange.only "bob")
863− key'' `shouldEqual` (Just $ toKey 2)
867− it "get() - returns the record with the first key in the range" do
868− { db } <- setup
367+ { db } <- setup
869− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
368+ { storeParams: { autoIncrement: true, keyPath: [] }
369+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
371+ key <- IDBObjectStore.add store "patate" (Nothing :: Maybe Key)
372+ (toKey 1) `shouldEqual` key
375+ key <- IDBObjectStore.add store "patate" (Just 14)
376+ (toKey 14) `shouldEqual` key
379+ key <- IDBObjectStore.add store "patate" (Just 14.42)
380+ (toKey 14.42) `shouldEqual` key
383+ key <- IDBObjectStore.add store "patate" (Just "key")
384+ (toKey "key") `shouldEqual` key
387+ key <- IDBObjectStore.add store "patate" (Just date)
388+ (toKey date) `shouldEqual` key
391+ key <- IDBObjectStore.add store "patate" (Just $ toKey [14, 42])
392+ (toKey [14, 42]) `shouldEqual` key
398+ { storeParams: IDBObjectStore.defaultParameters
399+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
400+ key <- IDBObjectStore.add store "patate" (Just 14)
401+ _ <- IDBObjectStore.clear store
402+ val <- IDBObjectStore.get store (IDBKeyRange.only key)
403+ val `shouldEqual` (Nothing :: Maybe String)
409+ { storeParams: IDBObjectStore.defaultParameters
410+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
411+ key <- IDBObjectStore.add store "patate" (Just 14)
412+ key <- IDBObjectStore.add store "autruche" (Just 42)
413+ n <- IDBObjectStore.count store Nothing
870− , indexParams: IDBObjectStore.defaultParameters
420+ { storeParams: IDBObjectStore.defaultParameters
871− , keyPath: [ "indexedProperty" ]
421+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
872− , values:
422+ key <- IDBObjectStore.add store "patate" (Just 14)
873− [ { key: 14, indexedProperty: "patate" } :+: Nothing
423+ mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 14)
874− , { key: 42, indexedProperty: "autruche" } :+: Nothing
424+ mkey `shouldEqual` (Just key)
875− , { key: 1337, indexedProperty: "baguette" } :+: Nothing
425+
876− ]
426+ mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 42)
877− , onUpgradeNeeded: Nothing
427+ mkey `shouldEqual` (Nothing :: Maybe Key)
880− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
430+
881− store <- IDBTransaction.objectStore tx "store"
431+ it "getAllKeys()" do
433+ { storeParams: IDBObjectStore.defaultParameters
434+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
435+ key1 <- IDBObjectStore.add store "patate" (Just 14)
436+ key2 <- IDBObjectStore.add store "autruche" (Just 42)
437+ key3 <- IDBObjectStore.add store 14 (Just 1337)
440+ keys <- IDBObjectStore.getAllKeys store Nothing Nothing
441+ keys `shouldEqual` [key1, key2, key3]
444+ keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
445+ keys `shouldEqual` [key2, key3]
448+ keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
449+ keys `shouldEqual` [key1, key2]
452+ keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
453+ keys `shouldEqual` [key1, key2]
457+ it "openCursor()" do
459+ { storeParams: IDBObjectStore.defaultParameters
460+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
461+ _ <- IDBObjectStore.openCursor store Nothing Next
462+ _ <- IDBObjectStore.openCursor store Nothing NextUnique
882− index <- IDBObjectStore.index store "index"
463+ _ <- IDBObjectStore.openCursor store Nothing Prev
883− val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
464+ _ <- IDBObjectStore.openCursor store Nothing PrevUnique
884− ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
465+ _ <- IDBObjectStore.openCursor store (Just $ IDBKeyRange.upperBound 1 true) Next
470+ it "openKeyCursor()" do
472+ { storeParams: IDBObjectStore.defaultParameters
473+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
474+ _ <- IDBObjectStore.openKeyCursor store Nothing Next
475+ _ <- IDBObjectStore.openKeyCursor store Nothing NextUnique
476+ _ <- IDBObjectStore.openKeyCursor store Nothing Prev
477+ _ <- IDBObjectStore.openKeyCursor store Nothing PrevUnique
478+ _ <- IDBObjectStore.openKeyCursor store (Just $ IDBKeyRange.lowerBound 1 true) Next
886− tearDown db
481+ tearDown db
888− describe "IDBCursor" do
483+ describe "IDBIndex" do
890 tearDown db = do
485 tearDown db = do
891 IDBDatabase.close db
486 IDBDatabase.close db
892 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
487 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
893 pure unit
488 pure unit
896− :: forall value
490+ setup :: forall value e e'.
897− . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
491+ { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
898− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
492+ , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
899− , values :: Array (Tuple value (Maybe Key))
493+ , values :: Array (Tuple value (Maybe Key))
900− , keyPath :: Array String
494+ , keyPath :: Array String
901− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
495+ , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Eff (idb :: IDB, avar :: AVAR, exception :: EXCEPTION | e') Unit)
903− -> Aff { db :: Database, index :: Index, store :: ObjectStore }
496+ } -> Aff (idb :: IDB, avar :: AVAR | e) { db :: Database, index :: Index, store :: ObjectStore }
904 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
497 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
906− onUpgradeNeeded' var db tx _ = launchAff' do
498+ let onUpgradeNeeded' var db tx = launchAff' do
907− store <- IDBDatabase.createObjectStore db "store" storeParams
499+ store <- IDBDatabase.createObjectStore db "store" storeParams
908− _ <- traverse (uncurry (IDBObjectStore.add store)) values
500+ _ <- traverse (uncurry (IDBObjectStore.add store)) values
909− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
501+ index <- IDBObjectStore.createIndex store "index" keyPath indexParams
910− liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
502+ liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
911− AVar.put { db, index, store } var
503+ putVar var { db, index, store }
913− var <- AVar.empty
505+ var <- makeVar
914− db <- IDBFactory.open "db" Nothing
506+ db <- IDBFactory.open "db" Nothing
915− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
507+ { onUpgradeNeeded : Just (onUpgradeNeeded' var)
916− , onBlocked: Nothing
508+ , onBlocked : Nothing
920− it "continue() - iterate to the next record" do
922− { storeParams: IDBDatabase.defaultParameters
923− , indexParams: IDBObjectStore.defaultParameters
926− [ "cupcake" :+: (Just $ toKey 4)
927− , "pancake" :+: (Just $ toKey 2)
928− , "pie" :+: (Just $ toKey 1)
929− , "pie" :+: (Just $ toKey 3)
931− , onUpgradeNeeded: Nothing
935− { onComplete: launchAff' do
938− , onError: \error -> launchAff' do
939− fail $ "unexpected error: " <> show error
941− , onSuccess: \cursor -> launchAff' do
942− vals <- AVar.take vvals
943− pure (IDBCursor.value cursor) >>= shouldEqual (maybe "" _.v $ head vals)
944− IDBCursor.primaryKey cursor >>= shouldEqual (maybe (toKey 0) _.k $ head vals)
945− AVar.put (drop 1 vals) vvals
946− IDBCursor.continue cursor none
950− [ { v: "pie", k: toKey 1 }
951− , { v: "pancake", k: toKey 2 }
952− , { v: "pie", k: toKey 3 }
953− , { v: "cupcake", k: toKey 4 }
955− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
956− store <- IDBTransaction.objectStore tx "store"
957− IDBObjectStore.openCursor store Nothing Next (cb vdone vvals)
961− it "continue() - attempt to iterate in the wrong direction" do
963− { storeParams: IDBDatabase.defaultParameters
964− , indexParams: IDBObjectStore.defaultParameters
967− [ "cupcake" :+: (Just $ toKey 4)
968− , "pancake" :+: (Just $ toKey 2)
969− , "pie" :+: (Just $ toKey 1)
970− , "pie" :+: (Just $ toKey 3)
972− , onUpgradeNeeded: Nothing
976− { onComplete: launchAff' do
977− fail $ "shouldn't complete"
979− , onError: \error -> launchAff' do
980− fail $ "unexpected error: " <> show error
982− , onSuccess: \cursor -> launchAff' do
983− res <- attempt $ IDBCursor.continue cursor (Just 1)
986− name err `shouldEqual` "DataError"
989− fail "expected continue to fail"
991− vdone <- AVar.empty
510+ takeVar var
992− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
511+
513+ it "returns an IDBIndex and the properties are set correctly" do
514+ { db, index } <- setup
515+ { storeParams : IDBObjectStore.defaultParameters
516+ , indexParams : IDBIndex.defaultParameters
517+ , onUpgradeNeeded : Nothing
521+ IDBIndex.name index `shouldEqual` "index"
522+ IDBIndex.keyPath index `shouldEqual` []
523+ IDBIndex.unique index `shouldEqual` IDBIndex.defaultParameters.unique
524+ IDBIndex.multiEntry index `shouldEqual` IDBIndex.defaultParameters.multiEntry
527+ it "attempt to create an index that requires unique values on an object store already contains duplicates" do
528+ let onAbort var = launchAff' (putVar var true)
531+ res <- attempt $ setup
532+ { storeParams : IDBObjectStore.defaultParameters
533+ , indexParams : { unique : true
534+ , multiEntry : false
536+ , keyPath : ["indexedProperty"]
537+ , values : [ { indexedProperty: "bar" } :+: (Just $ toKey 1)
538+ , { indexedProperty: "bar" } :+: (Just $ toKey 2)
540+ , onUpgradeNeeded : Just $ \db tx _ -> launchAff' do
993− store <- IDBTransaction.objectStore tx "store"
541+ IDBTransaction.onAbort tx (onAbort txVar)
994− IDBObjectStore.openCursor store Nothing Next (cb vdone)
542+ IDBDatabase.onAbort db (onAbort dbVar)
995− AVar.take vdone
543+ }
996− tearDown db
544+ case res of
998− it "advance() - iterate cursor number of times specified by count" do
546+ fail "expected abort"
548+ shouldEqual true =<< takeVar txVar
549+ shouldEqual true =<< takeVar dbVar
552+ it "the index is usable right after being made" do
999− { db } <- setup
553+ { db } <- setup
554+ { storeParams : { keyPath : ["key"]
1000− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
555+ , autoIncrement : false
1001− , indexParams: IDBObjectStore.defaultParameters
557+ , indexParams : IDBIndex.defaultParameters
1002− , keyPath: []
558+ , keyPath : ["indexedProperty"]
1003− , values:
559+ , values : [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
1004− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
560+ , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
1005− , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
561+ , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
1006− , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
1007− , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
1009− , onUpgradeNeeded: Nothing
563+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1010− }
564+ val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
1011− let
565+ ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
1012− cb vdone vjump =
566+ }
1013− { onComplete: launchAff' do
567+ tearDown db
1014− AVar.put unit vdone
568+
1015−
569+ it "empty keyPath" do
1016− , onError: \error -> launchAff' do
570+ { db } <- setup
1017− fail $ "unexpected error: " <> show error
571+ { storeParams : IDBObjectStore.defaultParameters
1018−
572+ , indexParams : IDBIndex.defaultParameters
1019− , onSuccess: \cursor -> launchAff' do
573+ , keyPath : []
1020− jump <- AVar.take vjump
574+ , values : [ "object_1" :+: (Just $ toKey 1)
1021− if jump then do
575+ , "object_2" :+: (Just $ toKey 2)
1022− IDBCursor.advance cursor 3
576+ , "object_3" :+: (Just $ toKey 3)
1024− let value = IDBCursor.value cursor
578+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1025− value.pKey `shouldEqual` "pkey_3"
579+ val <- IDBIndex.get index (IDBKeyRange.only "object_3")
1026− value.iKey `shouldEqual` "ikey_3"
580+ val `shouldEqual` (Just "object_3")
1027− IDBCursor.continue cursor none
581+ }
1028− AVar.put false vjump
1030− vdone <- AVar.empty
1031− vjump <- AVar.new true
1032− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
1033− store <- IDBTransaction.objectStore tx "store"
1034− IDBObjectStore.openCursor store Nothing Next (cb vdone vjump)
1036− tearDown db
582+ tearDown db
1038− it "delete() - remove a record from the object store" do
584+ it "index can be valid keys [date]" do
585+ date <- liftEff $ toDateTime <$> now
1039− { db } <- setup
586+ { db } <- setup
587+ { storeParams : { keyPath: ["key"]
1040− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
588+ , autoIncrement: false
1041− , indexParams: IDBObjectStore.defaultParameters
590+ , indexParams : IDBIndex.defaultParameters
1042− , keyPath: []
591+ , keyPath : ["i"]
1043− , values:
592+ , values : [ { key: "date", i: (toKey date) } :+: Nothing
1044− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
593+ ]
1045− , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
594+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1046− , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
595+ val <- IDBIndex.get index (IDBKeyRange.only date)
1047− , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
596+ ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
600+ it "index can be valid keys [num]" do
603+ { storeParams : { keyPath: ["key"]
604+ , autoIncrement: false
606+ , indexParams : IDBIndex.defaultParameters
608+ , values : [ { key: "num", i: (toKey num) } :+: Nothing
1049− , onUpgradeNeeded: Nothing
610+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1050− }
611+ val <- IDBIndex.get index (IDBKeyRange.only num)
1051− let
612+ ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
1052− cb vdone store =
613+ }
1053− { onComplete: launchAff' do
614+ tearDown db
1054− mval <- map _.pKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
615+
1055− mval `shouldEqual` (Nothing :: Maybe String)
616+ it "index can be valid keys [array]" do
1056− AVar.put unit vdone
617+ let array = ["patate", "autruche"]
1057−
618+ { db } <- setup
1058− , onError: \error -> launchAff' do
619+ { storeParams : { keyPath: ["key"]
1059− fail $ "unexpected error: " <> show error
620+ , autoIncrement: false
1061− , onSuccess: \cursor -> launchAff' do
622+ , indexParams : IDBIndex.defaultParameters
1062− let value = IDBCursor.value cursor
623+ , keyPath : ["i"]
624+ , values : [ { key: "array", i: (toKey array) } :+: Nothing
626+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
627+ val <- IDBIndex.get index (IDBKeyRange.only array)
628+ ((\r -> r.key) <$> val) `shouldEqual` (Just "array")
632+ it "openKeyCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
633+ res <- attempt $ setup
634+ { storeParams : { keyPath: ["key"], autoIncrement: false }
635+ , indexParams : IDBIndex.defaultParameters
636+ , keyPath : ["indexedProperty"]
637+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
639+ , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
640+ IDBTransaction.onAbort tx (pure unit)
641+ IDBDatabase.onAbort db (pure unit)
642+ IDBTransaction.abort tx
643+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next
645+ Right _ -> fail "expected InvalidStateError"
646+ Left err -> message err `shouldEqual` "InvalidStateError"
649+ Right _ -> fail "expected InvalidStateError"
652+ it "openKeyCursor() - throw TransactionInactiveError on aborted transaction" do
654+ { storeParams : { keyPath: ["key"], autoIncrement: false }
655+ , indexParams : IDBIndex.defaultParameters
656+ , keyPath : ["indexedProperty"]
657+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
659+ , onUpgradeNeeded : Nothing
662+ tx <- IDBDatabase.transaction db ["store"] ReadOnly
663+ store <- IDBTransaction.objectStore tx "store"
664+ index <- IDBObjectStore.index store "index"
665+ IDBTransaction.onAbort tx (pure unit)
666+ IDBTransaction.abort tx
667+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next
669+ Right _ -> fail "expected TransactionInactiveError"
670+ Left err -> message err `shouldEqual` "TransactionInactiveError"
674+ it "openKeyCursor() - throw InvalidStateError when the index is deleted" do
676+ { storeParams : { keyPath: ["key"], autoIncrement: false }
677+ , indexParams : IDBIndex.defaultParameters
678+ , keyPath : ["indexedProperty"]
679+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
681+ , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
682+ store <- IDBTransaction.objectStore tx "store"
683+ IDBObjectStore.deleteIndex store "index"
684+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next
686+ Right _ -> fail "expected InvalidStateError"
687+ Left err -> message err `shouldEqual` "InvalidStateError"
692+ it "openCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
693+ res <- attempt $ setup
694+ { storeParams : { keyPath: ["key"], autoIncrement: false }
695+ , indexParams : IDBIndex.defaultParameters
696+ , keyPath : ["indexedProperty"]
697+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
699+ , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
700+ IDBTransaction.onAbort tx (pure unit)
701+ IDBDatabase.onAbort db (pure unit)
702+ IDBTransaction.abort tx
703+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next
705+ Right _ -> fail "expected InvalidStateError"
706+ Left err -> message err `shouldEqual` "InvalidStateError"
709+ Right _ -> fail "expected InvalidStateError"
712+ it "openCursor() - throw TransactionInactiveError on aborted transaction" do
714+ { storeParams : { keyPath: ["key"], autoIncrement: false }
715+ , indexParams : IDBIndex.defaultParameters
716+ , keyPath : ["indexedProperty"]
717+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
719+ , onUpgradeNeeded : Nothing
722+ tx <- IDBDatabase.transaction db ["store"] ReadOnly
723+ store <- IDBTransaction.objectStore tx "store"
724+ index <- IDBObjectStore.index store "index"
725+ IDBTransaction.onAbort tx (pure unit)
726+ IDBTransaction.abort tx
727+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next
729+ Right _ -> fail "expected TransactionInactiveError"
730+ Left err -> message err `shouldEqual` "TransactionInactiveError"
734+ it "openCursor() - throw InvalidStateError when the index is deleted" do
736+ { storeParams : { keyPath: ["key"], autoIncrement: false }
737+ , indexParams : IDBIndex.defaultParameters
738+ , keyPath : ["indexedProperty"]
739+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
741+ , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
742+ store <- IDBTransaction.objectStore tx "store"
743+ IDBObjectStore.deleteIndex store "index"
744+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next
746+ Right _ -> fail "expected InvalidStateError"
747+ Left err -> message err `shouldEqual` "InvalidStateError"
752+ it "getKey() - multiEntry - adding keys" do
754+ { storeParams : IDBObjectStore.defaultParameters
755+ , indexParams : { unique: false, multiEntry: true }
756+ , keyPath : ["name"]
757+ , values : [ { name: ["patate", "autruche"] } :+: (Just $ toKey 1)
758+ , { name: ["bob"] } :+: (Just $ toKey 2)
760+ , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
761+ key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
1063− value.pKey `shouldEqual` "pkey_0"
762+ key `shouldEqual` (Just $ toKey 1)
1064− IDBCursor.delete cursor
763+
1065− IDBCursor.advance cursor 4
764+ key <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
1066− }
765+ key `shouldEqual` (Just $ toKey 1)
1067− vdone <- AVar.empty
766+
1068− tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
767+ key <- IDBIndex.getKey index (IDBKeyRange.only "bob")
1069− store <- IDBTransaction.objectStore tx "store"
768+ key `shouldEqual` (Just $ toKey 2)
1070− IDBObjectStore.openCursor store Nothing Next (cb vdone store)
769+ }
1072− tearDown db
770+ tearDown db
1074− it "update() - modify a record in the object store" do
772+
773+ it "get() - returns the record with the first key in the range" do
1075− { db } <- setup
774+ { db } <- setup
1076− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
775+ { storeParams : { keyPath: ["key"], autoIncrement: false }
1077− , indexParams: IDBObjectStore.defaultParameters
776+ , indexParams : IDBIndex.defaultParameters
1078− , keyPath: []
777+ , keyPath : ["indexedProperty"]
1079− , values:
778+ , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
1080− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
779+ , { key: 42, indexedProperty: "autruche" } :+: Nothing
780+ , { key: 1337, indexedProperty: "baguette" } :+: Nothing
1082− , onUpgradeNeeded: Nothing
782+ , onUpgradeNeeded : Nothing
1085− cb vdone store =
785+ tx <- IDBDatabase.transaction db ["store"] ReadOnly
1086− { onComplete: launchAff' do
786+ store <- IDBTransaction.objectStore tx "store"
787+ index <- IDBObjectStore.index store "index"
1087− mval <- map _.iKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
788+ val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
1088− mval `shouldEqual` (Just "patate")
789+ ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
1089− AVar.put unit vdone
790+
1091− , onError: \error -> launchAff' do
1092− fail $ "unexpected error: " <> show error
1094− , onSuccess: \cursor -> launchAff' do
1095− let value = IDBCursor.value cursor
1096− value.pKey `shouldEqual` "pkey_0"
1097− key <- IDBCursor.update cursor { pKey: "pkey_0", iKey: "patate" }
1098− key `shouldEqual` toKey "pkey_0"
1099− IDBCursor.advance cursor 4
1101− vdone <- AVar.empty
1102− tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
1103− store <- IDBTransaction.objectStore tx "store"
1104− IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1108− it "update() - throw ReadOnlyError after update on ReadOnly transaction" do
1110− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1111− , indexParams: IDBObjectStore.defaultParameters
1114− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1116− , onUpgradeNeeded: Nothing
1120− { onComplete: launchAff' do
1121− fail $ "shouldn't complete"
1123− , onError: \error -> launchAff' do
1124− fail $ "unexpected error: " <> show error
1126− , onSuccess: \cursor -> launchAff' do
1127− res <- attempt $ IDBCursor.update cursor "patate"
1130− name err `shouldEqual` "ReadOnlyError"
1131− AVar.put unit vdone
1133− fail $ "expected ReadOnlyError"
1135− vdone <- AVar.empty
1136− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
1137− store <- IDBTransaction.objectStore tx "store"
1138− IDBObjectStore.openCursor store Nothing Next (cb vdone)