@@ -2,790 +2,1140 @@ module Test.Main where
3import Prelude
3import Prelude
5−import Control.Monad.Aff (Aff, launchAff, forkAff, delay, attempt)
5+import Data.Array (head, drop)
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)
12−import Data.Date as Date
6+import Data.Date as Date
13−import Data.DateTime as DateTime
7+import Data.DateTime (DateTime(..), Time(..))
14−import Data.DateTime (DateTime(..), Time(..))
15−import Data.DateTime.Instant (toDateTime)
8+import Data.DateTime.Instant (toDateTime)
16−import Data.Either (Either(..))
9+import Data.Either (Either(..))
17−import Data.Enum (toEnum)
10+import Data.Enum (toEnum)
18−import Data.Maybe (Maybe(..), isNothing, maybe)
11+import Data.Maybe (Maybe(..), isNothing, maybe)
19−import Data.Time.Duration (Milliseconds(..))
12+import Data.Time.Duration (Milliseconds(..))
20−import Data.Traversable (traverse)
13+import Data.Traversable (traverse)
21−import Data.Tuple (Tuple(..), uncurry)
14+import Data.Tuple (Tuple(..), uncurry)
22−import Test.Spec (describe, describe, it, it)
15+import Database.IndexedDB.Core (CursorDirection(..), Database, Index, ObjectStore, Transaction, TransactionMode(..))
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)
23−import Test.Spec.Assertions (shouldEqual, fail)
33+import Test.Spec.Assertions (shouldEqual, fail)
24−import Test.Spec.Mocha (MOCHA, runMocha)
34+import Test.Spec.Reporter (consoleReporter)
25−
35+import Test.Spec.Runner (runSpec)
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
37infixr 7 Tuple as :+:
37infixr 7 Tuple as :+:
39−launchAff' :: forall a e. Aff e a -> Eff (exception :: EXCEPTION | e) Unit
39+launchAff' :: forall a. Aff a -> Effect Unit
40−launchAff' aff =
40+launchAff' =
41− pure unit <* (launchAff aff)
41+ launchAff_ <<< void
43+modifyAVar :: forall a. (a -> a) -> AVar a -> Aff Unit
43−-- main :: forall eff. Eff (now :: NOW, mocha :: MOCHA, idb :: IDB, exception :: EXCEPTION, avar :: AVAR | eff) Unit
48+main :: Effect Unit
44−main = runMocha do
49+main = do
50+ launchAff_ $ runSpec [ consoleReporter ] $ do
45− describe "IDBFactory" do
51+ describe "IDBFactory" do
47 tearDown name version db = do
53 tearDown name version db = do
48 IDBDatabase.close db
54 IDBDatabase.close db
49 version' <- IDBFactory.deleteDatabase name
55 version' <- IDBFactory.deleteDatabase name
56+ liftEffect $ log $ show version'
50 version' `shouldEqual` version
57 version' `shouldEqual` version
52− it "open default" do
59+ it "open default" do
53− let name = "db-default"
61+ name = "db-default"
54 version = 1
62 version = 1
55− db <- IDBFactory.open name Nothing
63+ db <- IDBFactory.open name Nothing
56− { onUpgradeNeeded : Nothing
64+ { onUpgradeNeeded: Nothing
57− , onBlocked : Nothing
65+ , onBlocked: Nothing
59− IDBDatabase.name db `shouldEqual` name
67+ IDBDatabase.name db `shouldEqual` name
60− tearDown name version db
68+ tearDown name version db
63− it "open specific version" do
70+ it "open specific version" do
64− let name = "db-specific"
72+ name = "db-specific"
65 version = 14
73 version = 14
66− db <- IDBFactory.open name (Just version)
74+ db <- IDBFactory.open name (Just version)
67− { onUpgradeNeeded : Nothing
75+ { onUpgradeNeeded: Nothing
68− , onBlocked : Nothing
76+ , onBlocked: Nothing
70− IDBDatabase.name db `shouldEqual` name
78+ IDBDatabase.name db `shouldEqual` name
71− tearDown name version db
79+ tearDown name version db
74− it "open specific version -> close -> open latest" do
81+ it "open specific version -> close -> open latest" do
75− let name = "db-latest"
83+ name = "db-latest"
76 version = 14
84 version = 14
77− db <- IDBFactory.open name (Just version)
85+ db01 <- IDBFactory.open name (Just version)
78− { onUpgradeNeeded : Nothing
86+ { onUpgradeNeeded: Nothing
79− , onBlocked : Nothing
87+ , onBlocked: Nothing
81− IDBDatabase.name db `shouldEqual` name
89+ IDBDatabase.name db01 `shouldEqual` name
82− IDBDatabase.close db
90+ IDBDatabase.close db01
83− db <- IDBFactory.open name Nothing
91+ db02 <- IDBFactory.open name Nothing
84− { onUpgradeNeeded : Nothing
92+ { onUpgradeNeeded: Nothing
85− , onBlocked : Nothing
93+ , onBlocked: Nothing
87− tearDown name version db
95+ tearDown name version db02
90− it "open + onUpgradeNeed" do
97+ it "open + onUpgradeNeed" do
91− let name = "db-upgrade-needed"
99+ name = "db-upgrade-needed"
92 version = 1
100 version = 1
93− callback var db _ = do
101+ callback (Tuple varName varVersion) db _ { oldVersion } = do
94− _ <- launchAff $ modifyVar (const $ IDBDatabase.name db) var
102+ _ <- launchAff $ modifyAVar (const $ IDBDatabase.name db) varName
103+ _ <- launchAff $ modifyAVar (const $ oldVersion) varVersion
95 pure unit
104 pure unit
96− var <- makeVar' "-"
105+ varName <- AVar.new "-"
106+ varVersion <- AVar.new (-1)
97− db <- IDBFactory.open name Nothing
107+ db <- IDBFactory.open name Nothing
98− { onUpgradeNeeded : Just (callback var)
108+ { onUpgradeNeeded: Just (callback (Tuple varName varVersion))
99− , onBlocked : Nothing
109+ , onBlocked: Nothing
101− name <- peekVar var
111+ name' <- AVar.read varName
112+ version' <- AVar.read varVersion
102− name `shouldEqual` name
113+ name' `shouldEqual` name
114+ version' `shouldEqual` 0
103− tearDown name version db
115+ tearDown name version db
106− it "open + onBlocked" do
117+ it "open + onBlocked" do
107− let name = "db-blocked"
119+ name = "db-blocked"
108 version = 14
120 version = 14
109 callback var = do
121 callback var = do
110− _ <- launchAff $ modifyVar (const $ "db-blocked") var
122+ _ <- launchAff $ modifyAVar (const $ "db-blocked") var
111 pure unit
123 pure unit
113− var <- makeVar' "-"
125+ var <- AVar.new "-"
114− db01 <- IDBFactory.open name Nothing
126+ db01 <- IDBFactory.open name Nothing
115− { onUpgradeNeeded : Nothing
127+ { onUpgradeNeeded: Nothing
116− , onBlocked : Nothing
128+ , onBlocked: Nothing
118− _ <- forkAff do
130+ _ <- forkAff do
119− delay (Milliseconds 100.0)
131+ delay (Milliseconds 100.0)
120− IDBDatabase.close db01
132+ IDBDatabase.close db01
122− db02 <- IDBFactory.open name (Just version)
134+ db02 <- IDBFactory.open name (Just version)
123− { onUpgradeNeeded : Nothing
135+ { onUpgradeNeeded: Nothing
124− , onBlocked : Just (callback var)
136+ , onBlocked: Just (callback var)
126− name <- peekVar var
138+ name' <- AVar.read var
127− name `shouldEqual` name
139+ name' `shouldEqual` name
128− tearDown name version db02
140+ tearDown name version db02
130− describe "IDBKeyRange" do
142+ describe "IDBKeyRange" do
131− it "only(int)" do
143+ it "only(int)" do
132− let key = 14
145+ key = 14
133 range = IDBKeyRange.only key
146 range = IDBKeyRange.only key
134− IDBKeyRange.includes range (toKey key) `shouldEqual` true
147+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
136− it "only(string)" do
149+ it "only(string)" do
137− let key = "patate"
151+ key = "patate"
138 range = IDBKeyRange.only key
152 range = IDBKeyRange.only key
139− IDBKeyRange.includes range (toKey key) `shouldEqual` true
153+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
141− it "only(float)" do
155+ it "only(float)" do
142− let key = 14.42
157+ key = 14.42
143 range = IDBKeyRange.only key
158 range = IDBKeyRange.only key
144− IDBKeyRange.includes range (toKey key) `shouldEqual` true
159+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
146− it "only(date)" do
161+ it "only(date)" do
147− let mkey = DateTime
163+ mkey = DateTime
148 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
164 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
149 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
165 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
151− case mkey of
167+ case mkey of
152− Nothing ->
168+ Nothing ->
153− fail "unable to create datetime"
169+ fail "unable to create datetime"
154− Just key -> do
170+ Just key -> do
155− let range = IDBKeyRange.only key
171+ let range = IDBKeyRange.only key
156− IDBKeyRange.includes range (toKey key) `shouldEqual` true
172+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
158− it "only([int])" do
174+ it "only([int])" do
159− let key = [14, 42]
176+ key = [ 14, 42 ]
160 range = IDBKeyRange.only key
177 range = IDBKeyRange.only key
161− IDBKeyRange.includes range (toKey key) `shouldEqual` true
178+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
163− it "only([string])" do
180+ it "only([string])" do
164− let key = ["patate", "autruche"]
182+ key = [ "patate", "autruche" ]
165 range = IDBKeyRange.only key
183 range = IDBKeyRange.only key
166− IDBKeyRange.includes range (toKey key) `shouldEqual` true
184+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
168− it "lowerBound(14, open)" do
186+ it "lowerBound(14, open)" do
169− let key = 14
188+ key = 14
170− open = true
189+ open = true
171 range = IDBKeyRange.lowerBound key open
190 range = IDBKeyRange.lowerBound key open
172− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
191+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
173− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
192+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
174− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
193+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
176− it "lowerBound(14, close)" do
195+ it "lowerBound(14, close)" do
177− let key = 14
197+ key = 14
178− open = false
198+ open = false
179 range = IDBKeyRange.lowerBound key open
199 range = IDBKeyRange.lowerBound key open
180− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
200+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
181− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
201+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
182− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
202+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
184− it "upperBound(14, open)" do
204+ it "upperBound(14, open)" do
185− let key = 14
206+ key = 14
186− open = true
207+ open = true
187 range = IDBKeyRange.upperBound key open
208 range = IDBKeyRange.upperBound key open
188− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
209+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
189− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
210+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
190− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
211+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
192− it "upperBound(14, close)" do
213+ it "upperBound(14, close)" do
193− let key = 14
215+ key = 14
194− open = false
216+ open = false
195 range = IDBKeyRange.upperBound key open
217 range = IDBKeyRange.upperBound key open
196− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
218+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
197− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
219+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
198− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
220+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
200− it "bound(42, 14, open, open) => Nothing" do
222+ it "bound(42, 14, open, open) => Nothing" do
201− let lower = 42
224+ lower = 42
202− upper = 14
225+ upper = 14
203 lowerOpen = true
226 lowerOpen = true
204 upperOpen = true
227 upperOpen = true
205− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
228+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
206− isNothing mrange `shouldEqual` true
229+ isNothing mrange `shouldEqual` true
208− it "bound(14, 42, open, open)" do
231+ it "bound(14, 42, open, open)" do
209− let lower = 14
233+ lower = 14
210− upper = 42
234+ upper = 42
211 lowerOpen = true
235 lowerOpen = true
212 upperOpen = true
236 upperOpen = true
213− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
237+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
214− case mrange of
238+ case mrange of
215− Nothing ->
239+ Nothing ->
216− fail "invalid range provided"
240+ fail "invalid range provided"
217− Just range -> do
241+ Just range -> do
218− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
242+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
219− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
243+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
220− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
244+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
221− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
245+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
222− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
246+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
223− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
247+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
225− it "bound(14, 42, open, close)" do
249+ it "bound(14, 42, open, close)" do
226− let lower = 14
251+ lower = 14
227− upper = 42
252+ upper = 42
228 lowerOpen = true
253 lowerOpen = true
229 upperOpen = false
254 upperOpen = false
230− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
255+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
231− case mrange of
256+ case mrange of
232− Nothing ->
257+ Nothing ->
233− fail "invalid range provided"
258+ fail "invalid range provided"
234− Just range -> do
259+ Just range -> do
235− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
260+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
236− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
261+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
237− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
262+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
238− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
263+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
239− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
264+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
240− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
265+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
242− it "bound(14, 42, close, open)" do
267+ it "bound(14, 42, close, open)" do
243− let lower = 14
269+ lower = 14
244− upper = 42
270+ upper = 42
245 lowerOpen = false
271 lowerOpen = false
246 upperOpen = true
272 upperOpen = true
247− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
273+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
248− case mrange of
274+ case mrange of
249− Nothing ->
275+ Nothing ->
250− fail "invalid range provided"
276+ fail "invalid range provided"
251− Just range -> do
277+ Just range -> do
252− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
278+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
253− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
279+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
254− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
280+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
255− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
281+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
256− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
282+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
257− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
283+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
259− it "bound(14, 42, close, close)" do
285+ it "bound(14, 42, close, close)" do
260− let lower = 14
287+ lower = 14
261− upper = 42
288+ upper = 42
262 lowerOpen = false
289 lowerOpen = false
263 upperOpen = false
290 upperOpen = false
264− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
291+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
265− case mrange of
292+ case mrange of
266− Nothing ->
293+ Nothing ->
267− fail "invalid range provided"
294+ fail "invalid range provided"
268− Just range -> do
295+ Just range -> do
269− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
296+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
270− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
297+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
271− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
298+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
272− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
299+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
273− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
300+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
274− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
301+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
276− it "can access attributes of a range" do
303+ it "can access attributes of a range" do
277− let range = IDBKeyRange.lowerBound 14 false
304+ let range = IDBKeyRange.lowerBound 14 false
278− IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
305+ IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
279− IDBKeyRange.upper range `shouldEqual` (Nothing :: Maybe Key)
306+ IDBKeyRange.upper range `shouldEqual` none
280− IDBKeyRange.lowerOpen range `shouldEqual` false
307+ IDBKeyRange.lowerOpen range `shouldEqual` false
281− IDBKeyRange.upperOpen range `shouldEqual` true
308+ IDBKeyRange.upperOpen range `shouldEqual` true
283− describe "IDBDatabase" do
310+ describe "IDBDatabase" do
285 tearDown db = do
312 tearDown db = do
286 IDBDatabase.close db
313 IDBDatabase.close db
287 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
314 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
288 pure unit
315 pure unit
290 setup storeParams = do
317 setup storeParams = do
291− let onUpgradeNeeded var db _ = launchAff' do
319+ onUpgradeNeeded var db _ _ = launchAff' do
292− store <- IDBDatabase.createObjectStore db "store" storeParams
320+ store <- IDBDatabase.createObjectStore db "store" storeParams
293− _ <- putVar var { db, store }
321+ _ <- AVar.put { db, store } var
294− pure unit
322+ pure unit
296− var <- makeVar
324+ var <- AVar.empty
297− db <- IDBFactory.open "db" Nothing
325+ _ <- IDBFactory.open "db" Nothing
298− { onUpgradeNeeded : Just (onUpgradeNeeded var)
326+ { onUpgradeNeeded: Just (onUpgradeNeeded var)
299− , onBlocked : Nothing
327+ , onBlocked: Nothing
302− takeVar var
330+ AVar.take var
304− it "createObjectStore (keyPath: [], autoIncrement: true)" do
332+ it "createObjectStore (keyPath: [], autoIncrement: true)" do
305− { db, store } <- setup { keyPath: [], autoIncrement: true }
333+ { db, store } <- setup { keyPath: [], autoIncrement: true }
306− IDBObjectStore.name store `shouldEqual` "store"
334+ IDBObjectStore.name store `shouldEqual` "store"
307− IDBObjectStore.keyPath store `shouldEqual` []
335+ IDBObjectStore.keyPath store `shouldEqual` []
308− IDBObjectStore.autoIncrement store `shouldEqual` true
336+ IDBObjectStore.autoIncrement store `shouldEqual` true
309− IDBObjectStore.indexNames store `shouldEqual` []
337+ IDBObjectStore.indexNames store `shouldEqual` []
310− tearDown db
338+ tearDown db
312− it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
340+ it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
313− { db, store } <- setup { keyPath: ["patate"], autoIncrement: true }
341+ { db, store } <- setup { keyPath: [ "patate" ], autoIncrement: true }
314− IDBObjectStore.name store `shouldEqual` "store"
342+ IDBObjectStore.name store `shouldEqual` "store"
315− IDBObjectStore.keyPath store `shouldEqual` ["patate"]
343+ IDBObjectStore.keyPath store `shouldEqual` [ "patate" ]
316− IDBObjectStore.autoIncrement store `shouldEqual` true
344+ IDBObjectStore.autoIncrement store `shouldEqual` true
317− IDBObjectStore.indexNames store `shouldEqual` []
345+ IDBObjectStore.indexNames store `shouldEqual` []
318− tearDown db
346+ tearDown db
320− it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
348+ it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
321− { db, store } <- setup { keyPath: ["patate", "autruche"], autoIncrement: false }
349+ { db, store } <- setup { keyPath: [ "patate", "autruche" ], autoIncrement: false }
322− IDBObjectStore.name store `shouldEqual` "store"
350+ IDBObjectStore.name store `shouldEqual` "store"
323− IDBObjectStore.keyPath store `shouldEqual` ["patate", "autruche"]
351+ IDBObjectStore.keyPath store `shouldEqual` [ "patate", "autruche" ]
324− IDBObjectStore.autoIncrement store `shouldEqual` false
352+ IDBObjectStore.autoIncrement store `shouldEqual` false
325− IDBObjectStore.indexNames store `shouldEqual` []
353+ IDBObjectStore.indexNames store `shouldEqual` []
326− tearDown db
354+ tearDown db
328− it "deleteObjectStore" do
356+ it "deleteObjectStore" do
329− let onUpgradeNeeded var db _ = launchAff' do
358+ onUpgradeNeeded var db _ _ = launchAff' do
330 _ <- IDBDatabase.deleteObjectStore db "store"
359 _ <- IDBDatabase.deleteObjectStore db "store"
331− putVar var true
360+ AVar.put true var
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
333− var <- makeVar
373+ describe "IDBObjectStore" do
334− { db, store } <- setup IDBObjectStore.defaultParameters
374+ let
335− IDBDatabase.close db
376+ 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
336− db <- IDBFactory.open "db" (Just 999) { onUpgradeNeeded : Just (onUpgradeNeeded var)
389+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
337− , onBlocked : Nothing
390+ , onBlocked: Nothing
339− deleted <- takeVar var
392+
340− deleted `shouldEqual` true
393+ AVar.take var
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
344− describe "IDBObjectStore" do
525+ describe "IDBIndex" do
346 tearDown db = do
527 tearDown db = do
347 IDBDatabase.close db
528 IDBDatabase.close db
348 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
529 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
349 pure unit
530 pure unit
351− setup { storeParams, onUpgradeNeeded } = do
532+ setup
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
352− let onUpgradeNeeded' var db _ = launchAff' do
543+ onUpgradeNeeded' var db tx _ = launchAff' do
353− store <- IDBDatabase.createObjectStore db "store" storeParams
544+ store <- IDBDatabase.createObjectStore db "store" storeParams
545+ _ <- traverse (uncurry (IDBObjectStore.add store)) values
546+ index <- IDBObjectStore.createIndex store "index" keyPath indexParams
354− liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure store)
547+ liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
355− putVar var { db, store }
548+ AVar.put { db, index, store } var
357− var <- makeVar
550+ var <- AVar.empty
358− db <- IDBFactory.open "db" Nothing
551+ _ <- IDBFactory.open "db" Nothing
359− { onUpgradeNeeded : Just (onUpgradeNeeded' var)
552+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
360− , onBlocked : Nothing
553+ , 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"
363− takeVar var
764+ tearDown db
365− it "add()" do
766+ it "openCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
366− date <- liftEff $ toDateTime <$> now
767+ res <- attempt $ setup
367− { db } <- setup
768+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
368− { storeParams: { autoIncrement: true, keyPath: [] }
769+ , indexParams: IDBObjectStore.defaultParameters
369− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
770+ , keyPath: [ "indexedProperty" ]
370− -- no key
771+ , values:
371− key <- IDBObjectStore.add store "patate" (Nothing :: Maybe Key)
772+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
372− (toKey 1) `shouldEqual` key
773+ ]
373−
774+ , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
375− key <- IDBObjectStore.add store "patate" (Just 14)
776+ cb =
376− (toKey 14) `shouldEqual` key
777+ { onSuccess: const $ pure unit
377−
778+ , onError: show >>> fail >>> launchAff'
378− -- number key
779+ , onComplete: pure unit
379− key <- IDBObjectStore.add store "patate" (Just 14.42)
780+ }
380− (toKey 14.42) `shouldEqual` key
781+ IDBTransaction.onAbort tx (pure unit)
381−
782+ IDBDatabase.onAbort db (pure unit)
382− -- string key
783+ IDBTransaction.abort tx
383− key <- IDBObjectStore.add store "patate" (Just "key")
784+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
384− (toKey "key") `shouldEqual` key
785+ case cursor of
385−
786+ Right _ -> fail "expected InvalidStateError"
386− -- date key
787+ Left err -> name err `shouldEqual` "InvalidStateError"
387− key <- IDBObjectStore.add store "patate" (Just date)
788+ }
388− (toKey date) `shouldEqual` key
789+ case res of
389−
790+ Right _ -> fail "expected InvalidStateError"
390− -- array key
791+ _ -> pure unit
391− key <- IDBObjectStore.add store "patate" (Just $ toKey [14, 42])
792+
392− (toKey [14, 42]) `shouldEqual` key
793+ it "openCursor() - throw TransactionInactiveError on aborted transaction" do
393− }
794+ { db } <- setup
394− tearDown db
795+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
395−
796+ , indexParams: IDBObjectStore.defaultParameters
396− it "clear()" do
797+ , keyPath: [ "indexedProperty" ]
397− { db } <- setup
798+ , values:
398− { storeParams: IDBObjectStore.defaultParameters
799+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
399− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
800+ ]
400− key <- IDBObjectStore.add store "patate" (Just 14)
801+ , onUpgradeNeeded: Nothing
401− _ <- IDBObjectStore.clear store
802+ }
402− val <- IDBObjectStore.get store (IDBKeyRange.only key)
803+ let
403− val `shouldEqual` (Nothing :: Maybe String)
804+ cb =
404− }
805+ { onSuccess: const $ pure unit
405− tearDown db
806+ , onError: show >>> fail >>> launchAff'
406−
807+ , onComplete: pure unit
407− it "count()" do
808+ }
408− { db } <- setup
809+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
409− { storeParams: IDBObjectStore.defaultParameters
810+ store <- IDBTransaction.objectStore tx "store"
410− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
811+ index <- IDBObjectStore.index store "index"
411− key <- IDBObjectStore.add store "patate" (Just 14)
812+ IDBTransaction.onAbort tx (pure unit)
412− key <- IDBObjectStore.add store "autruche" (Just 42)
813+ IDBTransaction.abort tx
413− n <- IDBObjectStore.count store Nothing
814+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
414− n `shouldEqual` 2
815+ case cursor of
415− }
816+ Right _ -> fail "expected TransactionInactiveError"
416− tearDown db
817+ Left err -> name err `shouldEqual` "TransactionInactiveError"
418− it "getKey()" do
819+ tearDown db
420− { storeParams: IDBObjectStore.defaultParameters
821+ it "openCursor() - throw InvalidStateError when the index is deleted" do
421− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
822+ { db } <- setup
422− key <- IDBObjectStore.add store "patate" (Just 14)
823+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
423− mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 14)
824+ , indexParams: IDBObjectStore.defaultParameters
424− mkey `shouldEqual` (Just key)
825+ , keyPath: [ "indexedProperty" ]
426− mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 42)
827+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
427− mkey `shouldEqual` (Nothing :: Maybe Key)
828+ ]
428− }
829+ , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
431− it "getAllKeys()" do
832+ { onSuccess: const $ pure unit
432− { db } <- setup
833+ , onError: show >>> fail >>> launchAff'
433− { storeParams: IDBObjectStore.defaultParameters
834+ , onComplete: pure unit
434− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
835+ }
435− key1 <- IDBObjectStore.add store "patate" (Just 14)
836+ store <- IDBTransaction.objectStore tx "store"
436− key2 <- IDBObjectStore.add store "autruche" (Just 42)
837+ IDBObjectStore.deleteIndex store "index"
437− key3 <- IDBObjectStore.add store 14 (Just 1337)
838+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
439− -- no bounds
840+ Right _ -> fail "expected InvalidStateError"
440− keys <- IDBObjectStore.getAllKeys store Nothing Nothing
841+ Left err -> name err `shouldEqual` "InvalidStateError"
441− keys `shouldEqual` [key1, key2, key3]
842+ }
443− -- lower bound
844+ tearDown db
444− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
845+
445− keys `shouldEqual` [key2, key3]
846+ it "getKey() - multiEntry - adding keys" do
447− -- upper bound
848+ { storeParams: IDBDatabase.defaultParameters
448− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
849+ , indexParams: { unique: false, multiEntry: true }
449− keys `shouldEqual` [key1, key2]
850+ , keyPath: [ "name" ]
451− -- count
852+ [ { name: [ "patate", "autruche" ] } :+: (Just $ toKey 1)
452− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
853+ , { name: [ "bob" ] } :+: (Just $ toKey 2)
453− keys `shouldEqual` [key1, key2]
854+ ]
454− }
855+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
455− tearDown db
856+ key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
456−
857+ key `shouldEqual` (Just $ toKey 1)
457− it "openCursor()" do
858+
458− { db } <- setup
859+ key' <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
459− { storeParams: IDBObjectStore.defaultParameters
860+ key' `shouldEqual` (Just $ toKey 1)
460− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
861+
461− _ <- IDBObjectStore.openCursor store Nothing Next
862+ key'' <- IDBIndex.getKey index (IDBKeyRange.only "bob")
462− _ <- IDBObjectStore.openCursor store Nothing NextUnique
863+ key'' `shouldEqual` (Just $ toKey 2)
463− _ <- IDBObjectStore.openCursor store Nothing Prev
864+ }
464− _ <- IDBObjectStore.openCursor store Nothing PrevUnique
865+ tearDown db
465− _ <- IDBObjectStore.openCursor store (Just $ IDBKeyRange.upperBound 1 true) Next
866+
466− pure unit
867+ it "get() - returns the record with the first key in the range" do
467− }
868+ { db } <- setup
468− tearDown db
869+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
469−
870+ , indexParams: IDBObjectStore.defaultParameters
470− it "openKeyCursor()" do
871+ , keyPath: [ "indexedProperty" ]
471− { db } <- setup
872+ , values:
472− { storeParams: IDBObjectStore.defaultParameters
873+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
473− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
874+ , { key: 42, indexedProperty: "autruche" } :+: Nothing
474− _ <- IDBObjectStore.openKeyCursor store Nothing Next
875+ , { key: 1337, indexedProperty: "baguette" } :+: Nothing
475− _ <- IDBObjectStore.openKeyCursor store Nothing NextUnique
876+ ]
476− _ <- IDBObjectStore.openKeyCursor store Nothing Prev
877+ , onUpgradeNeeded: Nothing
477− _ <- IDBObjectStore.openKeyCursor store Nothing PrevUnique
878+ }
478− _ <- IDBObjectStore.openKeyCursor store (Just $ IDBKeyRange.lowerBound 1 true) Next
879+
479− pure unit
880+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
480− }
881+ store <- IDBTransaction.objectStore tx "store"
481− tearDown db
882+ index <- IDBObjectStore.index store "index"
883+ val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
884+ ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
483− describe "IDBIndex" do
888+ describe "IDBCursor" do
485 tearDown db = do
890 tearDown db = do
486 IDBDatabase.close db
891 IDBDatabase.close db
487 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
892 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
488 pure unit
893 pure unit
490− setup :: forall value e e'.
896+ :: forall value
491− { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
897+ . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
492− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
898+ , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
493− , values :: Array (Tuple value (Maybe Key))
899+ , values :: Array (Tuple value (Maybe Key))
494− , keyPath :: Array String
900+ , keyPath :: Array String
495− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Eff (idb :: IDB, avar :: AVAR, exception :: EXCEPTION | e') Unit)
901+ , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
496− } -> Aff (idb :: IDB, avar :: AVAR | e) { db :: Database, index :: Index, store :: ObjectStore }
903+ -> Aff { db :: Database, index :: Index, store :: ObjectStore }
497 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
904 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
498− let onUpgradeNeeded' var db tx = launchAff' do
906+ onUpgradeNeeded' var db tx _ = launchAff' do
499− store <- IDBDatabase.createObjectStore db "store" storeParams
907+ store <- IDBDatabase.createObjectStore db "store" storeParams
500− _ <- traverse (uncurry (IDBObjectStore.add store)) values
908+ _ <- traverse (uncurry (IDBObjectStore.add store)) values
501− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
909+ index <- IDBObjectStore.createIndex store "index" keyPath indexParams
502− liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
910+ liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
503− putVar var { db, index, store }
911+ AVar.put { db, index, store } var
505− var <- makeVar
913+ var <- AVar.empty
506− db <- IDBFactory.open "db" Nothing
914+ db <- IDBFactory.open "db" Nothing
507− { onUpgradeNeeded : Just (onUpgradeNeeded' var)
915+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
508− , onBlocked : Nothing
916+ , 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"
510− takeVar var
991+ vdone <- AVar.empty
511−
992+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
512−
993+ store <- IDBTransaction.objectStore tx "store"
513− it "returns an IDBIndex and the properties are set correctly" do
994+ IDBObjectStore.openCursor store Nothing Next (cb vdone)
514− { db, index } <- setup
995+ AVar.take vdone
515− { storeParams : IDBObjectStore.defaultParameters
996+ tearDown db
516− , indexParams : IDBIndex.defaultParameters
997+
517− , onUpgradeNeeded : Nothing
998+ it "advance() - iterate cursor number of times specified by count" do
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
541− IDBTransaction.onAbort tx (onAbort txVar)
542− IDBDatabase.onAbort db (onAbort dbVar)
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
553− { db } <- setup
999+ { db } <- setup
554− { storeParams : { keyPath : ["key"]
555− , autoIncrement : false
1000+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
557− , indexParams : IDBIndex.defaultParameters
1001+ , indexParams: IDBObjectStore.defaultParameters
558− , keyPath : ["indexedProperty"]
1002+ , keyPath: []
559− , values : [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
1003+ , values:
560− , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
1004+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
561− , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
1005+ , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
1006+ , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
1007+ , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
563− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1009+ , onUpgradeNeeded: Nothing
564− val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
1010+ }
565− ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
1011+ let
566− }
1012+ cb vdone vjump =
567− tearDown db
1013+ { onComplete: launchAff' do
568−
1014+ AVar.put unit vdone
569− it "empty keyPath" do
1015+
570− { db } <- setup
1016+ , onError: \error -> launchAff' do
571− { storeParams : IDBObjectStore.defaultParameters
1017+ fail $ "unexpected error: " <> show error
572− , indexParams : IDBIndex.defaultParameters
1018+
573− , keyPath : []
1019+ , onSuccess: \cursor -> launchAff' do
574− , values : [ "object_1" :+: (Just $ toKey 1)
1020+ jump <- AVar.take vjump
575− , "object_2" :+: (Just $ toKey 2)
1021+ if jump then do
576− , "object_3" :+: (Just $ toKey 3)
1022+ IDBCursor.advance cursor 3
578− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1024+ let value = IDBCursor.value cursor
579− val <- IDBIndex.get index (IDBKeyRange.only "object_3")
1025+ value.pKey `shouldEqual` "pkey_3"
580− val `shouldEqual` (Just "object_3")
1026+ value.iKey `shouldEqual` "ikey_3"
581− }
1027+ IDBCursor.continue cursor none
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)
582− tearDown db
1036+ tearDown db
584− it "index can be valid keys [date]" do
1038+ it "delete() - remove a record from the object store" do
585− date <- liftEff $ toDateTime <$> now
586− { db } <- setup
1039+ { db } <- setup
587− { storeParams : { keyPath: ["key"]
588− , autoIncrement: false
1040+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
590− , indexParams : IDBIndex.defaultParameters
1041+ , indexParams: IDBObjectStore.defaultParameters
591− , keyPath : ["i"]
1042+ , keyPath: []
592− , values : [ { key: "date", i: (toKey date) } :+: Nothing
1043+ , values:
593− ]
1044+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
594− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1045+ , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
595− val <- IDBIndex.get index (IDBKeyRange.only date)
1046+ , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
596− ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
1047+ , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
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
610− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
1049+ , onUpgradeNeeded: Nothing
611− val <- IDBIndex.get index (IDBKeyRange.only num)
1050+ }
612− ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
1051+ let
613− }
1052+ cb vdone store =
614− tearDown db
1053+ { onComplete: launchAff' do
615−
1054+ mval <- map _.pKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
616− it "index can be valid keys [array]" do
1055+ mval `shouldEqual` (Nothing :: Maybe String)
617− let array = ["patate", "autruche"]
1056+ AVar.put unit vdone
618− { db } <- setup
1057+
619− { storeParams : { keyPath: ["key"]
1058+ , onError: \error -> launchAff' do
620− , autoIncrement: false
1059+ fail $ "unexpected error: " <> show error
622− , indexParams : IDBIndex.defaultParameters
1061+ , onSuccess: \cursor -> launchAff' do
623− , keyPath : ["i"]
1062+ let value = IDBCursor.value cursor
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")
762− key `shouldEqual` (Just $ toKey 1)
1063+ value.pKey `shouldEqual` "pkey_0"
763−
1064+ IDBCursor.delete cursor
764− key <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
1065+ IDBCursor.advance cursor 4
765− key `shouldEqual` (Just $ toKey 1)
1066+ }
766−
1067+ vdone <- AVar.empty
767− key <- IDBIndex.getKey index (IDBKeyRange.only "bob")
1068+ tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
768− key `shouldEqual` (Just $ toKey 2)
1069+ store <- IDBTransaction.objectStore tx "store"
769− }
1070+ IDBObjectStore.openCursor store Nothing Next (cb vdone store)
770− tearDown db
1072+ tearDown db
772−
1074+ it "update() - modify a record in the object store" do
773− it "get() - returns the record with the first key in the range" do
774− { db } <- setup
1075+ { db } <- setup
775− { storeParams : { keyPath: ["key"], autoIncrement: false }
1076+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
776− , indexParams : IDBIndex.defaultParameters
1077+ , indexParams: IDBObjectStore.defaultParameters
777− , keyPath : ["indexedProperty"]
1078+ , keyPath: []
778− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
1079+ , values:
779− , { key: 42, indexedProperty: "autruche" } :+: Nothing
1080+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
780− , { key: 1337, indexedProperty: "baguette" } :+: Nothing
782− , onUpgradeNeeded : Nothing
1082+ , onUpgradeNeeded: Nothing
785− tx <- IDBDatabase.transaction db ["store"] ReadOnly
1085+ cb vdone store =
786− store <- IDBTransaction.objectStore tx "store"
1086+ { onComplete: launchAff' do
787− index <- IDBObjectStore.index store "index"
788− val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
1087+ mval <- map _.iKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
789− ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
1088+ mval `shouldEqual` (Just "patate")
790−
1089+ AVar.put unit vdone
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)