git.iko.soy/purescript-indexed-DB
on 889b776 help sign in
.eslintignore+1−1
since splitsnapshots
unifiedsplit
@@ -1 +1 @@
1−dist/*
1+/dist/*
.github/browserstack.pngdeleted

Binary file not shown.

.gitignore−3
@@ -71,11 +71,8 @@ typings/
71# Generated files
71# Generated files
72output
72output
73generated-docs
73generated-docs
74−releases
75.pulp-cache
74.pulp-cache
76.psc*
75.psc*
77.purs*
76.purs*
78.psa*
77.psa*
79dist
78dist
80−.spago
81−test.js
.travis.ymldeleted−37
@@ -1,37 +0,0 @@
1−language: node_js
2−node_js:
3− - node
4−
5−addons:
6− browserstack:
7− username: $BROWSERSTACK_USERNAME
8− access_key: $BROWSERSTACK_ACCESSKEY
9−
10−before_install:
11− - export PATH=./node_modules/.bin:$PATH
12−
13−install:
14− - npm install
15− - bower install
16−
17−script:
18− - npm run test:browserstack
19−
20−after_script:
21− - npm run prepare:release
22−
23−deploy:
24− - provider: releases
25− api_key: $GITHUB_TOKEN
26− skip_cleanup: true
27− file_glob: true
28− file: releases/github/*
29− on:
30− tags: true
31− branch: master
32−
33− - provider: script
34− script: deploy.sh
35− on:
36− tags: true
37− branch: master
README.md+251−75
@@ -1,107 +1,283 @@
1−PureScript IndexedDB [![](https://img.shields.io/badge/doc-pursuit-60b5cc.svg)](http://pursuit.purescript.org/packages/purescript-indexeddb) [![Build Status](https://travis-ci.org/truqu/purescript-indexedDB.svg?branch=master)](https://travis-ci.org/truqu/purescript-indexedDB)
1+## API
2−=====
3
2
4−This package offers complete bindings and type-safety upon the [IndexedDB API](https://w3c.github.io/IndexedDB).
3+This document is a general grooming of the current state of the IndexedDB API. It covers only
4+the features specified in the official specs.
5
5
6−## Overview
6+### Remarks
7
7
8−The `IDBCore` and `IDBFactory` are the two entry points required to create and connect to an
8+- Better define a 'all' range instead of using Maybe `IDBKeyRange` in function
9−indexed database. From there, modules are divided such that each of them covers a specific IDB
9+signatures (Nothing meaning 'all').
10−interface.
11
10
12−They are designed to be used as qualified imports such that each method gets prefixed with a
11+- Some errors (like TypeError or DataError) can be avoided via static typing
13−menaingful namespace (e.g `IDBIndex.get`, `IDBObjectStore.openCursor` ...)
14
12
15−Here's a quick example of what it look likes.
13+- The `IDBRequest` is mostly a callback result holding an error or a value. We probably want to
16−```purescript
14+ use a typed Except or ExceptT instead.
17−module Main where
18
15
19−import Prelude
20
16
21−import Control.Monad.Aff (Aff, launchAff_)
17+### Table of Contents
22−import Control.Monad.Aff.Console (CONSOLE, log)
23−import Control.Monad.Eff.Exception (EXCEPTION)
24−import Control.Monad.Eff (Eff)
25−import Data.Maybe (Maybe(..), maybe)
26
18
27−import Database.IndexedDB.Core
19+- [IDBCursor](#idbcursor)
28−import Database.IndexedDB.IDBFactory as IDBFactory
20+- [IDBCursorWithValue](#idbcursorwithvalue)
29−import Database.IndexedDB.IDBDatabase as IDBDatabase
21+- [IDBCursorDirection](#idbcursordirection)
30−import Database.IndexedDB.IDBObjectStore as IDBObjectStore
22+- [IDBDatabase](#idbdatabase)
31−import Database.IndexedDB.IDBIndex as IDBIndex
23+- [IDBError](#idberror)
32−import Database.IndexedDB.IDBTransaction as IDBTransaction
24+- [IDBFactory](#idbfactory)
33−import Database.IndexedDB.IDBKeyRange as IDBKeyRange
25+- [IDBIndex](#idbindex)
26+- [IDBKeyRange](#idbkeyrange)
27+- [IDBRequest](#idbrequest)
28+- [IDBOpenDBRequest](#idbopendbrequest)
29+- [IDBObjectStore](#idbobjectstore)
30+- [IDBTransaction](#idbtransaction)
31+- [IDBTransactionMode](#idbtransactionmode)
34
32
35
33
36−main :: Eff (idb :: IDB, exception :: EXCEPTION, console :: CONSOLE) Unit
34+---
37−main = launchAff_ do
38− db <- IDBFactory.open "db" Nothing { onBlocked : Nothing
39− , onUpgradeNeeded : Just onUpgradeNeeded
40− }
41
35
42− tx <- IDBDatabase.transaction db ["store"] ReadOnly
43− store <- IDBTransaction.objectStore tx "store"
44− (val :: Maybe String) <- IDBObjectStore.get store (IDBKeyRange.only 1)
45− log $ maybe "not found" id val
46
36
37+#### IDBCursor
38+> https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor
47
39
48−onUpgradeNeeded :: forall e. Database -> Transaction -> { oldVersion :: Int } -> Eff (idb :: IDB, exception :: EXCEPTION | e) Unit
40+- source :: [IDBIndex](#idbindex), [IDBObjectStore](#idbobjectstore)
49−onUpgradeNeeded db _ _ = launchAff_ do
41+- direction :: [IDBCursorDirection](#idbcursordirection)
50− store <- IDBDatabase.createObjectStore db "store" IDBDatabase.defaultParameters
42+- key :: [IDBKey](#idbkey)
51− _ <- IDBObjectStore.add store "patate" (Just 1)
43+- primaryKey :: [IDBKey](#idbkey)
52− _ <- IDBObjectStore.add store { property: 42 } (Just 2)
44+- value :: Any
53− _ <- IDBObjectStore.createIndex store "index" ["property"] IDBObjectStore.defaultParameters
45+- advance :: [IDBCursor](#idbcursor) -> Int -> ()
54− pure unit
46+ > `throw` TransactionInactiveError, TypeError, InvalidStateError
55−```
47+- continue :: [IDBCursor](#idbcursor) -> Maybe [IDBKey](#idbkey) -> ()
48+ > `throw` TransactionInactivError, DataError, InvalidStateError
49+- continuePrimaryKey :: [IDBCursor](#idbcursor) -> [IDBKey](#idbkey) -> [IDBKey](#idbkey) -> ()
50+ > `throw` TransactionInactiveError, DataError, InvalidStateError, InvalidAccessError
56
51
57−## Notes
58
52
59−### Errors
53+---
60−Errors normally thrown by the IDB\* interfaces are wrapped in the `Aff` Monad as `Error` where
61−the `name` corresponds to the error's name (e.g. "InvalidStateError"). Pattern matching can
62−therefore be done on any error to handle specific errors thrown by the API.
63
54
64−### Examples
65−The `test` folder contains a great amount of examples showing practical usage of the IDB\*
66−interfaces. Do not hesitate to have a peek should you wonder how to use one of the module. The
67−wrapper tries to keep as much as possible an API consistent with the original IndexedDB API.
68−Hence, it should be quite straightforward to translate any JavaScript example to a PureScript
69−one.
70
55
71−## Changelog
56+#### IDBCursorWithValue
57+> https://developer.mozilla.org/en-US/docs/Web/API/IDBCursorwithValue
72
58
73−#### v3.0.0
59+Inherit from [IDBCursor](#idbcursor)
74
60
75−- callback to `onUpgradeNeeded` event now provide a record with the database old version.
61+- delete :: [IDBCursor](#idbcursor) -> [IDBRequest](#idbrequest) ()
62+ > `throw` TransactionInactiveError, ReadOnlyError, InvalidStateError
63+- update :: [IDBCursor](#idbcursor) -> a -> [IDBRequest](#idbrequest) a
64+ > `throw` TransactionInactiveError, ReadOnlyError, InvalidStateError, DataError, DataCloneError
76
65
77−#### v2.0.0
78
66
79−- review interface implementation (use of opaque classes to improve readability without compromising
67+---
80− the reusability). The API doesn't really change from a user perspective though.
81
68
82−- make the Key more opaque (by having an IDBKey instance for Foreign types)
83
69
84−- Upgrade purescript-exceptions to 3.1.0 and leverage the new `name` accessor
70+#### IDBCursorDirection
71+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBCursorDirection
85
72
73+data [IDBCursorDirection](#idbcursordirection)
74+ = Next
75+ | NextUnique
76+ | Prev
77+ | PrevUnique
86
78
87−#### v1.0.0
88
79
89−- [Indexed Database API 2.0](https://w3c.github.io/IndexedDB/) totally covered apart from
80+---
90− - `index.getAll` method (and the associated one for the IDBObjectStore)
91− - binary keys
92
81
93−## Documentation
94
82
95−Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-indexeddb).
83+#### IDBDatabase
84+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBDatabase
96
85
97−## Testing
86+- name :: String
98−Tested in the cloud on multiple browsers and operating systems thanks to [BrowserStack](https://www.browserstack.com)
87+- version :: Long
88+- objectStoreNames :: [String]
89+- close :: [IDBDatabase](#idbdatabase) -> ()
90+- createObjectStore :: [IDBDatabase](#idbdatabase) -> String -> { keyPath :: String, autoIncrement :: Bool } -> [IDBObjectStore](#idbobjectstore)
91+ > `throw` InvalidStateError, TransactionInactiveError, ConstraintError, InvalidAccessError
92+- deleteObjectStore :: [IDBDatabase](#idbdatabase) -> String -> ()
93+ > `throw` InvalidSateError, TransactionInactiveError, NotFoundError
94+- transaction :: [IDBDatabase](#idbdatabase) -> [String] -> [IDBTransactionMode](#idbtransactionmode) -> [IDBTransaction](#idbtransaction)
95+ > `throw` InvalidStateError, NotFoundError, TypeError, InvalidAccessError
99
96
97+##### Events
98+- onabort
99+- onerror
100+- onversionchange
100
101
101−| IE / Edge | Chrome | Firefox | Safari | Opera | Android | iOS Safari |
102−| ----------| ------ | ------- | ------- | ----- | ------- | ---------- |
103−| - | >= 57 | >= 51 | - | >= 46 | - | - |
104
102
105−<p align="center">
103+---
106− <a href="https://www.browserstack.com"><img alt="browserstack" src=".github/browserstack.png" /></a>
104+
107−</p>
105+
106+#### IDBError
107+> https://www.w3.org/TR/IndexedDB/#exceptions
108+
109+data IDBError
110+ = AbortError
111+ | ConstraintError
112+ | QuotaExceededError
113+ | UnknownError
114+ | NoError
115+ | VersionError
116+
117+
118+---
119+
120+
121+#### IDBFactory
122+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBFactory
123+
124+The method `cmp` isn't included; instead, we consider [IDBKey](#idbkey) to be comparable.
125+
126+- open :: String -> Maybe Long -> [IDBOpenDBRequest](#idbopendbrequest) ()
127+- deleteDatabase :: String -> [IDBOpenDBRequest](#idbopendbrequest) ()
128+
129+
130+---
131+
132+
133+#### IDBIndex
134+> https://www.w3.org/TR/IndexedDB/#index-concept
135+> https://www.w3.org/TR/IndexedDB/#index
136+
137+- name :: String
138+- objectStore :: [IDBObjectStore](#idbobjectstore)
139+- keyPath :: String
140+- multiEntry :: Bool
141+- unique :: Bool
142+- count :: [IDBIndex](#idbindex) -> Maybe [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) Int
143+ > `throw` TransactionInactiveError, DataError, InvalidStateError
144+- get :: [IDBIndex](#idbindex) -> [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) a
145+ > `throw` TransactionInactiveError, DataError, InvalidStateError
146+- getKey :: [IDBIndex](#idbindex) -> [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) [IDBKey](#idbkey)
147+ > `throw` TransactionInactiveError, DataError, InvalidStateError
148+- openCursor :: [IDBIndex](#idbindex) -> Maybe [IDBKeyRange](#idbkeyrange) -> Maybe Direction -> [IDBRequest](#idbrequest) CursorWithValue
149+ > `throw` TransactionInactiveError, DataError, TypeError, InvalidStateError
150+- openKeyCursor :: [IDBIndex](#idbindex) -> Maybe [IDBKeyRange](#idbkeyrange)-> Maybe Direction -> [IDBRequest](#idbrequest) Cursor
151+ > `throw` TransactionInactiveError, DataError, TypeError, InvalidStateError
152+
153+
154+---
155+
156+
157+#### IDBKey
158+> https://www.w3.org/TR/IndexedDB/#key-construct
159+
160+Should be comparable / derive Ord
161+
162+data IDBKey
163+ = Int Int
164+ | Float Float
165+ | String String
166+ | Date Date
167+ | Array [[IDBKey](#idbkey)]
168+
169+
170+---
171+
172+
173+#### IDBKeyRange
174+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBKeyRange
175+
176+- lower :: [IDBKey](#idbkey)
177+- upper :: [IDBKey](#idbkey)
178+- lowerOpen :: Boolean
179+- upperOpen :: Boolean
180+- bound :: [IDBKey](#idbkey) -> [IDBKey](#idbkey) -> Bool -> Bool -> [IDBKeyRange](#idbkeyrange)
181+ > `throw` DataError
182+- only :: [IDBKey](#idbkey) -> [IDBKeyRange](#idbkeyrange)
183+ > `throw` DataError
184+- lowerBound :: [IDBKey](#idbkey) -> Bool -> [IDBKeyRange](#idbkeyrange)
185+ > `throw` DataError
186+- upperBound :: [IDBKey](#idbkey) -> Bool -> [IDBKeyRange](#idbkeyrange)
187+ > `throw` DataError
188+- includes :: [IDBKey](#idbkey) -> Boolean
189+ > `throw` DataError
190+
191+
192+---
193+
194+
195+#### IDBRequest
196+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBRequest
197+
198+- error :: [IDBError](#idberror)
199+- result :: a
200+- source :: [IDBIndex](#idbindex) | [IDBObjectStore](#idbobjectstore) | [IDBCursor](#idbcursor)
201+- readyState :: Bool
202+- transaction :: Maybe [IDBTransaction](#idbtransaction)
203+
204+##### Events
205+- onerror
206+- onsuccess
207+
208+
209+---
210+
211+
212+#### IDBOpenDBRequest
213+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBRequest
214+
215+Inherit from [IDBRequest](#idbrequest)
216+
217+##### Events
218+ - onblocked
219+ - onupgradeneeded
220+
221+
222+---
223+
224+
225+#### IDBObjectStore
226+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBObjectStore
227+
228+- indexNames:: [String]
229+- keyPath :: String
230+- name :: String
231+- transaction :: [IDBTransaction](#idbtransaction)
232+- autoIncrement :: Bool
233+- add :: [IDBObjectStore](#idbobjectstore) -> Value -> Maybe [IDBKey](#idbkey) -> [IDBRequest](#idbrequest) ()
234+ > `throw` ReadOnlyError, TransactionInactiveError, DataError, InvalidStateError, DataCloneError
235+- clear :: [IDBObjectStore](#idbobjectstore) -> [IDBRequest](#idbrequest) ()
236+ > `throw` ReadOnlyError, TransactionInactiveError
237+- count :: [IDBObjectStore](#idbobjectstore) -> [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) Int
238+ > `throw` InvalidStateError, TransactionInactiveError, DataError
239+- createIndex :: [IDBObjectStore](#idbobjectstore) -> String -> String -> { unique :: Bool, multiEntry :: true } -> [IDBIndex](#idbindex)
240+ > `throw` ConstraintError, InvalidAccessError, InvalidStateError, SyntaxError, TransactionInactiveError
241+- delete :: [IDBObjectStore](#idbobjectstore) -> [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) ()
242+ > `throw` TransactionInactiveError, ReadOnlyError, InvalidStateError, DataError
243+- deleteIndex :: [IDBObjectStore](#idbobjectstore) -> String -> ()
244+ > `throw` InvalidStateError, TransactionInactiveError, NotFoundError
245+- get :: [IDBObjectStore](#idbobjectstore) -> [IDBKeyRange](#idbkeyrange) -> [IDBRequest](#idbrequest) a
246+ > `throw` InvalidStateError, TransactionInactiveError, DataError
247+- index :: [IDBObjectStore](#idbobjectstore) -> String -> [IDBIndex](#idbindex)
248+ > `throw` InvalidStateError, NotfoundError
249+- openCursor :: [IDBObjectStore](#idbobjectstore) -> Maybe [IDBKeyRange](#idbkeyrange) -> Maybe [IDBCursorDirection](#idbcursordirection) -> [IDBRequest](#idbrequest) [IDBCursorWithValue](#idbcursorwithvalue)
250+ > `throw` TransactionInactiveError, InvalidStateError, DataError
251+- put :: [IDBObjectStore](#idbobjectstore) -> a -> [IDBKey](#idbkey) -> [IDBRequest](#idbrequest) ()
252+ > `throw` ReadOnlyError, TransactionInactiveError, DataError, InvalidStateError, DataCloneError
253+
254+
255+---
256+
257+
258+#### IDBTransaction
259+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBTransaction
260+
261+- db :: [IDBDatabase](#idbdatabase)
262+- error :: [IDBError](#idberror)
263+- mode :: [IDBTransactionMode](#idbtransactionmode)
264+- abort :: [IDBTransaction](#idbtransaction) -> ()
265+ > `throw` InvalidStateError
266+- objectStore :: [IDBTransaction](#idbtransaction) -> String -> [IDBObjectStore](#idbobjectstore)
267+ > `throw` InvalidStateError, NotFoundError
268+
269+##### Events
270+- onabort
271+- oncomplete
272+- onerror
273+
274+---
275+
276+
277+#### IDBTransactionMode
278+> https://www.w3.org/TR/IndexedDB/#idl-def-IDBTransactionMode
279+
280+data IDBTransactionMode
281+ = ReadOnly
282+ | ReadWrite
283+ | VersionChange
bower.jsonnew file+19
@@ -0,0 +1,19 @@
1+{
2+ "name": "purescript-indexeddb",
3+ "ignore": [
4+ "**/.*",
5+ "node_modules",
6+ "bower_components",
7+ "output"
8+ ],
9+ "dependencies": {
10+ "purescript-maybe": "3.0.0",
11+ "purescript-aff": "3.1.0",
12+ "purescript-test-unit": "11.0.0",
13+ "purescript-spec": "1.0.0",
14+ "purescript-datetime": "3.2.0"
15+ },
16+ "devDependencies": {
17+ "purescript-psci-support": "3.0.0"
18+ }
19+}
index.jsdeleted−4
@@ -1,4 +0,0 @@
1−import "fake-indexeddb/auto";
2−import * as Main from './output/Test.Main/index.js';
3−
4−Main.main();
karma.conf.jsnew file+25
@@ -0,0 +1,25 @@
1+module.exports = config => {
2+ config.set({
3+ autoWatch: true,
4+ browsers: ["Chrome"],
5+ files: [
6+ "dist/karma/index.js",
7+ ],
8+ frameworks: [
9+ "mocha",
10+ ],
11+ plugins: [
12+ "karma-chrome-launcher",
13+ "karma-firefox-launcher",
14+ "karma-spec-reporter",
15+ "karma-mocha",
16+ ],
17+ reporters: ["spec"],
18+ singleRun: false,
19+ client: {
20+ mocha: {
21+ timeout: 10000
22+ }
23+ }
24+ });
25+};
package.json+39−8
@@ -1,15 +1,46 @@
1{
1{
2− "name": "purescript-indexed-DB",
2+ "name": "purescript-indexeddb",
3 "version": "1.0.0",
3 "version": "1.0.0",
4+ "description": "This document is a general grooming of the current state of the IndexedDB API. It covers only the features specified in the official specs.",
4− "main": "index.js",
5+ "main": "bundle.js",
5− "repository": "https://github.com/ilyakooo0/purescript-indexed-DB.git",
6− "author": "iko <mail@iko.soy>",
7− "license": "MIT",
8 "scripts": {
6 "scripts": {
9− "test": "spago build && node index.js"
7+ "test:build": "pulp browserify -j 4 --main \"Test.Main\" -I test --to dist/karma/index.js",
8+ "test:run": "karma start --single-run",
9+ "test:watch": "find . -type f -regex '.*\\(src\\|test\\).*' ! -regex '.*bower_components.*\\|.*node_modules.*|.*\\.sw.*$' | entr -s 'npm run test'",
10+ "test": "npm run test:build && npm run test:run",
11+ "build": "pulp browserify -j 4 -O --to dist/bundle.js",
12+ "start": "find . -type f -regex '.*\\(src\\|test\\).*' ! -regex '.*bower_components.*\\|.*node_modules.*|.*\\.sw.*$' | entr -s 'clear; pulp browserify -j 4 -t dist/bundle.js'",
13+ "start:test": "karma start"
10 },
14 },
11 "dependencies": {
15 "dependencies": {
12− "fake-indexeddb": "^4.0.1"
16+ "eslint": "^3.19.0",
17+ "eslint-config-airbnb": "^15.0.1",
18+ "eslint-plugin-import": "^2.3.0",
19+ "eslint-plugin-jsx-a11y": "^5.0.3",
20+ "eslint-plugin-react": "^7.1.0",
21+ "karma": "^1.7.0"
13 },
22 },
23+ "devDependencies": {
24+ "eslint": "3.19.0",
25+ "eslint-config-airbnb": "15.0.1",
26+ "eslint-plugin-import": "2.5.0",
27+ "eslint-plugin-jsx-a11y": "5.0.3",
28+ "eslint-plugin-react": "7.1.0",
29+ "karma": "1.7.0",
30+ "karma-chrome-launcher": "2.1.1",
31+ "karma-firefox-launcher": "1.0.1",
32+ "karma-mocha": "^1.3.0",
33+ "karma-spec-reporter": "0.0.31",
34+ "mocha": "^3.4.2"
35+ },
36+ "repository": {
14− "type": "module"
37+ "type": "git",
38+ "url": "git+https://github.com/Truqu/purescript-indexeddb.git"
39+ },
40+ "author": "",
41+ "license": "ISC",
42+ "bugs": {
43+ "url": "https://github.com/Truqu/purescript-indexeddb/issues"
44+ },
45+ "homepage": "https://github.com/Truqu/purescript-indexeddb#readme"
15}
46}
packages.dhalldeleted−105
@@ -1,105 +0,0 @@
1−{-
2−Welcome to your new Dhall package-set!
3−
4−Below are instructions for how to edit this file for most use
5−cases, so that you don't need to know Dhall to use it.
6−
7−## Use Cases
8−
9−Most will want to do one or both of these options:
10−1. Override/Patch a package's dependency
11−2. Add a package not already in the default package set
12−
13−This file will continue to work whether you use one or both options.
14−Instructions for each option are explained below.
15−
16−### Overriding/Patching a package
17−
18−Purpose:
19−- Change a package's dependency to a newer/older release than the
20− default package set's release
21−- Use your own modified version of some dependency that may
22− include new API, changed API, removed API by
23− using your custom git repo of the library rather than
24− the package set's repo
25−
26−Syntax:
27−where `entityName` is one of the following:
28−- dependencies
29−- repo
30−- version
31−-------------------------------
32−let upstream = --
33−in upstream
34− with packageName.entityName = "new value"
35−-------------------------------
36−
37−Example:
38−-------------------------------
39−let upstream = --
40−in upstream
41− with halogen.version = "master"
42− with halogen.repo = "https://example.com/path/to/git/repo.git"
43−
44− with halogen-vdom.version = "v4.0.0"
45− with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies
46−-------------------------------
47−
48−### Additions
49−
50−Purpose:
51−- Add packages that aren't already included in the default package set
52−
53−Syntax:
54−where `<version>` is:
55−- a tag (i.e. "v4.0.0")
56−- a branch (i.e. "master")
57−- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977")
58−-------------------------------
59−let upstream = --
60−in upstream
61− with new-package-name =
62− { dependencies =
63− [ "dependency1"
64− , "dependency2"
65− ]
66− , repo =
67− "https://example.com/path/to/git/repo.git"
68− , version =
69− "<version>"
70− }
71−-------------------------------
72−
73−Example:
74−-------------------------------
75−let upstream = --
76−in upstream
77− with benchotron =
78− { dependencies =
79− [ "arrays"
80− , "exists"
81− , "profunctor"
82− , "strings"
83− , "quickcheck"
84− , "lcg"
85− , "transformers"
86− , "foldable-traversable"
87− , "exceptions"
88− , "node-fs"
89− , "node-buffer"
90− , "node-readline"
91− , "datetime"
92− , "now"
93− ]
94− , repo =
95− "https://github.com/hdgarrood/purescript-benchotron.git"
96− , version =
97− "v7.0.0"
98− }
99−-------------------------------
100−-}
101−
102−let upstream =
103− https://github.com/purescript/package-sets/releases/download/psc-0.15.4-20221124/packages.dhall
104− sha256:792255bbd8e2141468d967325f3e78246cb7e500bf3ab6d76d5b22dffbb09d49
105−in upstream
spago.dhalldeleted−42
@@ -1,42 +0,0 @@
1−{-
2−Welcome to a Spago project!
3−You can edit this file as you like.
4−
5−Need help? See the following resources:
6−- Spago documentation: https://github.com/purescript/spago
7−- Dhall language tour: https://docs.dhall-lang.org/tutorials/Language-Tour.html
8−
9−When creating a new Spago project, you can use
10−`spago init --no-comments` or `spago init -C`
11−to generate this file without the comments in this block.
12−-}
13−{ name = "indexed-db"
14−, dependencies =
15− [ "aff"
16− , "arrays"
17− , "avar"
18− , "console"
19− , "control"
20− , "datetime"
21− , "effect"
22− , "either"
23− , "enums"
24− , "exceptions"
25− , "foldable-traversable"
26− , "foreign"
27− , "functions"
28− , "identity"
29− , "lists"
30− , "maybe"
31− , "nonempty"
32− , "now"
33− , "nullable"
34− , "prelude"
35− , "read"
36− , "spec"
37− , "transformers"
38− , "tuples"
39− ]
40−, packages = ./packages.dhall
41−, sources = [ "src/**/*.purs", "test/**/*.purs" ]
42−}
src/Database/IndexedDB/Core.js+5−36
@@ -1,52 +1,21 @@
1−const toArray = function toArray(xs) {
2− return Array.prototype.slice.apply(xs);
3−};
4−
5−
6−export function _showCursor(cursor) {
7− return '(IDBCursor ' +
8− '{ direction: ' + cursor.direction +
9− ', key: ' + cursor.key +
10− ', primaryKey: ' + cursor.primaryKey +
11− ' })';
12−};
13−
14−export function _showDatabase(db) {
1+exports._showDatabase = function _showDatabase(db) {
15 return '(IDBDatabase ' +
2 return '(IDBDatabase ' +
16 '{ name: ' + db.name +
3 '{ name: ' + db.name +
17− ', objectStoreNames: [' + toArray(db.objectStoreNames).join(', ') + ']' +
4+ ', objectStoreNames: [' + exports.toArray(db.objectStoreNames).join(', ') + ']' +
18 ', version: ' + db.version +
5 ', version: ' + db.version +
19 ' })';
6 ' })';
20};
7};
21
8
22−export function _showIndex(index) {
23− return '(IDBIndex ' +
24− '{ name: ' + index.name +
25− ', keyPath: ' + index.keyPath +
26− ', multiEntry: ' + index.multiEntry +
27− ', unique: ' + index.unique +
28− ' })';
29−};
30−
31−export function _showKeyRange(range) {
32− return '(IDBKeyRange ' +
33− '{ lower: ' + range.lower +
34− ', upper: ' + range.upper +
35− ', lowerOpen: ' + range.lowerOpen +
36− ', upperOpen: ' + range.upperOpen +
37− ' })';
38−};
39−
40−export function _showObjectStore(store) {
9+exports._showObjectStore = function _showObjectStore(store) {
41 return '(IDBObjectStore ' +
10 return '(IDBObjectStore ' +
42 '{ autoIncrement: ' + store.autoIncrement +
11 '{ autoIncrement: ' + store.autoIncrement +
43− ', indexNames: [' + toArray(store.indexNames).join(', ') + ']' +
12+ ', indexNames: [' + exports.toArray(store.indexNames).join(', ') + ']' +
44 ', keyPath: ' + store.keyPath +
13 ', keyPath: ' + store.keyPath +
45 ', name: ' + store.name +
14 ', name: ' + store.name +
46 ' })';
15 ' })';
47};
16};
48
17
49−export function _showTransaction(tx) {
18+exports._showTransaction = function _showTransaction(tx) {
50 return '(IDBTransaction ' +
19 return '(IDBTransaction ' +
51 '{ error: ' + tx.error +
20 '{ error: ' + tx.error +
52 ', mode: ' + tx.mode +
21 ', mode: ' + tx.mode +
src/Database/IndexedDB/Core.purs+45−177
@@ -1,242 +1,110 @@
1−-- | The Core module gathers types used across the library and provides basic Show instances for
2−-- | those types.
3module Database.IndexedDB.Core
1module Database.IndexedDB.Core
4− -- * Effects
2+ ( class FromString, parse
5− (
3+ , INDEXED_DB
6− -- IDB
4+ , CursorDirection(..)
7−
5+ , CursorSource(..)
8− -- * Types
9− Database
6+ , Database
10 , Index
7 , Index
11 , KeyCursor
8 , KeyCursor
12 , KeyRange
9 , KeyRange
13 , ObjectStore
10 , ObjectStore
14 , Transaction
11 , Transaction
15− , ValueCursor
16− , CursorDirection(..)
17− , CursorSource(..)
18− , KeyPath
19 , TransactionMode(..)
12 , TransactionMode(..)
20−
13+ , ValueCursor
21− -- * Classes
22− , class IDBConcreteCursor
23− , class IDBCursor
24− , class IDBDatabase
25− , class IDBIndex
26− , class IDBKeyRange
27− , class IDBTransaction
28− , class IDBObjectStore
29−
30− -- * Re-Exports
31 , module Database.IndexedDB.IDBKey
14 , module Database.IndexedDB.IDBKey
32 ) where
15 ) where
33
16
34−import Prelude (class Show)
17+import Prelude (class Show)
35
18
36−import Data.Maybe (Maybe(..))
19+import Control.Monad.Eff (kind Effect)
37−import Data.String.Read (class Read)
20+import Data.Maybe (Maybe(..))
38
21
39import Database.IndexedDB.IDBKey
22import Database.IndexedDB.IDBKey
40
23
41−--------------------
42−-- TYPES
43−--
44−
45−-- | Each origin has an associated set of databases. A database has zero or more object
46−-- | stores which hold the data stored in the database.
47−foreign import data Database :: Type
48−
49−-- | An index allows looking up records in an object store using properties of the values
50−-- | in the object stores records.
51−foreign import data Index :: Type
52−
53−-- | A key range is a continuous interval over some data type used for keys.
54−foreign import data KeyRange :: Type
55−
56−-- | A cursor is used to iterate over a range of records in an index or an object store
57−-- | in a specific direction. A KeyCursor doesn't hold any value.
58−foreign import data KeyCursor :: Type
59−
60−-- | A Transaction is used to interact with the data in a database.
61−-- | Whenever data is read or written to the database it is done by using a transaction.
62−foreign import data Transaction :: Type
63−
64−-- | An object store is the primary storage mechanism for storing data in a database.
65−foreign import data ObjectStore :: Type
66−
67−-- | A cursor is used to iterate over a range of records in an index or an object store
68−-- | in a specific direction. A ValueCursor also holds the value corresponding to matching key.
69−foreign import data ValueCursor :: Type
70−
71−-- | A cursor has a direction that determines whether it moves in monotonically
72−-- | increasing or decreasing order of the record keys when iterated, and if it
73−-- | skips duplicated values when iterating indexes.
74−-- | The direction of a cursor also determines if the cursor initial position is at
75−-- | the start of its source or at its end.
76−data CursorDirection
77− = Next
78− | NextUnique
79− | Prev
80− | PrevUnique
81
24
82−-- | If the source of a cursor is an object store, the effective object store of
25+class FromString a where
83−-- | the cursor is that object store and the effective key of the cursor is the
26+ parse :: String -> Maybe a
84−-- | cursor’s position. If the source of a cursor is an index, the effective object
85−-- | store of the cursor is that index’s referenced object store and the effective key
86−-- | is the cursor’s object store position.
87−data CursorSource
88− = ObjectStore ObjectStore
89− | Index Index
90
27
91−-- | A key path is a list of strings that defines how to extract a key from a value.
92−-- | A valid key path is one of:
93−-- |
94−-- | - An empty list.
95−-- | - An singleton identifier, which is a string matching the IdentifierName production from the ECMAScript Language Specification [ECMA-262].
96−-- | - A singleton string consisting of two or more identifiers separated by periods (U+002E FULL STOP).
97−-- | - A non-empty list containing only strings conforming to the above requirements.
98−type KeyPath = Array String
99
28
100−-- | A transaction has a mode that determines which types of interactions can be performed
29+data CursorDirection = Next | NextUnique | Prev | PrevUnique
101−-- | upon that transaction. The mode is set when the transaction is created and remains
102−-- | fixed for the life of the transaction.
103−data TransactionMode
104− = ReadOnly -- ^ The transaction is only allowed to read data.
105− | ReadWrite -- ^ The transaction is allowed to read, modify and delete data from existing object stores
106− | VersionChange -- ^ The transaction is allowed to read, modify and delete data from existing object stores, and can also create and remove object stores and indexes.
107
30
108−--------------------
109−-- Classes
110−--
111
31
112−-- | A concrete cursor not only shares IDBCursor properties, but also some
32+data CursorSource = ObjectStore ObjectStore | Index Index
113−-- | specific attributes (see KeyCursor or CursorWithValue).
114−class (IDBCursor cursor) <= IDBConcreteCursor cursor
115
33
116−-- | Cursor objects implement the IDBCursor interface.
117−-- | There is only ever one IDBCursor instance representing a given cursor.
118−-- | There is no limit on how many cursors can be used at the same time.
119−class IDBCursor cursor
120
34
121−-- | The IDBDatabase interface represents a connection to a database.
35+data TransactionMode = ReadOnly | ReadWrite | VersionChange
122−class IDBDatabase db
123
36
124−-- | The IDBIndex interface represents an index handle.
125−-- | Any of these methods throw an "TransactionInactiveError" DOMException
126−-- | if called when the transaction is not active.
127−class IDBIndex index
128
37
129−-- | The IDBKeyRange interface represents a key range.
38+foreign import data INDEXED_DB :: Effect
130−class IDBKeyRange range
131
39
132−-- | The IDBtransaction interface.
133−class IDBTransaction tx
134
40
135−-- | The IDBObjectStore interface represents an object store handle.
41+foreign import data Database :: Type
136−class IDBObjectStore store
137
42
138−--------------------
139−-- INSTANCES
140−--
141
43
142−instance idbCursorKeyCursor :: IDBCursor KeyCursor
44+foreign import data Index :: Type
143
45
144−instance idbCursorValueCursor :: IDBCursor ValueCursor
145
46
146−instance idbConcreteCursorKeyCursor :: IDBConcreteCursor KeyCursor
47+foreign import data KeyCursor :: Type
147
48
148−instance idbConcreteCursorValueCursor :: IDBConcreteCursor ValueCursor
149
49
150−instance idbDatabaseDatabase :: IDBDatabase Database
50+foreign import data KeyRange :: Type
151
51
152−instance idbIndexIndex :: IDBIndex Index
153
52
154−instance idbIndexObjectStore :: IDBIndex ObjectStore
53+foreign import data ObjectStore :: Type
155
54
156−instance idbKeyRangeKeyRange :: IDBKeyRange KeyRange
157
55
158−instance idbObjectStoreObjectStore :: IDBObjectStore ObjectStore
56+foreign import data Transaction :: Type
159
57
160−instance idbTransactionTransaction :: IDBTransaction Transaction
161
58
162−instance showKeyCursor :: Show KeyCursor where
59+foreign import data ValueCursor :: Type
163− show = _showCursor
164
60
165−instance showValueCursor :: Show ValueCursor where
166− show = _showCursor
167
61
62+foreign import _showDatabase :: Database -> String
168−instance showIndex :: Show Index where
63+instance showDatabase :: Show Database where
169− show = _showIndex
64+ show = _showDatabase
170
65
171−instance showKeyRange :: Show KeyRange where
172− show = _showKeyRange
173
66
67+foreign import _showObjectStore :: ObjectStore -> String
174instance showObjectStore :: Show ObjectStore where
68instance showObjectStore :: Show ObjectStore where
175 show = _showObjectStore
69 show = _showObjectStore
176
70
71+
72+foreign import _showTransaction :: Transaction -> String
177instance showTransaction :: Show Transaction where
73instance showTransaction :: Show Transaction where
178 show = _showTransaction
74 show = _showTransaction
179
75
180−instance showDatabase :: Show Database where
181− show = _showDatabase
182
76
183instance showCursorDirection :: Show CursorDirection where
77instance showCursorDirection :: Show CursorDirection where
184 show x =
78 show x =
185 case x of
79 case x of
186− Next -> "next"
80+ Next -> "next"
187 NextUnique -> "nextunique"
81 NextUnique -> "nextunique"
188− Prev -> "prev"
82+ Prev -> "prev"
189 PrevUnique -> "prevunique"
83 PrevUnique -> "prevunique"
190
84
85+
191instance showTransactionMode :: Show TransactionMode where
86instance showTransactionMode :: Show TransactionMode where
192 show x =
87 show x =
193 case x of
88 case x of
194− ReadOnly -> "readonly"
89+ ReadOnly -> "readonly"
195− ReadWrite -> "readwrite"
90+ ReadWrite -> "readwrite"
196 VersionChange -> "versionchange"
91 VersionChange -> "versionchange"
197
92
93+
198−instance readCursorDirection :: Read CursorDirection where
94+instance fromStringCursorDirection :: FromString CursorDirection where
199− read s =
95+ parse s =
200 case s of
96 case s of
201− "next" -> Just Next
97+ "next" -> Just Next
202 "nextunique" -> Just NextUnique
98 "nextunique" -> Just NextUnique
203− "prev" -> Just Prev
99+ "prev" -> Just Prev
204 "prevunique" -> Just PrevUnique
100 "prevunique" -> Just PrevUnique
205− _ -> Nothing
101+ _ -> Nothing
206
102
103+
207−instance readTransactionMode :: Read TransactionMode where
104+instance fromStringTransactionMode :: FromString TransactionMode where
208− read s =
105+ parse s =
209 case s of
106 case s of
210− "readonly" -> Just ReadOnly
107+ "readonly" -> Just ReadOnly
211− "readwrite" -> Just ReadWrite
108+ "readwrite" -> Just ReadWrite
212 "versionchange" -> Just VersionChange
109 "versionchange" -> Just VersionChange
213− _ -> Nothing
110+ _ -> Nothing
214−
215−--------------------
216−-- FFI
217−--
218−
219−foreign import _showCursor
220− :: forall cursor
221− . cursor
222− -> String
223−
224−foreign import _showDatabase
225− :: Database
226− -> String
227−
228−foreign import _showIndex
229− :: Index
230− -> String
231−
232−foreign import _showKeyRange
233− :: KeyRange
234− -> String
235−
236−foreign import _showObjectStore
237− :: ObjectStore
238− -> String
239−
240−foreign import _showTransaction
241− :: Transaction
242− -> String
src/Database/IndexedDB/IDBCursor.js+32−95
@@ -1,6 +1,6 @@
1const errorHandler = function errorHandler(cb) {
1const errorHandler = function errorHandler(cb) {
2 return function _handler(e) {
2 return function _handler(e) {
3− cb(e.target.error);
3+ cb(new Error(e.target.error.name));
4 };
4 };
5};
5};
6
6
@@ -10,135 +10,72 @@ const successHandler = function successHandler(cb) {
10 };
10 };
11};
11};
12
12
13+
13−export function _advance(cursor, count) {
14+exports._advance = function _advance(cursor, count) {
14− return function aff(error, success) {
15+ return function eff() {
15 try {
16 try {
16 cursor.advance(count);
17 cursor.advance(count);
17− success();
18 } catch (e) {
18 } catch (e) {
19− error(e);
19+ throw new Error(e.name);
20 }
20 }
21−
22− return function canceler(_, cancelerError) {
23− cancelerError(new Error("Can't cancel IDB Effects"));
24− };
25 };
21 };
26};
22};
27
23
28−export function _continue(cursor, key) {
24+exports._continue = function _continue(cursor, key) {
29− return function aff(error, success) {
25+ return function eff() {
30 try {
26 try {
31 cursor.continue(key || undefined);
27 cursor.continue(key || undefined);
32− success();
33 } catch (e) {
28 } catch (e) {
34− error(e);
29+ throw new Error(e.name);
35 }
30 }
36−
37− return function canceler(_, cancelerError) {
38− cancelerError(new Error("Can't cancel IDB Effects"));
39− };
40 };
31 };
41};
32};
42
33
43−export function _continuePrimaryKey(cursor, key, primaryKey) {
34+exports._continuePrimaryKey = function _continuePrimaryKey(cursor, key, primaryKey) {
44− return function aff(error, success) {
35+ return function eff() {
45 try {
36 try {
46 cursor.continuePrimaryKey(key, primaryKey);
37 cursor.continuePrimaryKey(key, primaryKey);
47− success();
48 } catch (e) {
38 } catch (e) {
49− error(e);
39+ throw new Error(e.name);
50 }
40 }
51−
52− return function canceler(_, cancelerError) {
53− cancelerError(new Error("Can't cancel IDB Effects"));
54− };
55 };
41 };
56};
42};
57
43
58−export function _delete(cursor) {
44+exports._delete = function _delete(cursor) {
59− return function aff(error, success) {
45+ return function aff(success, error) {
60− try {
61− const request = cursor.delete();
46+ const request = cursor.delete();
62− request.onsuccess = successHandler(success);
47+ request.onsuccess = successHandler(success);
63− request.onerror = errorHandler(error);
48+ request.onerror = errorHandler(error);
64− } catch (e) {
65− error(e);
66− }
67−
68− return function canceler(_, cancelerError) {
69− cancelerError(new Error("Can't cancel IDB Effects"));
70− };
71 };
49 };
72};
50};
73
51
74−export function _direction(fromString, cursor) {
52+exports._direction = function _direction(fromString, cursor) {
75 return fromString(cursor.direction);
53 return fromString(cursor.direction);
76};
54};
77
55
78−export function _key(cursor) {
56+exports._key = function _key(cursor) {
79− return function aff(error, success) {
80− try {
81− success(cursor.key);
57+ return cursor.key;
82− } catch (e) {
83− error(e);
84− }
85−
86− return function canceler(_, cancelerError) {
87− cancelerError(new Error("Can't cancel IDB Effects"));
88− };
89− };
90};
58};
91
59
92−export function _primaryKey(cursor) {
60+exports._primaryKey = function _primaryKey(cursor) {
93− return function aff(error, success) {
94− try {
95− success(cursor.primaryKey);
61+ return cursor.primaryKey;
96− } catch (e) {
97− error(e);
98− }
99−
100− return function canceler(_, cancelerError) {
101− cancelerError(new Error("Can't cancel IDB Effects"));
102− };
103− };
104};
62};
105
63
106−export function _source(IDBObjectStore, IDBIndex, cursor) {
64+exports._source = function _source(IDBObjectStore, IDBIndex, cursor) {
107− switch (cursor.source.constructor.name) {
108− case 'IDBIndex':
109− return IDBIndex(cursor.source);
65+ console.log(typeof cursor.source);
110− case 'IDBObjectStore':
66+ console.log(Object.getPrototypeOf(cursor.source));
111− return IDBObjectStore(cursor.source);
67+ console.log(cursor.source);
112− default:
68+ throw new Error('TODO');
113− throw Object.create(Error.prototype, {
114− message: {
115− enumerable: true,
116− value: 'Unable to retrieve the cursor\'s source constructor.',
117− },
118− name: {
119− enumerable: true,
120− value: 'UnexpectedCursorSource',
121− },
122− });
123− }
124};
69};
125
70
126−export function _update(cursor, value) {
71+exports._update = function _update(cursor, value) {
127− return function aff(error, success) {
72+ return function aff(success, error) {
128− try {
129− const request = cursor.update(value);
73+ const request = cursor.update(value);
130− request.onsuccess = successHandler(success);
74+ request.onsuccess = successHandler(success);
131− request.onerror = errorHandler(error);
75+ request.onerror = errorHandler(error);
132− } catch (e) {
133− error(e);
134− }
135−
136− return function canceler(_, cancelerError) {
137− cancelerError(new Error("Can't cancel IDB Effects"));
138− };
139 };
76 };
140};
77};
141
78
142−export function _value(cursor) {
79+exports._value = function _value(cursor) {
143 return cursor.value;
80 return cursor.value;
144};
81};
src/Database/IndexedDB/IDBCursor.purs+108−154
@@ -1,186 +1,140 @@
1−-- | A cursor is used to iterate over a range of records in an index or
2−-- | an object store in a specific direction.
3module Database.IndexedDB.IDBCursor
1module Database.IndexedDB.IDBCursor
4− -- * Interface
5− ( advance
6− , continue
7− , continuePrimaryKey
2+ ( class IDBCursor, advance, continue, continuePrimaryKey, delete, update
8− , delete
9− , update
10−
11− -- * Attributes
12 , direction
3 , direction
13 , key
4 , key
14 , primaryKey
5 , primaryKey
15 , source
6 , source
7+ , direction'
8+ , key'
9+ , primaryKey'
10+ , source'
16 , value
11 , value
17 ) where
12 ) where
18
13
14+import Prelude (Unit, (>>>))
15+
16+import Control.Monad.Aff (Aff)
17+import Control.Monad.Eff (Eff)
18+import Control.Monad.Eff.Exception (EXCEPTION)
19+import Data.Function.Uncurried as Fn
20+import Data.Function.Uncurried (Fn2, Fn3)
21+import Data.Maybe (Maybe)
22+import Data.Nullable (Nullable, toNullable)
23+import Data.Foreign (Foreign, toForeign, unsafeFromForeign)
24+
19import Database.IndexedDB.Core
25import Database.IndexedDB.Core
20
26
21−import Data.Function.Uncurried (Fn2, Fn3)
22−import Data.Function.Uncurried as Fn
23−import Data.Maybe (Maybe)
24−import Data.Nullable (Nullable, toNullable)
25−import Data.String.Read (read)
26−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key, toKey, unsafeFromKey)
27−import Effect.Aff (Aff)
28−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
29−import Foreign (Foreign, unsafeFromForeign, unsafeToForeign)
30−import Prelude (Unit, ($), (>>>), (<<<), map)
31
27
32--------------------
28--------------------
33-- INTERFACES
29-- INTERFACES
34--
30--
31+class IDBCursor cursor where
32+ advance :: forall eff. cursor -> Int -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
33+ continue :: forall eff. cursor -> Maybe Key -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
34+ continuePrimaryKey :: forall eff. cursor -> Key -> Key -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
35+ delete :: forall eff. cursor -> Aff (idb ::INDEXED_DB, exception :: EXCEPTION | eff) Unit
36+ update :: forall val eff. cursor -> val -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Key
35
37
36−-- | Advances the cursor through the next count records in range.
37−advance
38− :: forall cursor
39− . (IDBCursor cursor)
40− => cursor
41− -> Int
42− -> Aff Unit
43−advance c =
44− fromEffectFnAff <<< Fn.runFn2 _advance c
45−
46−-- | Advances the cursor to the next record in range matching or after key.
47−continue
48− :: forall k cursor
49− . (IDBKey k)
50− => (IDBCursor cursor)
51− => cursor
52− -> Maybe k
53− -> Aff Unit
54−continue c mk =
55− fromEffectFnAff $ Fn.runFn2 _continue c (toNullable $ map (toKey >>> unsafeFromKey) mk)
56−
57−-- | Advances the cursor to the next record in range matching or after key and primaryKey. Throws an "InvalidAccessError" DOMException if the source is not an index.
58−continuePrimaryKey
59− :: forall k cursor
60− . (IDBKey k)
61− => (IDBCursor cursor)
62− => cursor
63− -> k
64− -> k
65− -> Aff Unit
66−continuePrimaryKey c k1 k2 =
67− fromEffectFnAff $ Fn.runFn3 _continuePrimaryKey c (unsafeFromKey $ toKey k1) (unsafeFromKey $ toKey k2)
68−
69−-- | Delete the record pointed at by the cursor with a new value.
70−delete
71− :: forall cursor
72− . (IDBCursor cursor)
73− => cursor
74− -> Aff Unit
75−delete =
76− fromEffectFnAff <<< _delete
77−
78−-- | Update the record pointed at by the cursor with a new value.
79−-- |
80−-- | Throws a "DataError" DOMException if the effective object store uses
81−-- | in-line keys and the key would have changed.
82−update
83− :: forall val cursor
84− . (IDBCursor cursor)
85− => cursor
86− -> val
87− -> Aff Key
88−update c =
89− map toKey <<< fromEffectFnAff <<< Fn.runFn2 _update c <<< unsafeToForeign
90
38
91--------------------
39--------------------
92-- ATTRIBUTES
40-- ATTRIBUTES
93--
41--
94−
95−-- | Returns the direction (Next|NextUnique|Prev|PrevUnique) of the cursor.
96−direction
97− :: forall cursor
98− . (IDBConcreteCursor cursor)
99− => cursor
100− -> CursorDirection
42+direction :: KeyCursor -> CursorDirection
101direction =
43direction =
102− Fn.runFn2 _direction (read >>> toNullable)
44+ Fn.runFn2 _direction (parse >>> toNullable)
103−
45+
104−-- | Returns the key of the cursor. Throws a "InvalidStateError" DOMException
46+
105−-- | if the cursor is advancing or is finished.
47+key :: KeyCursor -> Key
106−key
107− :: forall cursor
108− . (IDBConcreteCursor cursor)
109− => cursor
110− -> Aff Key
111key =
48key =
112− map toKey <<< fromEffectFnAff <<< _key
49+ _key
113−
50+
114−-- | Returns the effective key of the cursor. Throws a "InvalidStateError" DOMException
51+
115−-- | if the cursor is advancing or is finished.
116−primaryKey
52+primaryKey :: KeyCursor -> Key
117− :: forall cursor
118− . (IDBConcreteCursor cursor)
119− => cursor
120− -> Aff Key
121primaryKey =
53primaryKey =
122− map toKey <<< fromEffectFnAff <<< _primaryKey
54+ _primaryKey
123−
55+
124−-- | Returns the IDBObjectStore or IDBIndex the cursor was opened from.
56+
125−source
126− :: forall cursor
127− . (IDBConcreteCursor cursor)
128− => cursor
129− -> CursorSource
57+source :: KeyCursor -> CursorSource
130source =
58source =
131 Fn.runFn3 _source ObjectStore Index
59 Fn.runFn3 _source ObjectStore Index
132
60
133−value
61+
134− :: forall val
62+-- NOTE: Polymorphism not used here cause *we want* those methods to be distincs for
63+-- the concrete types mostly for consistency with the Database.IndexedDB.IDBIndex module
64+-- where the IDBIndex interfaces is shared by Index and ObjectStore, but attributes of
65+-- respective concrete types aren't shared.
66+direction' :: ValueCursor -> CursorDirection
67+direction' =
68+ Fn.runFn2 _direction (parse >>> toNullable)
69+
70+
71+key' :: ValueCursor -> Key
72+key' =
73+ _key
74+
75+
76+primaryKey' :: ValueCursor -> Key
77+primaryKey' =
78+ _primaryKey
79+
80+
81+source' :: ValueCursor -> CursorSource
82+source' =
83+ Fn.runFn3 _source ObjectStore Index
84+
85+
135− . ValueCursor
86+value :: forall val. ValueCursor -> val
136− -> val
137value =
87value =
138 _value >>> unsafeFromForeign
88 _value >>> unsafeFromForeign
139
89
90+
91+--------------------
92+-- INSTANCES
93+--
94+instance keyCursorKeyCursor :: IDBCursor KeyCursor where
95+ advance = Fn.runFn2 _advance
96+ continue c mk = Fn.runFn2 _continue c (toNullable mk)
97+ continuePrimaryKey = Fn.runFn3 _continuePrimaryKey
98+ delete = _delete
99+ update c = toForeign >>> Fn.runFn2 _update c
100+
101+
102+instance valueCursorKeyCursor :: IDBCursor ValueCursor where
103+ advance = Fn.runFn2 _advance
104+ continue c mk = Fn.runFn2 _continue c (toNullable mk)
105+ continuePrimaryKey = Fn.runFn3 _continuePrimaryKey
106+ delete = _delete
107+ update c = toForeign >>> Fn.runFn2 _update c
108+
109+
140--------------------
110--------------------
141-- FFI
111-- FFI
142--
112--
113+foreign import _advance :: forall cursor eff. Fn2 cursor Int (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit)
114+
115+
116+foreign import _continue :: forall cursor eff. Fn2 cursor (Nullable Key) (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit)
117+
118+
119+foreign import _continuePrimaryKey :: forall cursor eff. Fn3 cursor Key Key (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit)
120+
121+
122+foreign import _delete :: forall cursor eff. cursor -> (Aff (idb ::INDEXED_DB, exception :: EXCEPTION | eff) Unit)
123+
124+
125+foreign import _direction :: forall cursor. Fn2 (String -> Nullable CursorDirection) cursor CursorDirection
126+
127+
128+foreign import _key :: forall cursor. cursor -> Key
129+
130+
131+foreign import _primaryKey :: forall cursor. cursor -> Key
132+
133+
134+foreign import _source :: forall cursor. Fn3 (ObjectStore -> CursorSource) (Index -> CursorSource) cursor CursorSource
135+
136+
137+foreign import _update :: forall cursor eff. Fn2 cursor Foreign (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Key)
138+
143
139
144−foreign import _advance
145− :: forall cursor
146− . Fn2 cursor Int (EffectFnAff Unit)
147−
148−foreign import _continue
149− :: forall cursor
150− . Fn2 cursor (Nullable Foreign) (EffectFnAff Unit)
151−
152−foreign import _continuePrimaryKey
153− :: forall cursor
154− . Fn3 cursor Foreign Foreign (EffectFnAff Unit)
155−
156−foreign import _delete
157− :: forall cursor
158− . cursor
159− -> (EffectFnAff Unit)
160−
161−foreign import _direction
162− :: forall cursor
163− . Fn2 (String -> Nullable CursorDirection) cursor CursorDirection
164−
165−foreign import _key
166− :: forall cursor
167− . cursor
168− -> EffectFnAff Key
169−
170−foreign import _primaryKey
171− :: forall cursor
172− . cursor
173− -> EffectFnAff Key
174−
175−foreign import _source
176− :: forall cursor
177− . Fn3 (ObjectStore -> CursorSource) (Index -> CursorSource) cursor CursorSource
178−
179−foreign import _update
180− :: forall cursor
181− . Fn2 cursor Foreign (EffectFnAff Foreign)
182−
183−foreign import _value
184− :: forall cursor val
140+foreign import _value :: forall cursor val. cursor -> val
185− . cursor
186− -> val
src/Database/IndexedDB/IDBDatabase.js+20−95
@@ -1,25 +1,20 @@
1−const toArray = function toArray(xs) {
1+const $Core = require('Database.IndexedDB.Core/foreign');
2− return Array.prototype.slice.apply(xs);
2+
3−};
3+const toArray = $Core.toArray;
4
4
5
5
6−export function _close(db) {
6+exports._close = function _close(db) {
7− return function aff(error, success) {
7+ return function eff() {
8 try {
8 try {
9 db.close();
9 db.close();
10− success();
11 } catch (e) {
10 } catch (e) {
12− error(e);
11+ throw new Error(e.name);
13 }
12 }
14−
15− return function canceler(_, cancelerError) {
16− cancelerError(new Error("Can't cancel IDB Effects"));
17− };
18 };
13 };
19};
14};
20
15
21−export function _createObjectStore(db, name, opts) {
16+exports._createObjectStore = function _createObjectStore(db, name, opts) {
22− return function aff(error, success) {
17+ return function eff() {
23 var keyPath;
18 var keyPath;
24
19
25 try {
20 try {
@@ -36,114 +31,44 @@ export function _createObjectStore(db, name, opts) {
36 default:
31 default:
37 keyPath = opts.keyPath;
32 keyPath = opts.keyPath;
38 }
33 }
39−
40− const store = db.createObjectStore(name, {
34+ return db.createObjectStore(name, {
41 autoIncrement: opts.autoIncrement,
35 autoIncrement: opts.autoIncrement,
42 keyPath: keyPath,
36 keyPath: keyPath,
43 });
37 });
44− success(store);
45 } catch (e) {
38 } catch (e) {
46− error(e);
39+ throw new Error(e.name);
47 }
40 }
48−
49− return function canceler(_, cancelerError) {
50− cancelerError(new Error("Can't cancel IDB Effects"));
51− };
52 };
41 };
53};
42};
54
43
55−export function _deleteObjectStore(db, name) {
44+exports._deleteObjectStore = function _deleteObjectStore(db, name) {
56− return function aff(error, success) {
45+ return function eff() {
57 try {
46 try {
58 db.deleteObjectStore(name);
47 db.deleteObjectStore(name);
59− success();
60 } catch (e) {
48 } catch (e) {
61− error(e);
49+ throw new Error(e.name);
62 }
50 }
63−
64− return function canceler(_, cancelerError) {
65− cancelerError(new Error("Can't cancel IDB Effects"));
66− };
67 };
51 };
68};
52};
69
53
70−export function _name(db) {
54+exports._name = function _name(db) {
71 return db.name;
55 return db.name;
72};
56};
73
57
74−export function _objectStoreNames(db) {
58+exports._objectStoreNames = function _objectStoreNames(db) {
75 return toArray(db.objectStoreNames);
59 return toArray(db.objectStoreNames);
76};
60};
77
61
78−export function _onAbort(db, f) {
62+exports._transaction = function _transaction(show, db, stores, mode) {
79− return function aff(error, success) {
80− db.onabort = function onabort() {
81− f();
82− };
83− success();
84−
85− return function canceler(_, cancelerError) {
86− cancelerError(new Error("Can't cancel IDB Effects"));
87− };
88− };
89−};
90−
91−export function _onClose(db, f) {
92− return function aff(error, success) {
93− db.onclose = function onclose() {
94− f();
95− };
96− success();
97−
98− return function canceler(_, cancelerError) {
99− cancelerError(new Error("Can't cancel IDB Effects"));
100− };
101− };
102−};
103−
104−export function _onError(db, f) {
105− return function aff(error, success) {
106− db.onerror = function onerror(e) {
107− f(e.target.error)();
108− };
109− success();
110−
111− return function canceler(_, cancelerError) {
112− cancelerError(new Error("Can't cancel IDB Effects"));
113− };
114− };
115−};
116−
117−export function _onVersionChange(db, f) {
118− return function aff(error, success) {
119− db.onversionchange = function onversionchange(e) {
120− f({ oldVersion: e.oldVersion, newVersion: e.newVersion })();
121− };
122− success();
123−
124− return function canceler(_, cancelerError) {
125− cancelerError(new Error("Can't cancel IDB Effects"));
126− };
127− };
128−};
129−
130−export function _transaction(db, stores, mode) {
131− return function aff(error, success) {
63+ return function eff() {
132− var transaction;
133 try {
64 try {
134− transaction = db.transaction(stores, mode);
65+ return db.transaction(stores, show(mode));
135− success(transaction);
136 } catch (e) {
66 } catch (e) {
137− error(e);
67+ throw new Error(e.name);
138 }
68 }
139−
140− return function canceler(_, cancelerError, cancelerSuccess) {
141− transaction.abort();
142− cancelerSuccess();
143− };
144 };
69 };
145};
70};
146
71
147−export function _version(db) {
72+exports._version = function _version(db) {
148 return db.version;
73 return db.version;
149};
74};
src/Database/IndexedDB/IDBDatabase.purs+40−171
@@ -1,215 +1,84 @@
1−-- | Each origin has an associated set of databases. A database has zero or more object
2−-- | stores which hold the data stored in the database.
3module Database.IndexedDB.IDBDatabase
1module Database.IndexedDB.IDBDatabase
4− -- * Types
5− ( StoreName
6− , ObjectStoreParameters
7− , defaultParameters
8−
9− -- * Interface
10− , close
11− , createObjectStore
2+ ( class IDBDatabase, close, createObjectStore, deleteObjectStore, transaction
12− , deleteObjectStore
13− , transaction
14−
15− -- * Attributes
16 , name
3 , name
17 , objectStoreNames
4 , objectStoreNames
18 , version
5 , version
19−
20− -- * Event handlers
21− , onAbort
22− , onClose
23− , onError
24− , onVersionChange
25 ) where
6 ) where
26
7
27−import Database.IndexedDB.Core
28−
29−import Data.Function.Uncurried (Fn2, Fn3)
30−import Data.Function.Uncurried as Fn
31−import Effect (Effect)
32−import Effect.Aff (Aff)
33−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
34−import Effect.Exception (Error)
35−import Prelude (Unit, show, (<<<), ($))
8+import Prelude (Unit, show)
36−
37−--------------------
38−-- TYPES
39−--
40
9
41−-- | Type alias for StoreName
10+import Control.Monad.Eff (Eff)
42−type StoreName = String
11+import Control.Monad.Eff.Exception (EXCEPTION)
12+import Data.Function.Uncurried as Fn
13+import Data.Function.Uncurried (Fn2, Fn3, Fn4)
43
14
44−-- | Options provided when creating an object store.
15+import Database.IndexedDB.Core
45−type ObjectStoreParameters =
46− { keyPath :: KeyPath
47− , autoIncrement :: Boolean
48− }
49
16
50−defaultParameters :: ObjectStoreParameters
51−defaultParameters =
52− { keyPath: []
53− , autoIncrement: false
54− }
55
17
56--------------------
18--------------------
57-- INTERFACE
19-- INTERFACE
58--
20--
21+class IDBDatabase db where
22+ close :: forall eff. db -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
23+ createObjectStore :: forall eff. db -> String -> { keyPath :: Array String, autoIncrement :: Boolean } -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore
24+ deleteObjectStore :: forall eff . db -> String -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore
25+ transaction :: forall eff. db -> Array String -> TransactionMode -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Transaction
59
26
60−-- | Closes the connection once all running transactions have finished.
61−close
62− :: forall db
63− . (IDBDatabase db)
64− => db
65− -> Aff Unit
66−close =
67− fromEffectFnAff <<< _close
68−
69−-- | Creates a new object store with the given name and options and returns a new IDBObjectStore.
70−-- |
71−-- | Throws a "InvalidStateError" DOMException if not called within an upgrade transaction
72−createObjectStore
73− :: forall db
74− . (IDBDatabase db)
75− => db
76− -> StoreName
77− -> ObjectStoreParameters
78− -> Aff ObjectStore
79−createObjectStore db name' opts =
80− fromEffectFnAff $ Fn.runFn3 _createObjectStore db name' opts
81−
82−-- | Deletes the object store with the given name.
83−-- |
84−-- | Throws a "InvalidStateError" DOMException if not called within an upgrade transaction.
85−deleteObjectStore
86− :: forall db
87− . (IDBDatabase db)
88− => db
89− -> StoreName
90− -> Aff ObjectStore
91−deleteObjectStore db name' =
92− fromEffectFnAff $ Fn.runFn2 _deleteObjectStore db name'
93−
94−-- | Returns a new transaction with the given mode (ReadOnly|ReadWrite)
95−-- | and scope which in the form of an array of object store names.
96−transaction
97− :: forall db
98− . (IDBDatabase db)
99− => db
100− -> Array StoreName
101− -> TransactionMode
102− -> Aff Transaction
103−transaction db stores mode' =
104− fromEffectFnAff $ Fn.runFn3 _transaction db stores (show mode')
105
27
106--------------------
28--------------------
107-- ATTRIBUTES
29-- ATTRIBUTES
108--
30--
109−
110−-- | Returns the name of the database.
111−name
112− :: Database
31+name :: Database -> String
113− -> String
114name =
32name =
115 _name
33 _name
116
34
117−-- | Returns a list of the names of object stores in the database.
35+
118−objectStoreNames
36+objectStoreNames :: Database -> Array String
119− :: Database
120− -> Array String
121objectStoreNames =
37objectStoreNames =
122 _objectStoreNames
38 _objectStoreNames
123
39
124−-- | Returns the version of the database.
40+
125−version
126− :: Database
41+version :: Database -> Int
127− -> Int
128version =
42version =
129 _version
43 _version
130
44
45+
131--------------------
46--------------------
132−-- EVENT HANDLERS
47+-- INSTANCES
133--
48--
134−-- | Event handler for the `abort` event.
49+instance idbDatabaseDatabase :: IDBDatabase Database where
135−onAbort
50+ close =
136− :: Database
51+ _close
137− -> Effect Unit
52+
138− -> Aff Unit
53+ createObjectStore db name' opts =
139−onAbort db f =
54+ Fn.runFn3 _createObjectStore db name' opts
140− fromEffectFnAff $ Fn.runFn2 _onAbort db f
55+
141−
56+ deleteObjectStore db name' =
142−-- | Event handler for the `close` event.
57+ Fn.runFn2 _deleteObjectStore db name'
143−onClose
58+
144− :: Database
59+ transaction db stores mode' =
145− -> Effect Unit
60+ Fn.runFn4 _transaction show db stores mode'
146− -> Aff Unit
61+
147−onClose db f =
148− fromEffectFnAff $ Fn.runFn2 _onClose db f
149−
150−-- | Event handler for the `error` event.
151−onError
152− :: Database
153− -> (Error -> Effect Unit)
154− -> Aff Unit
155−onError db f =
156− fromEffectFnAff $ Fn.runFn2 _onError db f
157−
158−-- | Event handler for the `versionchange` event.
159−onVersionChange
160− :: Database
161− -> ( { oldVersion :: Int, newVersion :: Int }
162− -> Effect Unit
163− )
164− -> Aff Unit
165−onVersionChange db f =
166− fromEffectFnAff $ Fn.runFn2 _onVersionChange db f
167
62
168--------------------
63--------------------
169-- FFI
64-- FFI
170--
65--
66+foreign import _close :: forall db eff. db -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
67+
171
68
172−foreign import _close
69+foreign import _createObjectStore :: forall db eff. Fn3 db String { keyPath :: Array String, autoIncrement :: Boolean } (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore)
173− :: forall db
174− . db
175− -> EffectFnAff Unit
176
70
177−foreign import _createObjectStore
178− :: forall db
179− . Fn3 db String { keyPath :: Array String, autoIncrement :: Boolean } (EffectFnAff ObjectStore)
180
71
181−foreign import _deleteObjectStore
72+foreign import _deleteObjectStore :: forall db eff. Fn2 db String (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore)
182− :: forall db
183− . Fn2 db String (EffectFnAff ObjectStore)
184
73
185−foreign import _name
186− :: Database
187− -> String
188
74
189−foreign import _objectStoreNames
75+foreign import _name :: Database -> String
190− :: Database
191− -> Array String
192
76
193−foreign import _onAbort
194− :: forall db
195− . Fn2 db (Effect Unit) (EffectFnAff Unit)
196
77
197−foreign import _onClose
78+foreign import _objectStoreNames :: Database -> Array String
198− :: forall db
199− . Fn2 db (Effect Unit) (EffectFnAff Unit)
200
79
201−foreign import _onError
202− :: forall db
203− . Fn2 db (Error -> Effect Unit) (EffectFnAff Unit)
204
80
205−foreign import _onVersionChange
81+foreign import _transaction :: forall db eff. Fn4 (db -> String) db (Array String) TransactionMode (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Transaction)
206− :: forall db
207− . Fn2 db ({ oldVersion :: Int, newVersion :: Int } -> Effect Unit) (EffectFnAff Unit)
208
82
209−foreign import _transaction
210− :: forall db
211− . Fn3 db (Array String) String (EffectFnAff Transaction)
212
83
213−foreign import _version
84+foreign import _version :: Database -> Int
214− :: Database
215− -> Int
src/Database/IndexedDB/IDBFactory.js+21−42
@@ -1,6 +1,6 @@
1const errorHandler = function errorHandler(cb) {
1const errorHandler = function errorHandler(cb) {
2 return function _handler(e) {
2 return function _handler(e) {
3− cb(e.target.error);
3+ cb(new Error(e.target.error.name));
4 };
4 };
5};
5};
6
6
@@ -14,57 +14,36 @@ const noOp2 = function noOp2() {
14 return noOp;
14 return noOp;
15};
15};
16
16
17−const noOp3 = function noOp3() {
18− return noOp2;
19−};
20−
21−export function _deleteDatabase(name) {
22− return function aff(error, success) {
23− try {
24− const request = indexedDB.deleteDatabase(name);
25−
26− request.onsuccess = function onSuccess(e) {
27− success(e.oldVersion);
28− };
29
17
30− request.onerror = errorHandler(error);
18+exports._deleteDatabase = function _deleteDatabase(name) {
31− } catch (e) {
19+ return function aff(success, error) {
32− error(e);
20+ const request = indexedDB.deleteDatabase(name);
33− }
34
21
35− return function canceler(_, cancelerError) {
22+ request.onsuccess = function onSuccess(e) {
36− cancelerError(new Error("Can't cancel IDB Effects"));
23+ success(e.oldVersion);
37 };
24 };
25+
26+ request.onerror = errorHandler(error);
38 };
27 };
39};
28};
40
29
41−export function _open(fromMaybe, name, mver, req) {
30+exports._open = function _open(fromMaybe, name, mver, req) {
42 const ver = fromMaybe(undefined)(mver);
31 const ver = fromMaybe(undefined)(mver);
43
32
44− return function aff(error, success) {
33+ return function aff(success, error) {
45− try {
46− const request = indexedDB.open(name, ver);
34+ const request = indexedDB.open(name, ver);
47− request.onsuccess = function onSuccess(e) {
35+ request.onsuccess = function onSuccess(e) {
48− success(e.target.result);
36+ success(e.target.result);
49− };
50−
51− request.onblocked = function onBlocked() {
52− fromMaybe(noOp)(req.onBlocked)();
53− };
54−
55− request.onupgradeneeded = function onUpgradeNeeded(e) {
56− const meta = { oldVersion: e.oldVersion };
57− // eslint-disable-next-line max-len
58− fromMaybe(noOp3)(req.onUpgradeNeeded)(e.target.result)(e.target.transaction)(meta)();
59− };
37+ };
60
38
61− request.onerror = errorHandler(error);
39+ request.onblocked = function onBlocked() {
62− } catch (e) {
40+ fromMaybe(noOp)(req.onBlocked)();
63− error(e);
64− }
41+ };
65
42
66− return function canceler(_, cancelerError) {
43+ request.onupgradeneeded = function onUpgradeNeeded(e) {
67− cancelerError(new Error("Can't cancel IDB Effects"));
44+ fromMaybe(noOp2)(req.onUpgradeNeeded)(e.target.result)();
68 };
45 };
46+
47+ request.onerror = errorHandler(error);
69 };
48 };
70};
49};
src/Database/IndexedDB/IDBFactory.purs+21−61
@@ -1,79 +1,39 @@
1−-- | Database objects are accessed through methods on the IDBFactory interface.
2−-- | A single object implementing this interface is present in the global scope
3−-- | of environments that support Indexed DB operations.
4−module Database.IndexedDB.IDBFactory
1+module Database.IndexedDB.IDBFactory where
5− -- * Types
6− ( Callbacks
7− , DatabaseName
8− , Version
9
2
10− -- * Interface
3+import Prelude (Unit)
11− , deleteDatabase
4+
12− , open
5+import Control.Monad.Aff (Aff)
13− ) where
6+import Control.Monad.Eff (Eff)
7+import Data.Function.Uncurried as Fn
8+import Data.Function.Uncurried (Fn4)
9+import Data.Maybe (Maybe, fromMaybe)
14
10
15import Database.IndexedDB.Core
11import Database.IndexedDB.Core
16
12
17−import Data.Function.Uncurried (Fn4)
18−import Data.Function.Uncurried as Fn
19−import Data.Maybe (Maybe, fromMaybe)
20−import Effect (Effect)
21−import Effect.Aff (Aff)
22−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
23−import Prelude (Unit, ($), (<<<))
24
13
25--------------------
14--------------------
26−-- TYPES
15+-- INTERFACE
27--
16--
28−
17+type OpenRequest eff =
29−-- Type alias for binding listeners to an initial open action.
30−type Callbacks =
31− { onBlocked :: Maybe (Effect Unit)
18+ { onBlocked :: Maybe (Eff (idb :: INDEXED_DB | eff) Unit)
32− , onUpgradeNeeded :: Maybe (Database -> Transaction -> { oldVersion :: Int } -> Effect Unit)
19+ , onUpgradeNeeded :: Maybe (Database -> Eff (idb :: INDEXED_DB | eff) Unit)
33 }
20 }
34
21
35−-- | Type alias for DatabaseName.
36−type DatabaseName = String
37
22
38−-- | Type alias for Version.
39−type Version = Int
40−
41−--------------------
42−-- INTERFACE
43−--
44−
45−-- | Attempts to delete the named database. If the database already exists
46−-- | and there are open connections that don’t close in response to a
47−-- | `versionchange` event, the request will be blocked until all they close.
48−deleteDatabase
23+deleteDatabase :: forall eff. String -> Aff (idb :: INDEXED_DB | eff) Int
49− :: DatabaseName
50− -> Aff Int
51deleteDatabase =
24deleteDatabase =
52− fromEffectFnAff <<< _deleteDatabase
25+ _deleteDatabase
26+
53
27
54−-- | Attempts to open a connection to the named database with the specified version.
28+open :: forall eff . String -> Maybe Int -> OpenRequest eff -> Aff (idb :: INDEXED_DB | eff) Database
55−-- | If the database already exists with a lower version and there are open connections
56−-- | that don’t close in response to a versionchange event, the request will be blocked
57−-- | until all they close, then an upgrade will occur. If the database already exists with
58−-- | a higher version the request will fail.
59−-- |
60−-- | When the version isn't provided (`Nothing`), attempts to open a connection to the
61−-- | named database with the current version, or 1 if it does not already exist.
62−open
63− :: DatabaseName
64− -> Maybe Version
65− -> Callbacks
66− -> Aff Database
67open name mver req =
29open name mver req =
68− fromEffectFnAff $ Fn.runFn4 _open fromMaybe name mver req
30+ Fn.runFn4 _open fromMaybe name mver req
31+
69
32
70--------------------
33--------------------
71-- FFI
34-- FFI
72--
35--
73−foreign import _deleteDatabase
36+foreign import _deleteDatabase :: forall eff. String -> Aff (idb :: INDEXED_DB | eff) Int
74− :: String
37+
75− -> EffectFnAff Int
76
38
77−foreign import _open
78− :: forall a
79− . Fn4 (a -> Maybe a -> a) String (Maybe Int) (Callbacks) (EffectFnAff Database)
39+foreign import _open :: forall a eff. Fn4 (a -> Maybe a -> a) String (Maybe Int) (OpenRequest eff) (Aff (idb :: INDEXED_DB | eff) Database)
src/Database/IndexedDB/IDBIndex.jsdeleted−171
@@ -1,171 +0,0 @@
1−const errorHandler = function errorHandler(cb) {
2− return function _handler(e) {
3− cb(e.target.error);
4− };
5−};
6−
7−const successHandler = function successHandler(cb) {
8− return function _handler(e) {
9− cb(e.target.result);
10− };
11−};
12−
13−
14−export function _keyPath(index) {
15− const path = index.keyPath;
16−
17− if (Array.isArray(path)) {
18− return path;
19− }
20−
21− if (typeof path === 'string' && path !== '') {
22− return [path];
23− }
24−
25− return [];
26−};
27−
28−export function _multiEntry(index) {
29− return index.multiEntry;
30−};
31−
32−export function _name(index) {
33− return index.name;
34−};
35−
36−export function _objectStore(index) {
37− return index.obectStore;
38−};
39−
40−export function _unique(index) {
41− return index.unique;
42−};
43−
44−export function _count(index, query) {
45− return function aff(error, success) {
46− try {
47− const request = index.count(query);
48− request.onsuccess = successHandler(success);
49− request.onerror = errorHandler(error);
50− } catch (e) {
51− error(e);
52− }
53−
54− return function canceler(_, cancelerError) {
55− cancelerError(new Error("Can't cancel IDB Effects"));
56− };
57− };
58−};
59−
60−export function _get(index, range) {
61− return function aff(error, success) {
62− try {
63− const request = index.get(range);
64− request.onsuccess = successHandler(success);
65− request.onerror = errorHandler(error);
66− } catch (e) {
67− error(e);
68− }
69−
70− return function canceler(_, cancelerError) {
71− cancelerError(new Error("Can't cancel IDB Effects"));
72− };
73− };
74−};
75−
76−/*
77− * NOTE: Require some additional work. The array (which isn't necessarily a list of
78− * polymorphic types in js) can't be easily translated to a PureScript array.
79− *
80− * However, it may be doable to convert the result to some key / value structure with values of
81− * different types.
82−export function _getAll(index, query, count) {
83− return function aff(error, success) {
84− const request = index.getAll(query, count);
85− request.onsuccess = successHandler(success);
86− request.onerror = errorHandler(error);
87− };
88−};
89−*/
90−
91−export function _getAllKeys(index, range, count) {
92− return function aff(error, success) {
93− try {
94− const request = index.getAllKeys(range, count || undefined);
95− request.onsuccess = successHandler(success);
96− request.onerror = errorHandler(error);
97− } catch (e) {
98− error(e);
99− }
100−
101− return function canceler(_, cancelerError) {
102− cancelerError(new Error("Can't cancel IDB Effects"));
103− };
104− };
105−};
106−
107−export function _getKey(index, range) {
108− return function aff(error, success) {
109− try {
110− const request = index.getKey(range);
111− request.onsuccess = successHandler(success);
112− request.onerror = errorHandler(error);
113− } catch (e) {
114− error(e);
115− }
116−
117− return function canceler(_, cancelerError) {
118− cancelerError(new Error("Can't cancel IDB Effects"));
119− };
120− };
121−};
122−
123−export function _openCursor(index, query, dir, cb) {
124− return function aff(error, success) {
125− try {
126− const request = index.openCursor(query, dir);
127− request.onsuccess = function onSuccess(e) {
128− if (e.target.result != null) {
129− cb.onSuccess(e.target.result)();
130− } else {
131− cb.onComplete();
132− }
133− };
134− request.onerror = function onError(e) {
135− cb.onError(e.target.error);
136− };
137− success();
138− } catch (e) {
139− error(e);
140− }
141−
142− return function canceler(_, cancelerError) {
143− cancelerError(new Error("Can't cancel IDB Effects"));
144− };
145− };
146−};
147−
148−export function _openKeyCursor(index, query, dir, cb) {
149− return function aff(error, success) {
150− try {
151− const request = index.openKeyCursor(query, dir);
152− request.onsuccess = function onSuccess(e) {
153− if (e.target.result != null) {
154− cb.onSuccess(e.target.result)();
155− } else {
156− cb.onComplete();
157− }
158− };
159− request.onerror = function onError(e) {
160− cb.onError(e.target.error);
161− };
162− success();
163− } catch (e) {
164− error(e);
165− }
166−
167− return function canceler(_, cancelerError) {
168− cancelerError(new Error("Can't cancel IDB Effects"));
169− };
170− };
171−};
src/Database/IndexedDB/IDBIndex.purs+5−199
@@ -1,206 +1,12 @@
1−-- | An index allows looking up records in an object store using properties of the values
2−-- | in the object stores records.
3module Database.IndexedDB.IDBIndex
1module Database.IndexedDB.IDBIndex
4− -- * Types
2+ ( module Database.IndexedDB.IDBIndex.Internal
5− ( Callbacks
3+ ) where
6−
7− -- * Interface
8− , count
9− , get
10− , getAllKeys
11− , getKey
12− , openCursor
13− , openKeyCursor
14
4
15− -- * Attributes
5+import Database.IndexedDB.IDBIndex.Internal
6+ ( class IDBIndex, count, get, getAllKeys, getKey, openCursor, openKeyCursor
16 , keyPath
7 , keyPath
17 , multiEntry
8 , multiEntry
18 , name
9 , name
19 , objectStore
10 , objectStore
20 , unique
11 , unique
21− ) where
12+ )
22−
23−import Database.IndexedDB.Core
24−
25−import Data.Function.Uncurried (Fn2, Fn3, Fn4)
26−import Data.Function.Uncurried as Fn
27−import Data.Maybe (Maybe)
28−import Data.Nullable (Nullable, toMaybe, toNullable)
29−import Database.IndexedDB.IDBKey.Internal (Key, toKey)
30−import Effect (Effect)
31−import Effect.Aff (Aff)
32−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
33−import Effect.Exception (Error)
34−import Foreign (Foreign, unsafeFromForeign)
35−import Prelude (Unit, map, show, ($), (>>>))
36−
37−--------------------
38−-- TYPES
39−--
40−
41−-- | Callbacks to manipulate a cursor from an Open*Cursor call
42−type Callbacks cursor =
43− { onSuccess :: cursor -> Effect Unit
44− , onError :: Error -> Effect Unit
45− , onComplete :: Effect Unit
46− }
47−
48−--------------------
49−-- INTERFACES
50−--
51−
52−-- | Retrieves the number of records matching the key range in query.
53−count
54− :: forall index
55− . (IDBIndex index)
56− => index
57− -> Maybe KeyRange
58− -> Aff Int
59−count index range =
60− fromEffectFnAff $ Fn.runFn2 _count index (toNullable range)
61−
62−-- | Retrieves the value of the first record matching the given key range in query.
63−-- |
64−-- | NOTE
65−-- | The coercion from `a` to any type is unsafe and might throw a runtime error if incorrect.
66−get
67− :: forall a index
68− . (IDBIndex index)
69− => index
70− -> KeyRange
71− -> Aff (Maybe a)
72−get index range =
73− map (toMaybe >>> map unsafeFromForeign) $ fromEffectFnAff $ Fn.runFn2 _get index range
74−
75−-- | Retrieves the keys of records matching the given key range in query
76−-- | (up to the number given if given).
77−getAllKeys
78− :: forall index
79− . (IDBIndex index)
80− => index
81− -> Maybe KeyRange
82− -> Maybe Int
83− -> Aff (Array Key)
84−getAllKeys index range n =
85− map (map toKey) $ fromEffectFnAff $ Fn.runFn3 _getAllKeys index (toNullable range) (toNullable n)
86−
87−-- | Retrieves the key of the first record matching the given key or key range in query.
88−getKey
89− :: forall index
90− . (IDBIndex index)
91− => index
92− -> KeyRange
93− -> Aff (Maybe Key)
94−getKey index range =
95− map (toMaybe >>> map toKey) $ fromEffectFnAff $ Fn.runFn2 _getKey index range
96−
97−-- | Opens a ValueCursor over the records matching query, ordered by direction.
98−-- | If query is `Nothing`, all records in index are matched.
99−openCursor
100− :: forall index
101− . (IDBIndex index)
102− => index
103− -> Maybe KeyRange
104− -> CursorDirection
105− -> Callbacks ValueCursor
106− -> Aff Unit
107−openCursor index range dir cb =
108− fromEffectFnAff $ Fn.runFn4 _openCursor index (toNullable range) (show dir) cb
109−
110−-- | Opens a KeyCursor over the records matching query, ordered by direction.
111−-- | If query is `Nothing`, all records in index are matched.
112−openKeyCursor
113− :: forall index
114− . (IDBIndex index)
115− => index
116− -> Maybe KeyRange
117− -> CursorDirection
118− -> Callbacks KeyCursor
119− -> Aff Unit
120−openKeyCursor index range dir cb =
121− fromEffectFnAff $ Fn.runFn4 _openKeyCursor index (toNullable range) (show dir) cb
122−
123−--------------------
124−-- ATTRIBUTES
125−--
126−-- | Returns the key path of the index.
127−keyPath
128− :: Index
129− -> KeyPath
130−keyPath =
131− _keyPath
132−
133−-- | Returns true if the index's multiEntry flag is set.
134−multiEntry
135− :: Index
136− -> Boolean
137−multiEntry =
138− _multiEntry
139−
140−-- | Returns the name of the index.
141−name
142− :: Index
143− -> String
144−name =
145− _name
146−
147−-- | Returns the IDBObjectStore the index belongs to.
148−objectStore
149− :: Index
150− -> ObjectStore
151−objectStore =
152− _objectStore
153−
154−-- | Returns true if the index's unique flag is set.
155−unique
156− :: Index
157− -> Boolean
158−unique =
159− _unique
160−
161−--------------------
162−-- FFI
163−--
164−foreign import _keyPath
165− :: Index
166− -> Array String
167−
168−foreign import _multiEntry
169− :: Index
170− -> Boolean
171−
172−foreign import _name
173− :: Index
174− -> String
175−
176−foreign import _objectStore
177− :: Index
178− -> ObjectStore
179−
180−foreign import _unique
181− :: Index
182− -> Boolean
183−
184−foreign import _count
185− :: forall index
186− . Fn2 index (Nullable KeyRange) (EffectFnAff Int)
187−
188−foreign import _get
189− :: forall index
190− . Fn2 index KeyRange (EffectFnAff (Nullable Foreign))
191−
192−foreign import _getAllKeys
193− :: forall index
194− . Fn3 index (Nullable KeyRange) (Nullable Int) (EffectFnAff (Array Foreign))
195−
196−foreign import _getKey
197− :: forall index
198− . Fn2 index KeyRange (EffectFnAff (Nullable Foreign))
199−
200−foreign import _openCursor
201− :: forall index
202− . Fn4 index (Nullable KeyRange) String (Callbacks ValueCursor) (EffectFnAff Unit)
203−
204−foreign import _openKeyCursor
205− :: forall index
206− . Fn4 index (Nullable KeyRange) String (Callbacks KeyCursor) (EffectFnAff Unit)
src/Database/IndexedDB/IDBIndex/Internal.jsnew file+95
@@ -0,0 +1,95 @@
1+const errorHandler = function errorHandler(cb) {
2+ return function _handler(e) {
3+ cb(new Error(e.target.error.name));
4+ };
5+};
6+
7+const successHandler = function successHandler(cb) {
8+ return function _handler(e) {
9+ cb(e.target.result);
10+ };
11+};
12+
13+
14+exports._keyPath = function _keyPath(index) {
15+ return index.keyPath;
16+};
17+
18+exports._multiEntry = function _multiEntry(index) {
19+ return index.multiEntry;
20+};
21+
22+exports._name = function _name(index) {
23+ return index.name;
24+};
25+
26+exports._objectStore = function _objectStore(index) {
27+ return index.obectStore;
28+};
29+
30+exports._unique = function _unique(index) {
31+ return index.unique;
32+};
33+
34+exports._count = function _count(index, query) {
35+ return function aff(success, error) {
36+ const request = index.count(query);
37+ request.onsuccess = successHandler(success);
38+ request.onerror = errorHandler(error);
39+ };
40+};
41+
42+exports._get = function _get(index, range) {
43+ return function aff(success, error) {
44+ const request = index.get(range);
45+ request.onsuccess = successHandler(success);
46+ request.onerror = errorHandler(error);
47+ };
48+};
49+
50+/*
51+ * NOTE: Require some additional work. The array (which isn't necessarily a list of
52+ * polymorphic types in js) can't be easily translated to a PureScript array.
53+ *
54+ * However, it may be doable to convert the result to some key / value structure with values of
55+ * different types.
56+exports._getAll = function _getAll(index, query, count) {
57+ return function aff(success, error) {
58+ const request = index.getAll(query, count);
59+ request.onsuccess = successHandler(success);
60+ request.onerror = errorHandler(error);
61+ };
62+};
63+*/
64+
65+exports._getAllKeys = function _getAllKeys(index, range, count) {
66+ return function aff(success, error) {
67+ const request = index.getAllKeys(range, count || undefined);
68+ request.onsuccess = successHandler(success);
69+ request.onerror = errorHandler(error);
70+ };
71+};
72+
73+exports._getKey = function _getKey(index, range) {
74+ return function aff(success, error) {
75+ const request = index.getKey(range);
76+ request.onsuccess = successHandler(success);
77+ request.onerror = errorHandler(error);
78+ };
79+};
80+
81+exports._openCursor = function _openCursor(index, query, dir) {
82+ return function aff(success, error) {
83+ const request = index.openCursor(query, dir);
84+ request.onsuccess = successHandler(success);
85+ request.onerror = errorHandler(error);
86+ };
87+};
88+
89+exports._openKeyCursor = function _openKeyCursor(index, query, dir) {
90+ return function aff(success, error) {
91+ const request = index.openKeyCursor(query, dir);
92+ request.onsuccess = successHandler(success);
93+ request.onerror = errorHandler(error);
94+ };
95+};
src/Database/IndexedDB/IDBIndex/Internal.pursnew file+132
@@ -0,0 +1,132 @@
1+module Database.IndexedDB.IDBIndex.Internal where
2+
3+import Prelude
4+
5+import Control.Monad.Aff (Aff)
6+import Control.Monad.Eff.Exception (EXCEPTION)
7+import Data.Foreign (Foreign, unsafeFromForeign)
8+import Data.Function.Uncurried as Fn
9+import Data.Function.Uncurried (Fn2, Fn3)
10+import Data.Maybe (Maybe)
11+import Data.Nullable (Nullable, toMaybe, toNullable)
12+
13+import Database.IndexedDB.Core (INDEXED_DB, CursorDirection, Index, Key, KeyCursor, KeyRange, ObjectStore, ValueCursor)
14+
15+
16+--------------------
17+-- INTERFACES
18+--
19+class IDBIndex index where
20+ count :: forall eff. index -> Maybe KeyRange -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Int
21+ get :: forall a eff. index -> KeyRange -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Maybe a)
22+ getAllKeys :: forall eff. index -> Maybe KeyRange -> Maybe Int -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Array Key)
23+ getKey :: forall eff. index -> KeyRange -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Maybe Key)
24+ openCursor :: forall eff. index -> Maybe KeyRange -> Maybe CursorDirection -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ValueCursor
25+ openKeyCursor :: forall eff. index -> Maybe KeyRange -> Maybe CursorDirection -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) KeyCursor
26+
27+
28+--------------------
29+-- ATTRIBUTES
30+--
31+keyPath :: Index -> String
32+keyPath =
33+ _keyPath
34+
35+
36+multiEntry :: Index -> Boolean
37+multiEntry =
38+ _multiEntry
39+
40+
41+name :: Index -> String
42+name =
43+ _name
44+
45+
46+objectStore :: Index -> ObjectStore
47+objectStore =
48+ _objectStore
49+
50+
51+unique :: Index -> Boolean
52+unique =
53+ _unique
54+
55+
56+--------------------
57+-- INSTANCES
58+--
59+instance idbIndexIndex :: IDBIndex Index where
60+ count index range =
61+ Fn.runFn2 _count index (toNullable range)
62+
63+ get index range =
64+ (toMaybe >>> map unsafeFromForeign) <$> Fn.runFn2 _get index range
65+
66+ getAllKeys index range count =
67+ Fn.runFn3 _getAllKeys index (toNullable range) (toNullable count)
68+
69+ getKey index range =
70+ toMaybe <$> Fn.runFn2 _getKey index range
71+
72+ openCursor index range dir =
73+ Fn.runFn3 _openCursor index (toNullable range) (toNullable dir)
74+
75+ openKeyCursor index range dir =
76+ Fn.runFn3 _openKeyCursor index (toNullable range) (toNullable dir)
77+
78+
79+instance idbIndexObjectStore :: IDBIndex ObjectStore where
80+ count store range =
81+ Fn.runFn2 _count store (toNullable range)
82+
83+ get store range =
84+ (toMaybe >>> map unsafeFromForeign) <$> Fn.runFn2 _get store range
85+
86+ getAllKeys store range count =
87+ Fn.runFn3 _getAllKeys store (toNullable range) (toNullable count)
88+
89+ getKey store range =
90+ toMaybe <$> Fn.runFn2 _getKey store range
91+
92+ openCursor store range dir =
93+ Fn.runFn3 _openCursor store (toNullable range) (toNullable dir)
94+
95+ openKeyCursor store range dir =
96+ Fn.runFn3 _openKeyCursor store (toNullable range) (toNullable dir)
97+
98+
99+--------------------
100+-- FFI
101+--
102+foreign import _keyPath :: Index -> String
103+
104+
105+foreign import _multiEntry :: Index -> Boolean
106+
107+
108+foreign import _name :: Index -> String
109+
110+
111+foreign import _objectStore :: Index -> ObjectStore
112+
113+
114+foreign import _unique :: Index -> Boolean
115+
116+
117+foreign import _count :: forall index eff. Fn2 index (Nullable KeyRange) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Int)
118+
119+
120+foreign import _get :: forall index eff. Fn2 index KeyRange (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Nullable Foreign))
121+
122+
123+foreign import _getAllKeys :: forall index eff. Fn3 index (Nullable KeyRange) (Nullable Int) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Array Key))
124+
125+
126+foreign import _getKey :: forall index eff. Fn2 index KeyRange (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) (Nullable Key))
127+
128+
129+foreign import _openCursor :: forall index eff. Fn3 index (Nullable KeyRange) (Nullable CursorDirection) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ValueCursor)
130+
131+
132+foreign import _openKeyCursor :: forall index eff. Fn3 index (Nullable KeyRange) (Nullable CursorDirection) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) KeyCursor)
src/Database/IndexedDB/IDBKey.purs+1−11
@@ -1,15 +1,5 @@
1−-- | A key has an associated type which is one of: number, date, string, or array.
2−-- |
3−-- | NOTE: Binary keys aren't supported yet.
4module Database.IndexedDB.IDBKey
1module Database.IndexedDB.IDBKey
5 ( module Database.IndexedDB.IDBKey.Internal
2 ( module Database.IndexedDB.IDBKey.Internal
6 ) where
3 ) where
7
4
8−import Database.IndexedDB.IDBKey.Internal
5+import Database.IndexedDB.IDBKey.Internal(Key, class IDBKey, toKey, fromKey, unsafeFromKey)
9− ( class IDBKey
10− , Key
11− , none
12− , toKey
13− , fromKey
14− , unsafeFromKey
15− )
src/Database/IndexedDB/IDBKey/Internal.js+3−3
@@ -1,8 +1,8 @@
1−export function _dateTimeToForeign(y, m, d, h, mi, s, ms) {
1+exports._dateTimeToForeign = function _dateTimeToForeign(y, m, d, h, mi, s, ms) {
2 return new Date(y, m, d, h, mi, s, ms);
2 return new Date(y, m, d, h, mi, s, ms);
3};
3};
4
4
5−export function _readDateTime(parse, right, left, date) {
5+exports._readDateTime = function _readDateTime(parse, right, left, date) {
6 if (Object.getPrototypeOf(date) !== Date.prototype) {
6 if (Object.getPrototypeOf(date) !== Date.prototype) {
7 return left(typeof date);
7 return left(typeof date);
8 }
8 }
@@ -24,7 +24,7 @@ export function _readDateTime(parse, right, left, date) {
24 return right(mdate);
24 return right(mdate);
25};
25};
26
26
27−export function _unsafeReadDateTime(parse, date) {
27+exports._unsafeReadDateTime = function _unsafeReadDateTime(parse, date) {
28 const y = date.getFullYear();
28 const y = date.getFullYear();
29 const m = date.getMonth() + 1;
29 const m = date.getMonth() + 1;
30 const d = date.getDate();
30 const d = date.getDate();
src/Database/IndexedDB/IDBKey/Internal.purs+89−116
@@ -1,129 +1,113 @@
1−-- | A key has an associated type which is one of: number, date, string, or array.
2−-- |
3−-- | NOTE: Binary keys aren't supported yet.
4module Database.IndexedDB.IDBKey.Internal
1module Database.IndexedDB.IDBKey.Internal
5− ( Key
2+ ( Key(..)
6− , class IDBKey
7− , toKey
8− , fromKey
9− , unsafeFromKey
3+ , class IDBKey, toKey , fromKey , unsafeFromKey
10− , none
4+ , extractForeign
11− ) where
5+ ) where
12
6
13import Prelude
7import Prelude
14
8
15−import Control.Alt ((<|>))
9+import Control.Alt ((<|>))
16−import Control.Monad.Except (ExceptT(..), runExceptT)
10+import Control.Monad.Except (ExceptT(..), runExceptT)
17−import Data.Date as Date
11+import Data.Date as Date
18−import Data.DateTime (DateTime(..), Time(..))
12+import Data.DateTime (DateTime(..), Time(..))
19−import Data.Either (Either(..), either, isRight)
20−import Data.Enum (fromEnum, toEnum)
13+import Data.Enum (fromEnum, toEnum)
21−import Foreign as Foreign
14+import Data.Foreign as Foreign
22−import Foreign (Foreign, F)
15+import Data.Foreign (Foreign, F)
23−import Data.Function.Uncurried as Fn
16+import Data.Function.Uncurried as Fn
24−import Data.Function.Uncurried (Fn2, Fn4, Fn7)
17+import Data.Function.Uncurried (Fn2, Fn4, Fn7)
25−import Data.Identity (Identity(..))
26−import Data.List.NonEmpty (NonEmptyList(..))
18+import Data.List.NonEmpty (NonEmptyList(..))
27−import Data.List.Types (List(..))
19+import Data.List.Types (List(..))
28−import Data.Maybe (Maybe(..))
20+import Data.NonEmpty (NonEmpty(..))
29−import Data.NonEmpty (NonEmpty(..))
21+import Data.Either (Either(..), either, isRight)
22+import Data.Identity (Identity(..))
30−import Data.Nullable (Nullable, toNullable)
23+import Data.Nullable (Nullable, toNullable)
31−import Data.Time as Time
24+import Data.Time as Time
32−import Data.Traversable (traverse)
25+import Data.Traversable (traverse)
26+
33
27
34newtype Key = Key Foreign
28newtype Key = Key Foreign
35
29
30+
31+extractForeign :: Key -> Foreign
32+extractForeign (Key f) =
33+ f
34+
35+
36--------------------
36--------------------
37-- INTERFACES
37-- INTERFACES
38--
38--
39−-- | Interface describing a key. Use the `unsafeFromKey` to convert a key
40−-- | to a known type (e.g if you only strings as keys, or perfectly knows the
41−-- | type of a given key).
42class IDBKey a where
39class IDBKey a where
43− toKey :: a -> Key
40+ toKey :: a -> Key
44− fromKey :: Key -> F a
41+ fromKey :: Key -> F a
45 unsafeFromKey :: Key -> a
42 unsafeFromKey :: Key -> a
46
43
47−none :: Maybe Key
48−none =
49− Nothing
50
44
51--------------------
45--------------------
52-- INSTANCES
46-- INSTANCES
53--
47--
54instance eqKey :: Eq Key where
48instance eqKey :: Eq Key where
55 eq a b = (runExceptT >>> runIdentity >>> isRight) $
49 eq a b = (runExceptT >>> runIdentity >>> isRight) $
56− eq <$> ((fromKey a) :: F Int) <*> fromKey b
50+ eq <$> ((fromKey a) :: F Int) <*> fromKey b
57− <|>
51+ <|>
58− eq <$> ((fromKey a) :: F Number) <*> fromKey b
52+ eq <$> ((fromKey a) :: F Number) <*> fromKey b
59− <|>
53+ <|>
60− eq <$> ((fromKey a) :: F String) <*> fromKey b
54+ eq <$> ((fromKey a) :: F String) <*> fromKey b
61− <|>
55+ <|>
62− eq <$> ((fromKey a) :: F DateTime) <*> fromKey b
56+ eq <$> ((fromKey a) :: F DateTime) <*> fromKey b
63− <|>
64− eq <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
65 where
57 where
66− runIdentity :: forall a. Identity a -> a
58+ runIdentity :: forall a. Identity a -> a
67− runIdentity (Identity x) = x
59+ runIdentity (Identity x) = x
60+
68
61
69instance ordKey :: Ord Key where
62instance ordKey :: Ord Key where
70− compare a b = (runExceptT >>> runIdentity >>> either (const LT) identity) $
63+ compare a b = (runExceptT >>> runIdentity >>> either (const LT) id) $
71− compare <$> ((fromKey a) :: F Int) <*> fromKey b
64+ compare <$> ((fromKey a) :: F Int) <*> fromKey b
72− <|>
65+ <|>
73− compare <$> ((fromKey a) :: F Number) <*> fromKey b
66+ compare <$> ((fromKey a) :: F Number) <*> fromKey b
74− <|>
67+ <|>
75− compare <$> ((fromKey a) :: F String) <*> fromKey b
68+ compare <$> ((fromKey a) :: F String) <*> fromKey b
76− <|>
69+ <|>
77− compare <$> ((fromKey a) :: F DateTime) <*> fromKey b
70+ compare <$> ((fromKey a) :: F DateTime) <*> fromKey b
78− <|>
79− compare <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
80 where
71 where
81− runIdentity :: forall a. Identity a -> a
72+ runIdentity :: forall a. Identity a -> a
82− runIdentity (Identity x) = x
73+ runIdentity (Identity x) = x
74+
83
75
84instance showKey :: Show Key where
76instance showKey :: Show Key where
85 show a = (runExceptT >>> format) $
77 show a = (runExceptT >>> format) $
86− (show <$> (fromKey a :: F Int))
78+ (show <$> (fromKey a :: F Int))
87− <|>
79+ <|>
88− (show <$> (fromKey a :: F Number))
80+ (show <$> (fromKey a :: F Number))
89− <|>
81+ <|>
90− (show <$> (fromKey a :: F String))
82+ (show <$> (fromKey a :: F String))
91− <|>
83+ <|>
92− (show <$> (fromKey a :: F DateTime))
84+ (show <$> (fromKey a :: F DateTime))
93− <|>
94− (show <$> (fromKey a :: F (Array Key)))
95 where
85 where
96− format :: forall a. Identity (Either a String) -> String
86+ format :: forall a. Identity (Either a String) -> String
97− format (Identity x) =
87+ format (Identity x) =
98− either (const "(Key)") (\s -> "(Key " <> s <> ")") x
88+ either (const "(Key)") (\s -> "(Key " <> s <> ")") x
99−
100−instance idbKeyKey :: IDBKey Key where
101− toKey = identity
102− fromKey = pure
103− unsafeFromKey = identity
104
89
105−instance idbKeyForeign :: IDBKey Foreign where
106− toKey = Key
107− fromKey (Key f) = pure f
108− unsafeFromKey (Key f) = f
109
90
110instance idbKeyInt :: IDBKey Int where
91instance idbKeyInt :: IDBKey Int where
111− toKey = Foreign.unsafeToForeign >>> Key
92+ toKey = Foreign.toForeign >>> Key
112− fromKey (Key f) = Foreign.readInt f
93+ fromKey (Key f) = Foreign.readInt f
113 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
94 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
114
95
96+
115instance idbKeyNumber :: IDBKey Number where
97instance idbKeyNumber :: IDBKey Number where
116− toKey = Foreign.unsafeToForeign >>> Key
98+ toKey = Foreign.toForeign >>> Key
117− fromKey (Key f) = Foreign.readNumber f
99+ fromKey (Key f) = Foreign.readNumber f
118 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
100 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
119
101
102+
120instance idbKeyString :: IDBKey String where
103instance idbKeyString :: IDBKey String where
121− toKey = Foreign.unsafeToForeign >>> Key
104+ toKey = Foreign.toForeign >>> Key
122− fromKey (Key f) = Foreign.readString f
105+ fromKey (Key f) = Foreign.readString f
123 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
106 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
124
107
108+
125instance idbKeyDate :: IDBKey DateTime where
109instance idbKeyDate :: IDBKey DateTime where
126− toKey (DateTime d t) = Key $ Fn.runFn7 _dateTimeToForeign
110+ toKey (DateTime d t) = Key $ Fn.runFn7 _dateTimeToForeign
127 (fromEnum $ Date.year d)
111 (fromEnum $ Date.year d)
128 (fromEnum $ Date.month d)
112 (fromEnum $ Date.month d)
129 (fromEnum $ Date.day d)
113 (fromEnum $ Date.day d)
@@ -131,51 +115,40 @@ instance idbKeyDate :: IDBKey DateTime where
131 (fromEnum $ Time.minute t)
115 (fromEnum $ Time.minute t)
132 (fromEnum $ Time.second t)
116 (fromEnum $ Time.second t)
133 (fromEnum $ Time.millisecond t)
117 (fromEnum $ Time.millisecond t)
134− fromKey (Key f) = Fn.runFn4 _readDateTime dateTime dateTimeF dateTimeE f
118+ fromKey (Key f) = Fn.runFn4 _readDateTime dateTime dateTimeF dateTimeE f
135 unsafeFromKey (Key f) = Fn.runFn2 _unsafeReadDateTime dateTime f
119 unsafeFromKey (Key f) = Fn.runFn2 _unsafeReadDateTime dateTime f
136
120
121+
137instance idbKeyArray :: IDBKey a => IDBKey (Array a) where
122instance idbKeyArray :: IDBKey a => IDBKey (Array a) where
138− toKey = Foreign.unsafeToForeign >>> Key
123+ toKey = Foreign.toForeign >>> Key
139− fromKey (Key f) = Foreign.readArray f >>= traverse (Key >>> fromKey)
124+ fromKey (Key f) = Foreign.readArray f >>= traverse (Key >>> fromKey)
140 unsafeFromKey (Key f) = map unsafeFromKey (Foreign.unsafeFromForeign f)
125 unsafeFromKey (Key f) = map unsafeFromKey (Foreign.unsafeFromForeign f)
141
126
142−-- FFI constructor to build a DateTime from years, months, days, hours, minutes, seconds and millis
127+
143−dateTime
144− :: Int -- ^ years
145− -> Int -- ^ months
146− -> Int -- ^ days
147− -> Int -- ^ hours
148− -> Int -- ^ minutes
149− -> Int -- ^ seconds
150− -> Int -- ^ milliseconds
151− -> Nullable DateTime
128+dateTime :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime
152dateTime y m d h mi s ms =
129dateTime y m d h mi s ms =
153 toNullable $ DateTime
130 toNullable $ DateTime
154− <$> (Date.canonicalDate <$> toEnum y <*> toEnum m <*> toEnum d)
131+ <$> (Date.canonicalDate <$> toEnum y <*> toEnum m <*> toEnum d)
155− <*> (Time <$> toEnum h <*> toEnum mi <*> toEnum s <*> toEnum ms)
132+ <*> (Time <$> toEnum h <*> toEnum mi <*> toEnum s <*> toEnum ms)
133+
156
134
157−-- FFI constructor to convert a JS `Date` into a successful `F DateTime`
158−dateTimeF
135+dateTimeF :: DateTime -> F DateTime
159− :: DateTime
160− -> F DateTime
161dateTimeF =
136dateTimeF =
162 Right >>> Identity >>> ExceptT
137 Right >>> Identity >>> ExceptT
163
138
164−-- FFI constructor to convert a string into an errored `F DateTime`
139+
165−dateTimeE
140+dateTimeE :: String -> F DateTime
166− :: String
167− -> F DateTime
168dateTimeE =
141dateTimeE =
169 Foreign.TypeMismatch "Date" >>> flip NonEmpty Nil >>> NonEmptyList >>> Left >>> Identity >>> ExceptT
142 Foreign.TypeMismatch "Date" >>> flip NonEmpty Nil >>> NonEmptyList >>> Left >>> Identity >>> ExceptT
170
143
144+
171--------------------
145--------------------
172-- FFI
146-- FFI
173--
147--
174−foreign import _dateTimeToForeign
148+foreign import _dateTimeToForeign :: Fn7 Int Int Int Int Int Int Int Foreign
175− :: Fn7 Int Int Int Int Int Int Int Foreign
149+
150+
151+foreign import _readDateTime :: Fn4 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) (DateTime -> F DateTime) (String -> F DateTime) Foreign (F DateTime)
176
152
177−foreign import _readDateTime
178− :: Fn4 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) (DateTime -> F DateTime) (String -> F DateTime) Foreign (F DateTime)
179
153
180−foreign import _unsafeReadDateTime
181− :: Fn2 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) Foreign DateTime
154+foreign import _unsafeReadDateTime :: Fn2 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) Foreign DateTime
src/Database/IndexedDB/IDBKeyRange.js+9−9
@@ -1,4 +1,4 @@
1−export function _bound(lower, upper, lowerOpen, upperOpen) {
1+exports._bound = function _bound(lower, upper, lowerOpen, upperOpen) {
2 try {
2 try {
3 return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen);
3 return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen);
4 } catch (e) {
4 } catch (e) {
@@ -6,34 +6,34 @@ export function _bound(lower, upper, lowerOpen, upperOpen) {
6 }
6 }
7};
7};
8
8
9−export function _includes(range, key) {
9+exports._includes = function _includes(range, key) {
10 return range.includes(key);
10 return range.includes(key);
11};
11};
12
12
13−export function _lower(range) {
13+exports._lower = function _lower(range) {
14 return range.lower;
14 return range.lower;
15};
15};
16
16
17−export function _lowerBound(lower, open) {
17+exports._lowerBound = function _lowerBound(lower, open) {
18 return IDBKeyRange.lowerBound(lower, open);
18 return IDBKeyRange.lowerBound(lower, open);
19};
19};
20
20
21−export function _lowerOpen(range) {
21+exports._lowerOpen = function _lowerOpen(range) {
22 return range.lowerOpen;
22 return range.lowerOpen;
23};
23};
24
24
25−export function _only(key) {
25+exports._only = function _only(key) {
26 return IDBKeyRange.only(key);
26 return IDBKeyRange.only(key);
27};
27};
28
28
29−export function _upper(range) {
29+exports._upper = function _upper(range) {
30 return range.upper;
30 return range.upper;
31};
31};
32
32
33−export function _upperBound(upper, open) {
33+exports._upperBound = function _upperBound(upper, open) {
34 return IDBKeyRange.upperBound(upper, open);
34 return IDBKeyRange.upperBound(upper, open);
35};
35};
36
36
37−export function _upperOpen(range) {
37+exports._upperOpen = function _upperOpen(range) {
38 return range.upperOpen;
38 return range.upperOpen;
39};
39};
src/Database/IndexedDB/IDBKeyRange.purs+60−120
@@ -1,170 +1,110 @@
1−-- | A key has an associated type which is one of: number, date, string, binary, or array.
2module Database.IndexedDB.IDBKeyRange
1module Database.IndexedDB.IDBKeyRange
3− -- * Types
2+ ( class IDBKeyRange, includes
4− ( Open
5−
6− -- * Constructors
7 , only
3 , only
8 , lowerBound
4 , lowerBound
9 , upperBound
5 , upperBound
10 , bound
6 , bound
11−
12− -- * Interface
13− , includes
14−
15− -- * Attributes
16 , lower
7 , lower
17 , upper
8 , upper
18 , lowerOpen
9 , lowerOpen
19 , upperOpen
10 , upperOpen
20 ) where
11 ) where
21
12
22−import Prelude (($), (>>>), map)
13+import Prelude
23−
24−import Foreign (Foreign)
25−import Data.Function.Uncurried as Fn
26−import Data.Function.Uncurried (Fn2, Fn4)
27−import Data.Maybe (Maybe)
28−import Data.Nullable (Nullable, toMaybe)
29
14
30−import Database.IndexedDB.Core (class IDBKeyRange, KeyRange)
15+import Data.Foreign (Foreign)
31−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key, toKey, unsafeFromKey)
16+import Data.Function.Uncurried as Fn
17+import Data.Function.Uncurried (Fn2, Fn4)
18+import Data.Maybe (Maybe)
19+import Data.Nullable (Nullable, toMaybe)
32
20
33−--------------------
21+import Database.IndexedDB.Core (KeyRange)
34−-- TYPES
22+import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key(..), toKey, extractForeign)
35−--
36
23
37−-- | Type alias for open
38−type Open = Boolean
39
24
40--------------------
25--------------------
41−-- CONSTRUCTORS
26+-- INTERFACES
42--
27--
28+class IDBKeyRange range where
29+ includes :: range -> Key -> Boolean
43
30
44−-- | Returns a new IDBKeyRange spanning only key.
31+
45−only
46− :: forall a
47− . (IDBKey a)
48− => a
49− -> KeyRange
32+only :: forall a. (IDBKey a) => a -> KeyRange
50only key =
33only key =
51− _only (unsafeFromKey $ toKey key)
34+ _only (extractForeign $ toKey key)
52−
35+
53−-- | Returns a new IDBKeyRange starting at key with no upper bound.
36+
54−-- | If `Open` is `true`, key is not included in the range.
55−lowerBound
37+lowerBound :: forall a. (IDBKey a) => a -> Boolean -> KeyRange
56− :: forall a
57− . (IDBKey a)
58− => a
59− -> Open
60− -> KeyRange
61lowerBound key open =
38lowerBound key open =
62− Fn.runFn2 _lowerBound (unsafeFromKey $ toKey key) open
39+ Fn.runFn2 _lowerBound (extractForeign $ toKey key) open
63−
40+
64−-- | Returns a new IDBKeyRange with no lower bound and ending at key.
41+
65−-- | If `Open` is `true`, key is not included in the range.
66−upperBound
42+upperBound :: forall a. (IDBKey a) => a -> Boolean -> KeyRange
67− :: forall a
68− . (IDBKey a)
69− => a
70− -> Open
71− -> KeyRange
72upperBound key open =
43upperBound key open =
73− Fn.runFn2 _upperBound (unsafeFromKey $ toKey key) open
44+ Fn.runFn2 _upperBound (extractForeign $ toKey key) open
74−
45+
75−-- | Returns a new IDBKeyRange spanning from `lower` to `upper`.
76−-- | If `lowerOpen` is `true`, `lower` is not included in the range.
77−-- | If `upperOpen` is `true`, `upper` is not included in the range.
78−-- |
79−-- | It throws a `DataError` if the bound is invalid.
80−bound
81− :: forall key
82− . (IDBKey key)
83− => { lower :: key, upper :: key, lowerOpen :: Boolean, upperOpen :: Boolean }
46+bound :: forall a. (IDBKey a) => { lower :: a, upper :: a, lowerOpen :: Boolean, upperOpen :: Boolean } -> Maybe KeyRange
84− -> Maybe KeyRange
85bound { lower: key1, upper: key2, lowerOpen: open1, upperOpen: open2 } =
47bound { lower: key1, upper: key2, lowerOpen: open1, upperOpen: open2 } =
86 toMaybe
48 toMaybe
87− $ Fn.runFn4 _bound (unsafeFromKey $ toKey key1) (unsafeFromKey $ toKey key2) open1 open2
49+ $ Fn.runFn4 _bound (extractForeign $ toKey key1) (extractForeign $ toKey key2) open1 open2
88−
89−--------------------
90−-- INTERFACE
91−--
92
50
93−-- | Returns true if key is included in the range, and false otherwise.
94−includes
95− :: forall key range
96− . (IDBKey key)
97− => (IDBKeyRange range)
98− => range
99− -> key
100− -> Boolean
101−includes range =
102− toKey >>> unsafeFromKey >>> Fn.runFn2 _includes range
103
51
104--------------------
52--------------------
105-- ATTRIBUTES
53-- ATTRIBUTES
106--
54--
107−-- | Returns lower bound if any.
108−lower
109− :: KeyRange
55+lower :: KeyRange -> Maybe Key
110− -> Maybe Key
111lower =
56lower =
112− _lower >>> toMaybe >>> map toKey
57+ _lower >>> toMaybe >>> map Key
113
58
114−-- | Returns upper bound if any.
59+
115−upper
116− :: KeyRange
60+upper :: KeyRange -> Maybe Key
117− -> Maybe Key
118upper =
61upper =
119− _upper >>> toMaybe >>> map toKey
62+ _upper >>> toMaybe >>> map Key
63+
120
64
121−-- | Returns true if the lower open flag is set, false otherwise.
122−lowerOpen
65+lowerOpen :: KeyRange -> Boolean
123− :: KeyRange
124− -> Boolean
125lowerOpen =
66lowerOpen =
126 _lowerOpen
67 _lowerOpen
127
68
128−-- | Returns true if the upper open flag is set, false otherwise.
69+
129−upperOpen
70+upperOpen :: KeyRange -> Boolean
130− :: KeyRange
131− -> Boolean
132upperOpen =
71upperOpen =
133 _upperOpen
72 _upperOpen
134
73
74+
75+--------------------
76+-- INSTANCES
77+--
78+instance idbKeyRangeKeyRange :: IDBKeyRange KeyRange where
79+ includes range =
80+ extractForeign >>> Fn.runFn2 _includes range
81+
82+
135--------------------
83--------------------
136-- FFI
84-- FFI
137--
85--
86+foreign import _bound :: Fn4 Foreign Foreign Boolean Boolean (Nullable KeyRange)
87+
88+
89+foreign import _includes :: forall range. Fn2 range Foreign Boolean
90+
91+
92+foreign import _lower :: KeyRange -> Nullable Foreign
93+
94+
95+foreign import _lowerBound :: Fn2 Foreign Boolean KeyRange
96+
138
97
139−foreign import _only
98+foreign import _lowerOpen :: KeyRange -> Boolean
140− :: Foreign
141− -> KeyRange
142
99
143−foreign import _lowerBound
144− :: Fn2 Foreign Boolean KeyRange
145
100
146−foreign import _upperBound
147− :: Fn2 Foreign Boolean KeyRange
101+foreign import _only :: Foreign -> KeyRange
148
102
149−foreign import _bound
150− :: Fn4 Foreign Foreign Boolean Boolean (Nullable KeyRange)
151
103
152−foreign import _includes
104+foreign import _upper :: KeyRange -> Nullable Foreign
153− :: forall range
154− . Fn2 range Foreign Boolean
155
105
156−foreign import _lower
157− :: KeyRange
158− -> Nullable Foreign
159
106
160−foreign import _upper
107+foreign import _upperBound :: Fn2 Foreign Boolean KeyRange
161− :: KeyRange
162− -> Nullable Foreign
163
108
164−foreign import _lowerOpen
165− :: KeyRange
166− -> Boolean
167
109
168−foreign import _upperOpen
110+foreign import _upperOpen :: KeyRange -> Boolean
169− :: KeyRange
170− -> Boolean
src/Database/IndexedDB/IDBObjectStore.js+38−89
@@ -1,6 +1,6 @@
1const errorHandler = function errorHandler(cb) {
1const errorHandler = function errorHandler(cb) {
2 return function _handler(e) {
2 return function _handler(e) {
3− cb(e.target.error);
3+ cb(new Error(e.target.error.name));
4 };
4 };
5};
5};
6
6
@@ -15,44 +15,28 @@ const toArray = function toArray(xs) {
15};
15};
16
16
17
17
18−export function _add(store, value, key) {
18+exports._add = function _add(store, value, key) {
19− return function aff(error, success) {
19+ return function aff(success, error) {
20− try {
21− const request = store.add(value, key || undefined);
20+ const request = store.add(value, key || undefined);
22− request.onsuccess = successHandler(success);
21+ request.onsuccess = successHandler(success);
23− request.onerror = errorHandler(error);
22+ request.onerror = errorHandler(error);
24− } catch (e) {
25− error(e);
26− }
27−
28− return function canceler(_, cancelerError) {
29− cancelerError(new Error("Can't cancel IDB Effects"));
30− };
31 };
23 };
32};
24};
33
25
34−export function _autoIncrement(store) {
26+exports._autoIncrement = function _autoIncrement(store) {
35 return store.autoIncrement;
27 return store.autoIncrement;
36};
28};
37
29
38−export function _clear(store) {
30+exports._clear = function _clear(store) {
39− return function aff(error, success) {
31+ return function aff(success, error) {
40− try {
41− const request = store.clear();
32+ const request = store.clear();
42− request.onsuccess = successHandler(success);
33+ request.onsuccess = successHandler(success);
43− request.onerror = errorHandler(error);
34+ request.onerror = errorHandler(error);
44− } catch (e) {
45− error(e);
46− }
47−
48− return function canceler(_, cancelerError) {
49− cancelerError(new Error("Can't cancel IDB Effects"));
50− };
51 };
35 };
52};
36};
53
37
54−export function _createIndex(store, name, path, params) {
38+exports._createIndex = function _createIndex(store, name, path, params) {
55− return function aff(error, success) {
39+ return function eff() {
56 var keyPath;
40 var keyPath;
57
41
58 try {
42 try {
@@ -60,7 +44,7 @@ export function _createIndex(store, name, path, params) {
60 // a string hasn't the same meaning as a sequence of strings
44 // a string hasn't the same meaning as a sequence of strings
61 switch (path.length) {
45 switch (path.length) {
62 case 0:
46 case 0:
63− keyPath = '';
47+ keyPath = null;
64 break;
48 break;
65 case 1:
49 case 1:
66 keyPath = path[0];
50 keyPath = path[0];
@@ -69,69 +53,46 @@ export function _createIndex(store, name, path, params) {
69 keyPath = path;
53 keyPath = path;
70 }
54 }
71
55
72− const index = store.createIndex(name, keyPath, params);
56+ store.createIndex(name, keyPath, params);
73− success(index);
74 } catch (e) {
57 } catch (e) {
75− error(e);
58+ throw new Error(e.name);
76 }
59 }
77−
78− return function canceler(_, cancelerError) {
79− cancelerError(new Error("Can't cancel IDB Effects"));
80− };
81 };
60 };
82};
61};
83
62
84−export function _deleteIndex(store, name) {
63+exports._deleteIndex = function _deleteIndex(store, name) {
85− return function aff(error, success) {
64+ return function eff() {
86 try {
65 try {
87 store.deleteIndex(name);
66 store.deleteIndex(name);
88− success();
89 } catch (e) {
67 } catch (e) {
90− error(e);
68+ throw new Error(e.name);
91 }
69 }
92−
93− return function canceler(_, cancelerError) {
94− cancelerError(new Error("Can't cancel IDB Effects"));
95− };
96 };
70 };
97};
71};
98
72
99−export function _delete(store, query) {
73+exports._delete = function _delete(store, query) {
100− return function aff(error, success) {
74+ return function aff(success, error) {
101− try {
102− const request = store.delete(query);
75+ const request = store.delete(query);
103− request.onsuccess = successHandler(success);
76+ request.onsuccess = successHandler(success);
104− request.onerror = errorHandler(error);
77+ request.onerror = errorHandler(error);
105− } catch (e) {
106− error(e);
107− }
108−
109− return function canceler(_, cancelerError) {
110− cancelerError(new Error("Can't cancel IDB Effects"));
111− };
112 };
78 };
113};
79};
114
80
115−export function _index(store, name) {
81+exports._index = function _index(store, name) {
116− return function aff(error, success) {
82+ return function eff() {
117 try {
83 try {
118− const index = store.index(name);
84+ return store.index(name);
119− success(index);
120 } catch (e) {
85 } catch (e) {
121− error(e);
86+ throw new Error(e.name);
122 }
87 }
123−
124− return function canceler(_, cancelerError) {
125− cancelerError(new Error("Can't cancel IDB Effects"));
126− };
127 };
88 };
128};
89};
129
90
130−export function _indexNames(store) {
91+exports._indexNames = function _indexNames(store) {
131 return toArray(store.indexNames);
92 return toArray(store.indexNames);
132};
93};
133
94
134−export function _keyPath(store) {
95+exports._keyPath = function _keyPath(store) {
135 const path = store.keyPath;
96 const path = store.keyPath;
136
97
137 if (Array.isArray(path)) {
98 if (Array.isArray(path)) {
@@ -139,32 +100,20 @@ export function _keyPath(store) {
139 }
100 }
140
101
141 if (typeof path === 'string') {
102 if (typeof path === 'string') {
142− return [path];
103+ return path.split('.');
143 }
104 }
144
105
145 return [];
106 return [];
146};
107};
147
108
148−export function _name(store) {
109+exports._name = function _name(store) {
149 return store.name;
110 return store.name;
150};
111};
151
112
152−export function _put(store, value, key) {
113+exports._put = function _put(store, value, key) {
153− return function aff(error, success) {
114+ return function aff(success, error) {
154− try {
155− const request = store.put(value, key || undefined);
115+ const request = store.put(value, key || undefined);
156− request.onsuccess = successHandler(success);
116+ request.onsuccess = successHandler(success);
157− request.onerror = errorHandler(error);
117+ request.onerror = errorHandler(error);
158− } catch (e) {
159− error(e);
160− }
161−
162− return function canceler(_, cancelerError) {
163− cancelerError(new Error("Can't cancel IDB Effects"));
164− };
165 };
118 };
166};
119};
167−
168−export function _transaction(store) {
169− return store.transaction;
170−};
src/Database/IndexedDB/IDBObjectStore.purs+86−222
@@ -1,257 +1,121 @@
1−-- | An object store is the primary storage mechanism for storing data in a database.
2module Database.IndexedDB.IDBObjectStore
1module Database.IndexedDB.IDBObjectStore
3− -- * Types
2+ ( class IDBObjectStore, add, clear, createIndex, delete, deleteIndex, index, put
4− ( IndexName
3+ , module Database.IndexedDB.IDBIndex.Internal
5− , IndexParameters
6− , defaultParameters
7−
8− -- * Interface
9− , add
10− , clear
11− , createIndex
12− , delete
13− , deleteIndex
14− , index
15− , put
16−
17− -- * Attributes
18 , autoIncrement
4 , autoIncrement
19 , indexNames
5 , indexNames
20 , keyPath
6 , keyPath
21 , name
7 , name
22− , transaction
23−
24− -- * Re-Exports
25− , module Database.IndexedDB.IDBIndex
26 ) where
8 ) where
27
9
28−import Database.IndexedDB.Core
10+import Prelude (Unit, ($), (<$>))
29
11
12+import Control.Monad.Aff (Aff)
13+import Control.Monad.Eff (Eff)
14+import Control.Monad.Eff.Exception (EXCEPTION)
15+import Data.Foreign (Foreign)
30−import Data.Function.Uncurried (Fn2, Fn3, Fn4)
16+import Data.Function.Uncurried as Fn
31−import Data.Function.Uncurried as Fn
17+import Data.Function.Uncurried (Fn2, Fn3, Fn4)
32−import Data.Maybe (Maybe)
18+import Data.Maybe (Maybe)
33−import Data.Nullable (Nullable, toNullable)
19+import Data.Nullable (Nullable, toNullable)
34−import Database.IndexedDB.IDBIndex (count, get, getAllKeys, getKey, openCursor, openKeyCursor)
35−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key, unsafeFromKey, toKey)
36−import Effect.Aff (Aff)
37−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
38−import Foreign (Foreign)
39−import Prelude (Unit, map, ($), (<$>), (>>>), (<<<))
40
20
41−--------------------
21+import Database.IndexedDB.Core (INDEXED_DB, Index, KeyRange, ObjectStore)
42−-- TYPES
22+import Database.IndexedDB.IDBIndex.Internal (class IDBIndex, get, getAllKeys, getKey, openCursor, openKeyCursor)
43−--
23+import Database.IndexedDB.IDBKey.Internal (Key(Key), extractForeign)
44
24
45−-- | Type alias for IndexName
46−type IndexName = String
47−
48−-- | Flags to set on the index.
49−-- |
50−-- | An index has a `unique` flag. When this flag is set, the index enforces that no
51−-- | two records in the index has the same key. If a record in the index’s referenced
52−-- | object store is attempted to be inserted or modified such that evaluating the index’s
53−-- | key path on the records new value yields a result which already exists in the index,
54−-- | then the attempted modification to the object store fails.
55−-- |
56−-- | An index has a `multiEntry` flag. This flag affects how the index behaves when the
57−-- | result of evaluating the index’s key path yields an array key. If the `multiEntry` flag
58−-- | is unset, then a single record whose key is an array key is added to the index.
59−-- | If the `multiEntry` flag is true, then the one record is added to the index for each
60−-- | of the subkeys.
61−type IndexParameters =
62− { unique :: Boolean
63− , multiEntry :: Boolean
64− }
65−
66−defaultParameters :: IndexParameters
67−defaultParameters =
68− { unique: false
69− , multiEntry: false
70− }
71
25
72--------------------
26--------------------
73-- INTERFACES
27-- INTERFACES
74--
28--
29+class IDBObjectStore store where
30+ add :: forall value eff. store -> value -> Maybe Key -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Key
31+ clear :: forall eff. store -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
32+ createIndex :: forall eff. store -> String -> (Array String) -> { unique :: Boolean, multiEntry :: Boolean } -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Index
33+ delete :: forall eff. store -> KeyRange -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
34+ deleteIndex :: forall eff. store -> String -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
35+ index :: forall eff. store -> String -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Index
36+ put :: forall value eff. store -> value -> Maybe Key -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Key
75
37
76−-- | Adds or updates a record in store with the given value and key.
77−-- |
78−-- | If the store uses in-line keys and key is specified a "DataError" DOMException
79−-- | will be thrown.
80−-- |
81−-- | If add() is used, and if a record with the key already exists the request will fail,
82−-- | with a "ConstraintError" DOMException.
83−add
84− :: forall key val store
85− . (IDBKey key)
86− => (IDBObjectStore store)
87− => store
88− -> val
89− -> Maybe key
90− -> Aff Key
91−add store value key =
92− map toKey $ fromEffectFnAff $ Fn.runFn3 _add store value (toNullable $ (toKey >>> unsafeFromKey) <$> key)
93−
94−-- | Deletes all records in store.
95−clear
96− :: forall store
97− . (IDBObjectStore store)
98− => store
99− -> Aff Unit
100−clear =
101− fromEffectFnAff <<< _clear
102−
103−-- | Creates a new index in store with the given name, keyPath and options and
104−-- | returns a new IDBIndex. If the keyPath and options define constraints that
105−-- | cannot be satisfied with the data already in store the upgrade transaction
106−-- | will abort with a "ConstraintError" DOMException.
107−-- |
108−-- | Throws an "InvalidStateError" DOMException if not called within an upgrade transaction.
109−createIndex
110− :: forall store
111− . (IDBObjectStore store)
112− => store
113− -> IndexName
114− -> KeyPath
115− -> IndexParameters
116− -> Aff Index
117−createIndex store name' path params =
118− fromEffectFnAff $ Fn.runFn4 _createIndex store name' path params
119−
120−-- | Deletes records in store with the given key or in the given key range in query.
121−delete
122− :: forall store
123− . (IDBObjectStore store)
124− => store
125− -> KeyRange
126− -> Aff Unit
127−delete store range =
128− fromEffectFnAff $ Fn.runFn2 _delete store range
129−
130−-- | Deletes the index in store with the given name.
131−-- |
132−-- | Throws an "InvalidStateError" DOMException if not called within an upgrade transaction.
133−deleteIndex
134− :: forall store
135− . (IDBObjectStore store)
136− => store
137− -> IndexName
138− -> Aff Unit
139−deleteIndex store name' =
140− fromEffectFnAff $ Fn.runFn2 _deleteIndex store name'
141−
142−-- | Returns an IDBIndex for the index named name in store.
143−index
144− :: forall store
145− . (IDBObjectStore store)
146− => store
147− -> IndexName
148− -> Aff Index
149−index store name' =
150− fromEffectFnAff $ Fn.runFn2 _index store name'
151−
152−-- | Adds or updates a record in store with the given value and key.
153−-- |
154−-- | If the store uses in-line keys and key is specified a "DataError" DOMException
155−-- | will be thrown.
156−-- |
157−-- | If put() is used, any existing record with the key will be replaced.
158−put
159− :: forall val key store
160− . (IDBKey key)
161− => (IDBObjectStore store)
162− => store
163− -> val
164− -> Maybe key
165− -> Aff Key
166−put store value key =
167− map toKey $ fromEffectFnAff $ Fn.runFn3 _put store value (toNullable $ (toKey >>> unsafeFromKey) <$> key)
168
38
169--------------------
39--------------------
170-- ATTRIBUTES
40-- ATTRIBUTES
171--
41--
172−-- | Returns `true` if the store has a key generator, and `false` otherwise.
173−autoIncrement
42+autoIncrement :: ObjectStore -> Boolean
174− :: ObjectStore
175− -> Boolean
176autoIncrement =
43autoIncrement =
177 _autoIncrement
44 _autoIncrement
178
45
179−--| Returns a list of the names of indexes in the store.
46+
180−indexNames
181− :: ObjectStore
47+indexNames :: ObjectStore -> Array String
182− -> Array String
183indexNames =
48indexNames =
184 _indexNames
49 _indexNames
185
50
186−-- | Returns the key path of the store, or empty array if none
51+
187−keyPath
188− :: ObjectStore
52+keyPath :: ObjectStore -> Array String
189− -> Array String
190keyPath =
53keyPath =
191 _keyPath
54 _keyPath
192
55
193−-- | Returns the name of the store.
56+
194−name
195− :: ObjectStore
57+name :: ObjectStore -> String
196− -> String
197name =
58name =
198 _name
59 _name
199
60
200−-- | Returns the associated transaction.
61+
201−transaction
62+--------------------
202− :: ObjectStore
63+-- INSTANCES
203− -> Transaction
64+--
204−transaction =
65+instance idbObjectStoreObjectStore :: IDBObjectStore ObjectStore where
205− _transaction
66+ add store value key =
67+ Key <$> Fn.runFn3 _add store value (toNullable $ extractForeign <$> key)
68+
69+ clear =
70+ _clear
71+
72+ createIndex store name' path params =
73+ Fn.runFn4 _createIndex store name' path params
74+
75+ delete store range =
76+ Fn.runFn2 _delete store range
77+
78+ deleteIndex store name' =
79+ Fn.runFn2 _deleteIndex store name'
80+
81+ index store name' =
82+ Fn.runFn2 _index store name'
83+
84+ put store value key =
85+ Key <$> Fn.runFn3 _put store value (toNullable $ extractForeign <$> key)
86+
206
87
207--------------------
88--------------------
208-- FFI
89-- FFI
209--
90--
210−foreign import _add
91+foreign import _add :: forall value eff. Fn3 ObjectStore value (Nullable Foreign) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Foreign)
211− :: forall val store
92+
212− . Fn3 store val (Nullable Foreign) (EffectFnAff Foreign)
93+
213−
214−foreign import _autoIncrement
94+foreign import _autoIncrement :: ObjectStore -> Boolean
215− :: ObjectStore
95+
216− -> Boolean
96+
217−
97+foreign import _clear :: forall eff. ObjectStore -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
218−foreign import _clear
98+
219− :: forall store
99+
220− . store
221− -> EffectFnAff Unit
222−
223−foreign import _createIndex
224− :: forall store
225− . Fn4 store String (Array String) { unique :: Boolean, multiEntry :: Boolean } (EffectFnAff Index)
100+foreign import _createIndex :: forall eff. Fn4 ObjectStore String (Array String) { unique :: Boolean, multiEntry :: Boolean } (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Index)
226−
101+
227−foreign import _delete
102+
228− :: forall store
103+foreign import _delete :: forall eff. Fn2 ObjectStore KeyRange (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit)
229− . Fn2 store KeyRange (EffectFnAff Unit)
104+
230−
105+
231−foreign import _deleteIndex
106+foreign import _deleteIndex :: forall eff. Fn2 ObjectStore String (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit)
232− :: forall store
107+
233− . Fn2 store String (EffectFnAff Unit)
108+
234−
109+foreign import _index :: forall eff. Fn2 ObjectStore String (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Index)
235−foreign import _index
110+
236− :: forall store
111+
237− . Fn2 store String (EffectFnAff Index)
238−
239−foreign import _indexNames
112+foreign import _indexNames :: ObjectStore -> Array String
240− :: ObjectStore
113+
241− -> Array String
114+
242−
243−foreign import _keyPath
115+foreign import _keyPath :: ObjectStore -> Array String
244− :: ObjectStore
116+
245− -> Array String
117+
246−
247−foreign import _name
118+foreign import _name :: ObjectStore -> String
248− :: ObjectStore
119+
249− -> String
120+
250−
121+foreign import _put :: forall value eff. Fn3 ObjectStore value (Nullable Foreign) (Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Foreign)
251−foreign import _put
252− :: forall val store
253− . Fn3 store val (Nullable Foreign) (EffectFnAff Foreign)
254−
255−foreign import _transaction
256− :: ObjectStore
257− -> Transaction
src/Database/IndexedDB/IDBTransaction.js+10−67
@@ -1,29 +1,20 @@
1−export function _abort(tx) {
1+exports._abort = function _abort(tx) {
2− return function aff(error, success) {
2+ return function eff() {
3 try {
3 try {
4 tx.abort();
4 tx.abort();
5− success();
6 } catch (e) {
5 } catch (e) {
7− error(e);
6+ throw new Error(e.name);
8 }
7 }
9−
10− return function canceler(_, cancelerError) {
11− cancelerError(new Error("Can't cancel IDB Effects"));
12− };
13 };
8 };
14};
9};
15
10
16−export function _db(tx) {
17− return tx.db;
18−};
19−
20−export function _error(tx) {
11+exports._error = function _error(tx) {
21 return tx.error == null
12 return tx.error == null
22 ? null
13 ? null
23− : tx.error;
14+ : new Error(tx.error.name);
24};
15};
25
16
26−export function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
17+exports._mode = function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
27 if (tx.mode === 'readwrite') {
18 if (tx.mode === 'readwrite') {
28 return ReadWrite;
19 return ReadWrite;
29 } else if (tx.mode === 'versionchange') {
20 } else if (tx.mode === 'versionchange') {
@@ -33,60 +24,12 @@ export function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
33 return ReadOnly;
24 return ReadOnly;
34};
25};
35
26
36−export function _objectStore(tx, name) {
27+exports._objectStore = function _objectStore(tx, name) {
37− return function aff(error, success) {
28+ return function eff() {
38 try {
29 try {
39− const store = tx.objectStore(name);
30+ return tx.objectStore(name);
40− success(store);
41 } catch (e) {
31 } catch (e) {
42− error(e);
32+ throw new Error(e.name);
43 }
33 }
44−
45− return function canceler(_, cancelerError) {
46− cancelerError(new Error("Can't cancel IDB Effects"));
47− };
48− };
49−};
50−
51−export function _objectStoreNames(tx) {
52− return tx.objectStoreNames;
53−};
54−
55−export function _onAbort(tx, f) {
56− return function aff(error, success) {
57− tx.onabort = function onabort() {
58− f();
59− };
60− success();
61−
62− return function canceler(_, cancelerError) {
63− cancelerError(new Error("Can't cancel IDB Effects"));
64− };
65− };
66−};
67−
68−export function _onComplete(tx, f) {
69− return function aff(error, success) {
70− tx.oncomplete = function oncomplete() {
71− f();
72− };
73− success();
74−
75− return function canceler(_, cancelerError) {
76− cancelerError(new Error("Can't cancel IDB Effects"));
77− };
78− };
79−};
80−
81−export function _onError(tx, f) {
82− return function aff(error, success) {
83− tx.onerror = function onerror(e) {
84− f(e.target.error)();
85− };
86− success();
87−
88− return function canceler(_, cancelerError) {
89− cancelerError(new Error("Can't cancel IDB Effects"));
90− };
91 };
34 };
92};
35};
src/Database/IndexedDB/IDBTransaction.purs+28−118
@@ -1,153 +1,63 @@
1−-- | An object store is the primary storage mechanism for storing data in a database.
2module Database.IndexedDB.IDBTransaction
1module Database.IndexedDB.IDBTransaction
3− -- * Interface
4− ( abort
5− , objectStore
2+ (class IDBTransaction, abort, objectStore
6−
7− -- * Attributes
8 , error
3 , error
9 , mode
4 , mode
10−
11− -- * Event Handlers
12− , onAbort
13− , onComplete
14− , onError
15 ) where
5 ) where
16
6
7+import Prelude (Unit, (>>>))
8+
9+import Control.Monad.Eff (Eff)
10+import Control.Monad.Eff.Exception (EXCEPTION, Error)
11+import Data.Function.Uncurried as Fn
12+import Data.Function.Uncurried (Fn2, Fn4)
13+import Data.Maybe (Maybe)
14+import Data.Nullable (Nullable, toMaybe)
15+
17−import Database.IndexedDB.Core
16+import Database.IndexedDB.Core (INDEXED_DB, ObjectStore, Transaction, TransactionMode(..))
18
17
19−import Data.Function.Uncurried (Fn2, Fn4)
20−import Data.Function.Uncurried as Fn
21−import Data.Maybe (Maybe)
22−import Data.Nullable (Nullable, toMaybe)
23−import Effect (Effect)
24−import Effect.Aff (Aff)
25−import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
26−import Effect.Exception (Error)
27−import Prelude (Unit, ($), (<<<), (>>>))
28
18
29--------------------
19--------------------
30-- INTERFACES
20-- INTERFACES
31--
21--
22+class IDBTransaction tx where
23+ abort :: forall eff. tx -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
24+ objectStore :: forall eff. tx -> String -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore
32
25
33−-- | Aborts the transaction. All pending requests will fail with a "AbortError"
34−-- | DOMException and all changes made to the database will be reverted.
35−abort
36− :: forall tx
37− . (IDBTransaction tx)
38− => tx
39− -> Aff Unit
40−abort =
41− fromEffectFnAff <<< _abort
42−
43−-- | Returns an IDBObjectStore in the transaction's scope.
44−objectStore
45− :: forall tx
46− . (IDBTransaction tx)
47− => tx
48− -> String
49− -> Aff ObjectStore
50−objectStore tx name =
51− fromEffectFnAff $ Fn.runFn2 _objectStore tx name
52
26
53--------------------
27--------------------
54-- ATTRIBUTES
28-- ATTRIBUTES
55--
29--
56−
57−--- | Returns the transaction’s connection.
58−db
59− :: Transaction
30+error :: Transaction -> Maybe Error
60− -> Database
61−db =
62− _db
63−
64−-- | If the transaction was aborted, returns the error (a DOMException) providing the reason.
65−error
66− :: Transaction
67− -> Maybe Error
68error =
31error =
69 _error >>> toMaybe
32 _error >>> toMaybe
70
33
71−-- | Returns the mode the transaction was created with (`ReadOnly|ReadWrite`)
34+
72−-- | , or `VersionChange` for an upgrade transaction.
73−mode
74− :: Transaction
75− -> TransactionMode
35+mode :: Transaction -> TransactionMode
76mode =
36mode =
77 Fn.runFn4 _mode ReadOnly ReadWrite VersionChange
37 Fn.runFn4 _mode ReadOnly ReadWrite VersionChange
78
38
79−-- | Returns a list of the names of object stores in the transaction’s scope.
80−-- | For an upgrade transaction this is all object stores in the database.
81−objectStoreNames
82− :: Transaction
83− -> Array String
84−objectStoreNames =
85− _objectStoreNames
86
39
87--------------------
40--------------------
88−-- EVENT HANDLERS
41+-- INSTANCES
89--
42--
43+instance idbTransactionTransaction :: IDBTransaction Transaction where
44+ objectStore tx name =
45+ Fn.runFn2 _objectStore tx name
46+
47+ abort =
48+ _abort
90
49
91−-- | Event handler for the `abort` event.
92−onAbort
93− :: Transaction
94− -> Effect Unit
95− -> Aff Unit
96−onAbort db' f =
97− fromEffectFnAff $ Fn.runFn2 _onAbort db' f
98−
99−-- | Event handler for the `complete` event.
100−onComplete
101− :: Transaction
102− -> Effect Unit
103− -> Aff Unit
104−onComplete db' f =
105− fromEffectFnAff $ Fn.runFn2 _onComplete db' f
106−
107−-- | Event handler for the `error` event.
108−onError
109− :: Transaction
110− -> (Error -> Effect Unit)
111− -> Aff Unit
112−onError db' f =
113− fromEffectFnAff $ Fn.runFn2 _onError db' f
114
50
115--------------------
51--------------------
116-- FFI
52-- FFI
117--
53--
54+foreign import _abort :: forall tx eff. tx -> Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
118
55
119−foreign import _abort
120− :: forall tx
121− . tx
122− -> EffectFnAff Unit
123−
124−foreign import _db
125− :: Transaction
126− -> Database
127−
128−foreign import _error
129− :: Transaction
130− -> (Nullable Error)
131−
132−foreign import _mode
133− :: Fn4 TransactionMode TransactionMode TransactionMode Transaction TransactionMode
134
56
135−foreign import _objectStoreNames
136− :: Transaction
57+foreign import _error :: Transaction -> (Nullable Error)
137− -> Array String
138
58
139−foreign import _objectStore
140− :: forall tx
141− . Fn2 tx String (EffectFnAff ObjectStore)
142
59
143−foreign import _onAbort
60+foreign import _mode :: Fn4 TransactionMode TransactionMode TransactionMode Transaction TransactionMode
144− :: forall tx
145− . Fn2 tx (Effect Unit) (EffectFnAff Unit)
146
61
147−foreign import _onComplete
148− :: forall tx
149− . Fn2 tx (Effect Unit) (EffectFnAff Unit)
150
62
151−foreign import _onError
63+foreign import _objectStore :: forall tx eff. Fn2 tx String (Eff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) ObjectStore)
152− :: forall tx
153− . Fn2 tx (Error -> Effect Unit) (EffectFnAff Unit)
src/Main.pursnew file+24
@@ -0,0 +1,24 @@
1+module Main where
2+
3+import Prelude
4+
5+import Control.Monad.Aff as Aff
6+import Control.Monad.Eff(kind Effect, Eff)
7+import Control.Monad.Eff.Console as Console
8+import Control.Monad.Eff.Console(CONSOLE)
9+import Control.Monad.Eff.Exception(EXCEPTION, catchException)
10+import Data.Maybe(Maybe(..))
11+import Data.Either(Either(..))
12+
13+import Core
14+import IDBDatabase as IDBDatabase
15+
16+
17+main :: Eff (exception :: EXCEPTION, idb :: INDEXED_DB, console :: CONSOLE) Unit
18+main = do
19+ _ <- Aff.runAff (show >>> Console.log) (IDBDatabase.name >>> Console.log) $ IDBDatabase.open "myDatabase" Nothing
20+ { onBlocked : Nothing
21+ , onUpgradeNeeded : Nothing
22+ }
23+
24+ pure unit
src/Test/Spec/Mocha.jsnew file+46
@@ -0,0 +1,46 @@
1+/* global exports, it */
2+
3+// module Test.Spec.Mocha
4+
5+if (typeof describe !== 'function' || typeof it !== 'function') {
6+ throw new Error('Mocha globals seem to be unavailable!');
7+}
8+
9+exports.itAsync = function (only) {
10+ "use strict";
11+ return function (name) {
12+ return function (aff) {
13+ return function () {
14+ var f = only ? it.only : it;
15+ f(name, function (done) {
16+ aff(function () {
17+ done();
18+ }, function (err) {
19+ done(err);
20+ });
21+ });
22+ };
23+ };
24+ };
25+};
26+
27+exports.itPending = function (name) {
28+ "use strict";
29+ return function () {
30+ it(name);
31+ };
32+};
33+
34+exports.describe = function (only) {
35+ "use strict";
36+ return function (name) {
37+ return function (nested) {
38+ return function () {
39+ var f = only ? describe : describe.only;
40+ f(name, function () {
41+ nested();
42+ });
43+ };
44+ };
45+ };
46+};
src/Test/Spec/Mocha.pursnew file+41
@@ -0,0 +1,41 @@
1+module Test.Spec.Mocha (
2+ runMocha,
3+ MOCHA()
4+ ) where
5+
6+import Prelude
7+
8+import Control.Monad.Aff (Aff())
9+import Control.Monad.Eff (kind Effect, Eff())
10+
11+import Data.Foldable (traverse_)
12+
13+import Test.Spec (Spec, Group(..), collect)
14+
15+foreign import data MOCHA :: Effect
16+
17+foreign import itAsync :: forall e.
18+ Boolean
19+ -> String
20+ -> Aff e Unit
21+ -> Eff (mocha :: MOCHA | e) Unit
22+
23+foreign import itPending :: forall e. String
24+ -> Eff (mocha :: MOCHA | e) Unit
25+
26+foreign import describe :: forall e.
27+ Boolean
28+ -> String
29+ -> Eff (mocha :: MOCHA | e) Unit
30+ -> Eff (mocha :: MOCHA | e) Unit
31+
32+registerGroup :: forall e. (Group (Aff e Unit))
33+ -> Eff (mocha :: MOCHA | e) Unit
34+registerGroup (It only name test) = itAsync only name test
35+registerGroup (Pending name) = itPending name
36+registerGroup (Describe only name groups) =
37+ describe only name (traverse_ registerGroup groups)
38+
39+runMocha :: forall e. Spec e Unit
40+ -> Eff (mocha :: MOCHA | e) Unit
41+runMocha spec = traverse_ registerGroup (collect spec)
test/Main.purs+373−1108
@@ -2,1140 +2,405 @@ module Test.Main where
2
2
3import Prelude
3import Prelude
4
4
5−import Data.Array (head, drop)
5+import Control.Monad.Aff (Aff, launchAff, forkAff, delay)
6−import Data.Date as Date
6+import Control.Monad.Aff.AVar (AVAR, makeVar', modifyVar, peekVar, killVar)
7−import Data.DateTime (DateTime(..), Time(..))
7+import Control.Monad.Eff (Eff)
8−import Data.DateTime.Instant (toDateTime)
8+import Control.Monad.Eff.Class (liftEff)
9−import Data.Either (Either(..))
9+import Control.Monad.Eff.Exception (EXCEPTION)
10+import Data.Date as Date
11+import Data.DateTime as DateTime
12+import Data.DateTime (DateTime(..), Date(..), Time(..))
10−import Data.Enum (toEnum)
13+import Data.Enum (toEnum)
11−import Data.Maybe (Maybe(..), isNothing, maybe)
14+import Data.Maybe (Maybe(..))
12−import Data.Time.Duration (Milliseconds(..))
15+import Data.Time.Duration (Milliseconds(..))
13−import Data.Traversable (traverse)
14−import Data.Tuple (Tuple(..), uncurry)
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)
16+import Test.Spec (describe, it)
33−import Test.Spec.Assertions (shouldEqual, fail)
17+import Test.Spec.Assertions (shouldEqual, fail)
34−import Test.Spec.Reporter (consoleReporter)
18+import Test.Spec.Mocha (MOCHA, runMocha)
35−import Test.Spec.Runner (runSpec)
19+
36−
20+import Database.IndexedDB.Core
37−infixr 7 Tuple as :+:
21+import Database.IndexedDB.IDBKey
38−
22+import Database.IndexedDB.IDBDatabase as IDBDatabase
39−launchAff' :: forall a. Aff a -> Effect Unit
23+import Database.IndexedDB.IDBFactory as IDBFactory
40−launchAff' =
24+import Database.IndexedDB.IDBObjectStore as IDBObjectStore
41− launchAff_ <<< void
25+import Database.IndexedDB.IDBKeyRange as IDBKeyRange
42−
26+
43−modifyAVar :: forall a. (a -> a) -> AVar a -> Aff Unit
27+
44−modifyAVar fn v = do
28+tearDown :: forall eff. String -> Int -> Database -> Aff (idb :: INDEXED_DB, exception :: EXCEPTION | eff) Unit
45− val <- AVar.take v
46− AVar.put (fn val) v
47−
48−main :: Effect Unit
49−main = do
50− launchAff_ $ runSpec [ consoleReporter ] $ do
51− describe "IDBFactory" do
52− let
53− tearDown name version db = do
29+tearDown name version db = do
54− IDBDatabase.close db
30+ liftEff $ IDBDatabase.close db
55− version' <- IDBFactory.deleteDatabase name
31+ version' <- IDBFactory.deleteDatabase name
56− liftEffect $ log $ show version'
57− version' `shouldEqual` version
32+ version' `shouldEqual` version
58−
33+
34+-- main :: forall eff. Eff (mocha :: MOCHA, idb :: INDEXED_DB, exception :: EXCEPTION, avar :: AVAR | eff) Unit
35+main = runMocha do
36+ describe "IDBFactory" do
59− it "open default" do
37+ it "open default" do
60− let
61− name = "db-default"
38+ let name = "db-default"
62 version = 1
39 version = 1
63− db <- IDBFactory.open name Nothing
40+ db <- IDBFactory.open name Nothing
64− { onUpgradeNeeded: Nothing
41+ { onUpgradeNeeded : Nothing
65− , onBlocked: Nothing
42+ , onBlocked : Nothing
66− }
43+ }
67− IDBDatabase.name db `shouldEqual` name
44+ IDBDatabase.name db `shouldEqual` name
68− tearDown name version db
45+ tearDown name version db
69
46
70− it "open specific version" do
71− let
72− name = "db-specific"
73− version = 14
74− db <- IDBFactory.open name (Just version)
75− { onUpgradeNeeded: Nothing
76− , onBlocked: Nothing
77− }
78− IDBDatabase.name db `shouldEqual` name
79− tearDown name version db
80
47
81− it "open specific version -> close -> open latest" do
48+ it "open specific version" do
82− let
83− name = "db-latest"
49+ let name = "db-specific"
84 version = 14
50 version = 14
85− db01 <- IDBFactory.open name (Just version)
51+ db <- IDBFactory.open name (Just version)
86− { onUpgradeNeeded: Nothing
52+ { onUpgradeNeeded : Nothing
87− , onBlocked: Nothing
53+ , onBlocked : Nothing
88− }
54+ }
89− IDBDatabase.name db01 `shouldEqual` name
55+ IDBDatabase.name db `shouldEqual` name
90− IDBDatabase.close db01
91− db02 <- IDBFactory.open name Nothing
92− { onUpgradeNeeded: Nothing
93− , onBlocked: Nothing
94− }
95− tearDown name version db02
56+ tearDown name version db
96
57
58+
59+ it "open specific version -> close -> open latest" do
60+ let name = "db-latest"
61+ version = 14
62+ db <- IDBFactory.open name (Just version)
63+ { onUpgradeNeeded : Nothing
64+ , onBlocked : Nothing
65+ }
66+ IDBDatabase.name db `shouldEqual` name
67+ liftEff $ IDBDatabase.close db
68+ db <- IDBFactory.open name Nothing
69+ { onUpgradeNeeded : Nothing
70+ , onBlocked : Nothing
71+ }
72+ tearDown name version db
73+
74+
97− it "open + onUpgradeNeed" do
75+ it "open + onUpgradeNeed" do
98− let
99− name = "db-upgrade-needed"
76+ let name = "db-upgrade-needed"
100 version = 1
77 version = 1
101− callback (Tuple varName varVersion) db _ { oldVersion } = do
78+ callback var db = do
102− _ <- launchAff $ modifyAVar (const $ IDBDatabase.name db) varName
79+ _ <- launchAff $ modifyVar (const $ IDBDatabase.name db) var
103− _ <- launchAff $ modifyAVar (const $ oldVersion) varVersion
104 pure unit
80 pure unit
105− varName <- AVar.new "-"
81+ var <- makeVar' "-"
106− varVersion <- AVar.new (-1)
107− db <- IDBFactory.open name Nothing
82+ db <- IDBFactory.open name Nothing
108− { onUpgradeNeeded: Just (callback (Tuple varName varVersion))
83+ { onUpgradeNeeded : Just (callback var)
109− , onBlocked: Nothing
84+ , onBlocked : Nothing
110− }
85+ }
111− name' <- AVar.read varName
86+ name <- peekVar var
112− version' <- AVar.read varVersion
113− name' `shouldEqual` name
87+ name `shouldEqual` name
114− version' `shouldEqual` 0
115− tearDown name version db
88+ tearDown name version db
116−
89+
90+
117− it "open + onBlocked" do
91+ it "open + onBlocked" do
118− let
119− name = "db-blocked"
92+ let name = "db-blocked"
120 version = 14
93 version = 14
121 callback var = do
94 callback var = do
122− _ <- launchAff $ modifyAVar (const $ "db-blocked") var
95+ _ <- launchAff $ modifyVar (const $ "db-blocked") var
123 pure unit
96 pure unit
124
97
125− var <- AVar.new "-"
98+ var <- makeVar' "-"
126− db01 <- IDBFactory.open name Nothing
99+ db01 <- IDBFactory.open name Nothing
127− { onUpgradeNeeded: Nothing
100+ { onUpgradeNeeded : Nothing
128− , onBlocked: Nothing
101+ , onBlocked : Nothing
129− }
102+ }
130− _ <- forkAff do
103+ _ <- forkAff do
131− delay (Milliseconds 100.0)
104+ delay (Milliseconds 100.0)
132− IDBDatabase.close db01
105+ liftEff $ IDBDatabase.close db01
133−
106+
134− db02 <- IDBFactory.open name (Just version)
107+ db02 <- IDBFactory.open name (Just version)
135− { onUpgradeNeeded: Nothing
108+ { onUpgradeNeeded : Nothing
136− , onBlocked: Just (callback var)
109+ , onBlocked : Just (callback var)
137− }
110+ }
138− name' <- AVar.read var
111+ name <- peekVar var
139− name' `shouldEqual` name
112+ name `shouldEqual` name
140− tearDown name version db02
113+ tearDown name version db02
141−
114+
142− describe "IDBKeyRange" do
115+ describe "IDBKeyRange" do
143− it "only(int)" do
116+ it "only(int)" do
144− let
145− key = 14
117+ let key = 14
146− range = IDBKeyRange.only key
118+ range = IDBKeyRange.new $ IDBKeyRange.Only key
147− IDBKeyRange.includes range (toKey key) `shouldEqual` true
119+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
148−
120+
149− it "only(string)" do
121+ it "only(string)" do
150− let
151− key = "patate"
122+ let key = "patate"
152− range = IDBKeyRange.only key
123+ range = IDBKeyRange.new $ IDBKeyRange.Only key
153− IDBKeyRange.includes range (toKey key) `shouldEqual` true
124+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
154−
125+
155− it "only(float)" do
126+ it "only(float)" do
156− let
157− key = 14.42
127+ let key = 14.42
158− range = IDBKeyRange.only key
128+ range = IDBKeyRange.new $ IDBKeyRange.Only key
159− IDBKeyRange.includes range (toKey key) `shouldEqual` true
129+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
160−
130+
161− it "only(date)" do
131+ it "only(date)" do
162− let
163− mkey = DateTime
132+ let mkey = DateTime
164 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
133 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
165 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
134 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
166
135
167− case mkey of
136+ case mkey of
168− Nothing ->
137+ Nothing ->
169− fail "unable to create datetime"
138+ fail "unable to create datetime"
170− Just key -> do
139+ Just key -> do
171− let range = IDBKeyRange.only key
140+ let range = IDBKeyRange.new $ IDBKeyRange.Only key
172− IDBKeyRange.includes range (toKey key) `shouldEqual` true
141+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
173−
142+
174− it "only([int])" do
143+ it "only([int])" do
175− let
176− key = [ 14, 42 ]
144+ let key = [14, 42]
177− range = IDBKeyRange.only key
145+ range = IDBKeyRange.new $ IDBKeyRange.Only key
178− IDBKeyRange.includes range (toKey key) `shouldEqual` true
146+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
179−
147+
180− it "only([string])" do
148+ it "only([string])" do
181− let
182− key = [ "patate", "autruche" ]
149+ let key = ["patate", "autruche"]
183− range = IDBKeyRange.only key
150+ range = IDBKeyRange.new $ IDBKeyRange.Only key
184− IDBKeyRange.includes range (toKey key) `shouldEqual` true
185−
186− it "lowerBound(14, open)" do
187− let
188− key = 14
189− open = true
190− range = IDBKeyRange.lowerBound key open
191− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
192− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
193− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
194−
195− it "lowerBound(14, close)" do
196− let
197− key = 14
198− open = false
199− range = IDBKeyRange.lowerBound key open
200− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
151+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
201− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
152+
202− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
203−
204− it "upperBound(14, open)" do
205− let
206− key = 14
207− open = true
208− range = IDBKeyRange.upperBound key open
209− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
210− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
211− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
212−
213− it "upperBound(14, close)" do
214− let
215− key = 14
216− open = false
217− range = IDBKeyRange.upperBound key open
218− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
219− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
220− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
221−
222− it "bound(42, 14, open, open) => Nothing" do
223− let
224− lower = 42
225− upper = 14
226− lowerOpen = true
227− upperOpen = true
228− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
229− isNothing mrange `shouldEqual` true
230−
231− it "bound(14, 42, open, open)" do
232− let
233− lower = 14
234− upper = 42
235− lowerOpen = true
236− upperOpen = true
237− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
238− case mrange of
239− Nothing ->
240− fail "invalid range provided"
241− Just range -> do
242− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
243− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
244− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
245− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
246− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
247− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
248−
249− it "bound(14, 42, open, close)" do
250− let
251− lower = 14
252− upper = 42
253− lowerOpen = true
254− upperOpen = false
255− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
256− case mrange of
257− Nothing ->
258− fail "invalid range provided"
259− Just range -> do
260− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
261− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
262− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
263− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
264− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
265− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
266−
267− it "bound(14, 42, close, open)" do
268− let
269− lower = 14
270− upper = 42
271− lowerOpen = false
272− upperOpen = true
273− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
274− case mrange of
275− Nothing ->
276− fail "invalid range provided"
277− Just range -> do
278− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
279− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
280− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
281− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
282− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
283− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
284−
285− it "bound(14, 42, close, close)" do
286− let
287− lower = 14
288− upper = 42
289− lowerOpen = false
290− upperOpen = false
291− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
292− case mrange of
293− Nothing ->
294− fail "invalid range provided"
295− Just range -> do
296− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
297− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
298− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
299− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
300− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
301− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
302−
303− it "can access attributes of a range" do
304− let range = IDBKeyRange.lowerBound 14 false
305− IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
306− IDBKeyRange.upper range `shouldEqual` none
307− IDBKeyRange.lowerOpen range `shouldEqual` false
308− IDBKeyRange.upperOpen range `shouldEqual` true
309−
310− describe "IDBDatabase" do
153+ describe "IDBDatabase" do
311− let
154+ it "createObjectStore (keyPath: [], autoIncrement: true)" do
312− tearDown db = do
155+ let dbName = "db-create-store-01"
313− IDBDatabase.close db
156+ dbVersion = 1
314− _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
157+ storeName = "store"
315− pure unit
158+ keyPath = []
316−
159+ autoIncrement = true
317− setup storeParams = do
160+ callback var db = do
318− let
161+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
319− onUpgradeNeeded var db _ _ = launchAff' do
162+ _ <- launchAff $ IDBObjectStore.name store `shouldEqual` storeName
320− store <- IDBDatabase.createObjectStore db "store" storeParams
163+ _ <- launchAff $ IDBObjectStore.keyPath store `shouldEqual` keyPath
321− _ <- AVar.put { db, store } var
164+ _ <- launchAff $ IDBObjectStore.autoIncrement store `shouldEqual` autoIncrement
322− pure unit
165+ _ <- launchAff $ IDBObjectStore.indexNames store `shouldEqual` []
323−
166+ _ <- launchAff $ modifyVar (const true) var
324− var <- AVar.empty
167+ pure unit
325− _ <- IDBFactory.open "db" Nothing
326− { onUpgradeNeeded: Just (onUpgradeNeeded var)
327− , onBlocked: Nothing
328− }
329
168
330− AVar.take var
169+ var <- makeVar' false
170+ db <- IDBFactory.open dbName Nothing
171+ { onUpgradeNeeded : Just (callback var)
172+ , onBlocked : Nothing
173+ }
174+ hasBeenCalled <- peekVar var
175+ hasBeenCalled `shouldEqual` true
176+ tearDown dbName dbVersion db
177+
178+
179+ it "createObjectStore (keyPath: [\"field\"], autoIncrement: true)" do
180+ let dbName = "db-create-store-02"
181+ dbVersion = 1
182+ storeName = "store"
183+ keyPath = ["field"]
184+ autoIncrement = true
185+ callback var db = do
186+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
187+ _ <- launchAff $ IDBObjectStore.name store `shouldEqual` storeName
188+ _ <- launchAff $ IDBObjectStore.keyPath store `shouldEqual` keyPath
189+ _ <- launchAff $ IDBObjectStore.autoIncrement store `shouldEqual` autoIncrement
190+ _ <- launchAff $ IDBObjectStore.indexNames store `shouldEqual` []
191+ _ <- launchAff $ modifyVar (const true) var
192+ pure unit
331
193
194+ var <- makeVar' false
195+ db <- IDBFactory.open dbName Nothing
196+ { onUpgradeNeeded : Just (callback var)
197+ , onBlocked : Nothing
198+ }
199+ hasBeenCalled <- peekVar var
200+ hasBeenCalled `shouldEqual` true
201+ tearDown dbName dbVersion db
202+
203+
332− it "createObjectStore (keyPath: [], autoIncrement: true)" do
204+ it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
205+ let dbName = "db-create-store-03"
206+ dbVersion = 1
207+ storeName = "store"
208+ keyPath = ["a", "b"]
209+ autoIncrement = false
210+ callback var db = do
333− { db, store } <- setup { keyPath: [], autoIncrement: true }
211+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
334− IDBObjectStore.name store `shouldEqual` "store"
212+ _ <- launchAff $ IDBObjectStore.name store `shouldEqual` storeName
335− IDBObjectStore.keyPath store `shouldEqual` []
213+ _ <- launchAff $ IDBObjectStore.keyPath store `shouldEqual` keyPath
336− IDBObjectStore.autoIncrement store `shouldEqual` true
214+ _ <- launchAff $ IDBObjectStore.autoIncrement store `shouldEqual` autoIncrement
337− IDBObjectStore.indexNames store `shouldEqual` []
215+ _ <- launchAff $ IDBObjectStore.indexNames store `shouldEqual` []
338− tearDown db
216+ _ <- launchAff $ modifyVar (const true) var
217+ pure unit
339
218
219+ var <- makeVar' false
220+ db <- IDBFactory.open dbName Nothing
221+ { onUpgradeNeeded : Just (callback var)
222+ , onBlocked : Nothing
223+ }
224+ hasBeenCalled <- peekVar var
225+ hasBeenCalled `shouldEqual` true
226+ tearDown dbName dbVersion db
227+
228+
340− it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
229+ it "createObjectStore (keyPath: [\"field\"], autoIncrement: false)" do
341− { db, store } <- setup { keyPath: [ "patate" ], autoIncrement: true }
230+ let dbName = "db-create-store-04"
231+ dbVersion = 1
232+ storeName = "store"
233+ keyPath = ["field"]
234+ autoIncrement = false
235+ callback var db = do
236+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
342− IDBObjectStore.name store `shouldEqual` "store"
237+ _ <- launchAff $ IDBObjectStore.name store `shouldEqual` storeName
343− IDBObjectStore.keyPath store `shouldEqual` [ "patate" ]
238+ _ <- launchAff $ IDBObjectStore.keyPath store `shouldEqual` keyPath
344− IDBObjectStore.autoIncrement store `shouldEqual` true
239+ _ <- launchAff $ IDBObjectStore.autoIncrement store `shouldEqual` autoIncrement
345− IDBObjectStore.indexNames store `shouldEqual` []
240+ _ <- launchAff $ IDBObjectStore.indexNames store `shouldEqual` []
346− tearDown db
241+ _ <- launchAff $ modifyVar (const true) var
242+ pure unit
347
243
348− it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
244+ var <- makeVar' false
349− { db, store } <- setup { keyPath: [ "patate", "autruche" ], autoIncrement: false }
245+ db <- IDBFactory.open dbName Nothing
350− IDBObjectStore.name store `shouldEqual` "store"
246+ { onUpgradeNeeded : Just (callback var)
351− IDBObjectStore.keyPath store `shouldEqual` [ "patate", "autruche" ]
247+ , onBlocked : Nothing
352− IDBObjectStore.autoIncrement store `shouldEqual` false
248+ }
353− IDBObjectStore.indexNames store `shouldEqual` []
249+ hasBeenCalled <- peekVar var
354− tearDown db
250+ hasBeenCalled `shouldEqual` true
251+ tearDown dbName dbVersion db
252+
253+
254+ it "deleteObjectStore" do
255+ let dbName = "db-delete-store"
256+ dbVersion = 2
257+ storeName = "store"
258+ keyPath = []
259+ autoIncrement = true
260+ callback db = do
261+ _ <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
262+ pure unit
263+ callback2 var db = do
264+ _ <- IDBDatabase.deleteObjectStore db storeName
265+ _ <- launchAff $ modifyVar (const true) var
266+ pure unit
355
267
356− it "deleteObjectStore" do
268+ var <- makeVar' false
357− let
269+ db <- IDBFactory.open dbName Nothing
358− onUpgradeNeeded var db _ _ = launchAff' do
270+ { onUpgradeNeeded : Just callback
359− _ <- IDBDatabase.deleteObjectStore db "store"
271+ , onBlocked : Nothing
360− AVar.put true var
272+ }
273+ liftEff $ IDBDatabase.close db
274+ db <- IDBFactory.open dbName (Just dbVersion)
275+ { onUpgradeNeeded : Just (callback2 var)
276+ , onBlocked : Nothing
277+ }
278+ hasBeenCalled <- peekVar var
279+ hasBeenCalled `shouldEqual` true
280+ tearDown dbName dbVersion db
281+
282+ describe "IDBObjectStore" do
283+ it "add(\"patate\", Nothing )" do
284+ let dbName = "db-add"
285+ dbVersion = 1
286+ storeName = "store"
287+ keyPath = []
288+ autoIncrement = true
289+ key = 1
290+ callback db = do
291+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
292+ key <- launchAff $ ((unsafeFromKey >>> shouldEqual key)
293+ <$> IDBObjectStore.add store "patate" Nothing)
294+ pure unit
361
295
362− var <- AVar.empty
363− { db } <- setup IDBDatabase.defaultParameters
364− IDBDatabase.close db
365− db' <- IDBFactory.open "db" (Just 999)
296+ db <- IDBFactory.open dbName Nothing
366− { onUpgradeNeeded: Just (onUpgradeNeeded var)
297+ { onUpgradeNeeded : Just callback
367− , onBlocked: Nothing
298+ , onBlocked : Nothing
368− }
299+ }
369− deleted <- AVar.take var
370− deleted `shouldEqual` true
371− tearDown db'
300+ tearDown dbName dbVersion db
301+
302+ it "add(\"patate\", Just 14 )" do
303+ let dbName = "db-add"
304+ dbVersion = 1
305+ storeName = "store"
306+ keyPath = []
307+ autoIncrement = true
308+ key = 14
309+ callback db = do
310+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
311+ key <- launchAff $ ((unsafeFromKey >>> shouldEqual key)
312+ <$> IDBObjectStore.add store "patate" (Just $ toKey key))
313+ pure unit
372
314
373− describe "IDBObjectStore" do
315+ db <- IDBFactory.open dbName Nothing
374− let
316+ { onUpgradeNeeded : Just callback
375− tearDown db = do
317+ , onBlocked : Nothing
376− IDBDatabase.close db
318+ }
377− _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
319+ tearDown dbName dbVersion db
320+
321+ it "add(\"patate\", Just \"key\" )" do
322+ let dbName = "db-add"
323+ dbVersion = 1
324+ storeName = "store"
325+ keyPath = []
326+ autoIncrement = true
327+ key = "key"
328+ callback db = do
329+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
330+ key <- launchAff $ ((unsafeFromKey >>> shouldEqual key)
331+ <$> IDBObjectStore.add store "patate" (Just $ toKey key))
378− pure unit
332+ pure unit
379
333
380− setup { storeParams, onUpgradeNeeded } = do
334+ db <- IDBFactory.open dbName Nothing
381− let
335+ { onUpgradeNeeded : Just callback
382− onUpgradeNeeded' var db _ _ = launchAff' do
336+ , onBlocked : Nothing
383− store <- IDBDatabase.createObjectStore db "store" storeParams
337+ }
384− liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure store)
338+ tearDown dbName dbVersion db
385− AVar.put { db, store } var
339+
340+ it "add(\"patate\", Just <date> )" do
341+ let dbName = "db-add"
342+ dbVersion = 1
343+ storeName = "store"
344+ keyPath = []
345+ autoIncrement = true
346+ mkey = DateTime
347+ <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
348+ <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
386
349
387− var <- AVar.empty
350+ case mkey of
351+ Nothing ->
352+ fail "unable to create datetime"
353+ Just key -> do
354+ let callback db = do
355+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
356+ key <- launchAff $ ((unsafeFromKey >>> shouldEqual key)
357+ <$> IDBObjectStore.add store "patate" (Just $ toKey key))
358+ pure unit
359+
388− _ <- IDBFactory.open "db" Nothing
360+ db <- IDBFactory.open dbName Nothing
389− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
361+ { onUpgradeNeeded : Just callback
390− , onBlocked: Nothing
362+ , onBlocked : Nothing
391 }
363 }
364+ tearDown dbName dbVersion db
365+
366+ it "add(\"patate\", Just [14, 42] )" do
367+ let dbName = "db-add"
368+ dbVersion = 1
369+ storeName = "store"
370+ keyPath = []
371+ autoIncrement = true
372+ key = [14, 42]
373+ callback db = do
374+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
375+ key <- launchAff $ ((unsafeFromKey >>> shouldEqual key)
376+ <$> IDBObjectStore.add store "patate" (Just $ toKey key))
377+ pure unit
392
378
393− AVar.take var
379+ db <- IDBFactory.open dbName Nothing
394−
395− it "add()" do
396− date <- liftEffect $ toDateTime <$> now
397− { db } <- setup
398− { storeParams: { autoIncrement: true, keyPath: [] }
399− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
380+ { onUpgradeNeeded : Just callback
400− -- no key
381+ , onBlocked : Nothing
401− key <- IDBObjectStore.add store "patate" none
402− (toKey 1) `shouldEqual` key
403−
404− -- int key
405− key' <- IDBObjectStore.add store "patate" (Just 14)
406− (toKey 14) `shouldEqual` key'
407−
408− -- number key
409− key'' <- IDBObjectStore.add store "patate" (Just 14.42)
410− (toKey 14.42) `shouldEqual` key''
411−
412− -- string key
413− key''' <- IDBObjectStore.add store "patate" (Just "key")
414− (toKey "key") `shouldEqual` key'''
415−
416− -- date key
417− key'''' <- IDBObjectStore.add store "patate" (Just date)
418− (toKey date) `shouldEqual` key''''
419−
420− -- array key
421− key''''' <- IDBObjectStore.add store "patate" (Just $ toKey [ 14, 42 ])
422− (toKey [ 14, 42 ]) `shouldEqual` key'''''
423− }
382+ }
424− tearDown db
383+ tearDown dbName dbVersion db
425−
384+
426− it "clear()" do
385+ it "clear()" do
427− { db } <- setup
386+ let dbName = "db-clear"
428− { storeParams: IDBDatabase.defaultParameters
387+ dbVersion = 1
388+ storeName = "store"
389+ keyPath = []
390+ autoIncrement = true
391+ callback db = do
392+ store <- IDBDatabase.createObjectStore db storeName { keyPath, autoIncrement }
429− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
393+ _ <- launchAff $ do
430− key <- IDBObjectStore.add store "patate" (Just 14)
394+ _ <- IDBObjectStore.add store "patate" (Just $ toKey 14)
431 _ <- IDBObjectStore.clear store
395 _ <- IDBObjectStore.clear store
432− val <- IDBObjectStore.get store (IDBKeyRange.only key)
396+ v <- IDBObjectStore.get store (IDBKeyRange.new $ IDBKeyRange.Only 14)
433− val `shouldEqual` (Nothing :: Maybe String)
397+ v `shouldEqual` (Nothing :: Maybe Int)
434− }
435− tearDown db
436−
437− it "count()" do
438− { db } <- setup
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
444− n `shouldEqual` 2
445− }
446− tearDown db
447−
448− it "getKey()" do
449− { db } <- setup
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)
455−
456− mkey' <- IDBObjectStore.getKey store (IDBKeyRange.only 42)
457− mkey' `shouldEqual` none
458− }
459− tearDown db
460−
461− it "getAllKeys()" do
462− { db } <- setup
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)
468−
469− -- no bounds
470− keys <- IDBObjectStore.getAllKeys store Nothing Nothing
471− keys `shouldEqual` [ key1, key2, key3 ]
472−
473− -- lower bound
474− keys' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
475− keys' `shouldEqual` [ key2, key3 ]
476−
477− -- upper bound
478− keys'' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
479− keys'' `shouldEqual` [ key1, key2 ]
480−
481− -- count
482− keys''' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
483− keys''' `shouldEqual` [ key1, key2 ]
484− }
485− tearDown db
486−
487− it "openCursor()" do
488− let
489− cb =
490− { onSuccess: const $ pure unit
491− , onError: show >>> fail >>> launchAff'
492− , onComplete: pure unit
493− }
494− { db } <- setup
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
502− pure unit
503− }
504− tearDown db
505
398
506− it "openKeyCursor()" do
399+ pure unit
507− let
508− cb =
509− { onSuccess: const $ pure unit
510− , onError: show >>> fail >>> launchAff'
511− , onComplete: pure unit
512− }
513− { db } <- setup
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
521− pure unit
522− }
523− tearDown db
524−
525− describe "IDBIndex" do
526− let
527− tearDown db = do
528− IDBDatabase.close db
529− _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
530− pure unit
531−
532− setup
533− :: forall value
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)
539− }
540− -> Aff { db :: Database, index :: Index, store :: ObjectStore }
541− setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
542− let
543− onUpgradeNeeded' var db tx _ = launchAff' do
544− 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)
548− AVar.put { db, index, store } var
549−
550− var <- AVar.empty
551− _ <- IDBFactory.open "db" Nothing
552− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
553− , onBlocked: Nothing
554− }
555− AVar.take var
556−
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
562− , keyPath: []
563− , values: []
564− }
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
569− tearDown db
570−
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)
573− txVar <- AVar.empty
574− dbVar <- AVar.empty
575− res <- attempt $ setup
576− { storeParams: IDBDatabase.defaultParameters
577− , indexParams:
578− { unique: true
579− , multiEntry: false
580− }
581− , keyPath: [ "indexedProperty" ]
582− , values:
583− [ { indexedProperty: "bar" } :+: (Just $ toKey 1)
584− , { indexedProperty: "bar" } :+: (Just $ toKey 2)
585− ]
586− , onUpgradeNeeded: Just $ \db tx _ -> launchAff' do
587− IDBTransaction.onAbort tx (onAbort txVar)
588− IDBDatabase.onAbort db (onAbort dbVar)
589− }
590− case res of
591− Right _ ->
592− fail "expected abort"
593− _ -> do
594− shouldEqual true =<< AVar.take txVar
595− shouldEqual true =<< AVar.take dbVar
596−
597− it "the index is usable right after being made" do
598− { db } <- setup
599− { storeParams:
600− { keyPath: [ "key" ]
601− , autoIncrement: false
602− }
603− , indexParams: IDBObjectStore.defaultParameters
604− , keyPath: [ "indexedProperty" ]
605− , values:
606− [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
607− , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
608− , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
609− ]
610− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
611− val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
612− ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
613− }
614− tearDown db
615−
616− it "empty keyPath" do
617− { db } <- setup
618− { storeParams: IDBDatabase.defaultParameters
619− , indexParams: IDBObjectStore.defaultParameters
620− , keyPath: []
621− , values:
622− [ "object_1" :+: (Just $ toKey 1)
623− , "object_2" :+: (Just $ toKey 2)
624− , "object_3" :+: (Just $ toKey 3)
625− ]
626− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
627− val <- IDBIndex.get index (IDBKeyRange.only "object_3")
628− val `shouldEqual` (Just "object_3")
629− }
630− tearDown db
631−
632− it "index can be valid keys [date]" do
633− date <- liftEffect $ toDateTime <$> now
634− { db } <- setup
635− { storeParams:
636− { keyPath: [ "key" ]
637− , autoIncrement: false
638− }
639− , indexParams: IDBObjectStore.defaultParameters
640− , keyPath: [ "i" ]
641− , values:
642− [ { key: "date", i: (toKey date) } :+: Nothing
643− ]
644− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
645− val <- IDBIndex.get index (IDBKeyRange.only date)
646− ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
647− }
648− tearDown db
649−
650− it "index can be valid keys [num]" do
651− let num = 14
652− { db } <- setup
653− { storeParams:
654− { keyPath: [ "key" ]
655− , autoIncrement: false
656− }
657− , indexParams: IDBObjectStore.defaultParameters
658− , keyPath: [ "i" ]
659− , values:
660− [ { key: "num", i: (toKey num) } :+: Nothing
661− ]
662− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
663− val <- IDBIndex.get index (IDBKeyRange.only num)
664− ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
665− }
666− tearDown db
667−
668− it "index can be valid keys [array]" do
669− let array = [ "patate", "autruche" ]
670− { db } <- setup
671− { storeParams:
672− { keyPath: [ "key" ]
673− , autoIncrement: false
674− }
675− , indexParams: IDBObjectStore.defaultParameters
676− , keyPath: [ "i" ]
677− , values:
678− [ { key: "array", i: (toKey array) } :+: Nothing
679− ]
680− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
681− val <- IDBIndex.get index (IDBKeyRange.only array)
682− ((\r -> r.key) <$> val) `shouldEqual` (Just "array")
683− }
684− tearDown db
685−
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" ]
691− , values:
692− [ { key: 14, indexedProperty: "patate" } :+: Nothing
693− ]
694− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
695− let
696− cb =
697− { onSuccess: const $ pure unit
698− , onError: show >>> fail >>> launchAff'
699− , onComplete: pure unit
700− }
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
705− case cursor of
706− Right _ -> fail "expected InvalidStateError"
707− Left err -> name err `shouldEqual` "InvalidStateError"
708− }
709− case res of
710− Right _ -> fail "expected InvalidStateError"
711− _ -> pure unit
712−
713− it "openKeyCursor() - throw TransactionInactiveError on aborted transaction" do
714− { db } <- setup
715− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
716− , indexParams: IDBObjectStore.defaultParameters
717− , keyPath: [ "indexedProperty" ]
718− , values:
719− [ { key: 14, indexedProperty: "patate" } :+: Nothing
720− ]
721− , onUpgradeNeeded: Nothing
722− }
723− let
724− cb =
725− { onSuccess: const $ pure unit
726− , onError: show >>> fail >>> launchAff'
727− , onComplete: pure unit
728− }
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
735− case cursor of
736− Right _ -> fail "expected TransactionInactiveError"
737− Left err -> name err `shouldEqual` "TransactionInactiveError"
738−
739− tearDown db
740−
741− it "openKeyCursor() - throw InvalidStateError when the index is deleted" do
742− { db } <- setup
743− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
744− , indexParams: IDBObjectStore.defaultParameters
745− , keyPath: [ "indexedProperty" ]
746− , values:
747− [ { key: 14, indexedProperty: "patate" } :+: Nothing
748− ]
749− , onUpgradeNeeded: Just $ \_ tx index -> launchAff' do
750− let
751− cb =
752− { onSuccess: const $ pure unit
753− , onError: show >>> fail >>> launchAff'
754− , onComplete: pure unit
755− }
756− store <- IDBTransaction.objectStore tx "store"
757− IDBObjectStore.deleteIndex store "index"
758− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
759− case cursor of
760− Right _ -> fail "expected InvalidStateError"
761− Left err -> name err `shouldEqual` "InvalidStateError"
762− }
763−
764− tearDown db
765−
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" ]
771− , values:
772− [ { key: 14, indexedProperty: "patate" } :+: Nothing
773− ]
774− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
775− let
776− cb =
777− { onSuccess: const $ pure unit
778− , onError: show >>> fail >>> launchAff'
779− , onComplete: pure unit
780− }
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
785− case cursor of
786− Right _ -> fail "expected InvalidStateError"
787− Left err -> name err `shouldEqual` "InvalidStateError"
788− }
789− case res of
790− Right _ -> fail "expected InvalidStateError"
791− _ -> pure unit
792−
793− it "openCursor() - throw TransactionInactiveError on aborted transaction" do
794− { db } <- setup
795− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
796− , indexParams: IDBObjectStore.defaultParameters
797− , keyPath: [ "indexedProperty" ]
798− , values:
799− [ { key: 14, indexedProperty: "patate" } :+: Nothing
800− ]
801− , onUpgradeNeeded: Nothing
802− }
803− let
804− cb =
805− { onSuccess: const $ pure unit
806− , onError: show >>> fail >>> launchAff'
807− , onComplete: pure unit
808− }
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
815− case cursor of
816− Right _ -> fail "expected TransactionInactiveError"
817− Left err -> name err `shouldEqual` "TransactionInactiveError"
818−
819− tearDown db
820−
821− it "openCursor() - throw InvalidStateError when the index is deleted" do
822− { db } <- setup
823− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
824− , indexParams: IDBObjectStore.defaultParameters
825− , keyPath: [ "indexedProperty" ]
826− , values:
827− [ { key: 14, indexedProperty: "patate" } :+: Nothing
828− ]
829− , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
830− let
831− cb =
832− { onSuccess: const $ pure unit
833− , onError: show >>> fail >>> launchAff'
834− , onComplete: pure unit
835− }
836− store <- IDBTransaction.objectStore tx "store"
837− IDBObjectStore.deleteIndex store "index"
838− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
839− case cursor of
840− Right _ -> fail "expected InvalidStateError"
841− Left err -> name err `shouldEqual` "InvalidStateError"
842− }
843−
844− tearDown db
845−
846− it "getKey() - multiEntry - adding keys" do
847− { db } <- setup
848− { storeParams: IDBDatabase.defaultParameters
849− , indexParams: { unique: false, multiEntry: true }
850− , keyPath: [ "name" ]
851− , values:
852− [ { name: [ "patate", "autruche" ] } :+: (Just $ toKey 1)
853− , { name: [ "bob" ] } :+: (Just $ toKey 2)
854− ]
855− , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
856− key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
857− key `shouldEqual` (Just $ toKey 1)
858−
859− key' <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
860− key' `shouldEqual` (Just $ toKey 1)
861−
862− key'' <- IDBIndex.getKey index (IDBKeyRange.only "bob")
863− key'' `shouldEqual` (Just $ toKey 2)
864− }
865− tearDown db
866−
867− it "get() - returns the record with the first key in the range" do
868− { db } <- setup
869− { storeParams: { keyPath: [ "key" ], autoIncrement: false }
870− , indexParams: IDBObjectStore.defaultParameters
871− , keyPath: [ "indexedProperty" ]
872− , values:
873− [ { key: 14, indexedProperty: "patate" } :+: Nothing
874− , { key: 42, indexedProperty: "autruche" } :+: Nothing
875− , { key: 1337, indexedProperty: "baguette" } :+: Nothing
876− ]
877− , onUpgradeNeeded: Nothing
878− }
879−
880− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
881− store <- IDBTransaction.objectStore tx "store"
882− index <- IDBObjectStore.index store "index"
883− val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
884− ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
885−
886− tearDown db
887−
888− describe "IDBCursor" do
889− let
890− tearDown db = do
891− IDBDatabase.close db
892− _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
893− pure unit
894−
895− setup
896− :: forall value
897− . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
898− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
899− , values :: Array (Tuple value (Maybe Key))
900− , keyPath :: Array String
901− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
902− }
903− -> Aff { db :: Database, index :: Index, store :: ObjectStore }
904− setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
905− let
906− onUpgradeNeeded' var db tx _ = launchAff' do
907− store <- IDBDatabase.createObjectStore db "store" storeParams
908− _ <- traverse (uncurry (IDBObjectStore.add store)) values
909− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
910− liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
911− AVar.put { db, index, store } var
912−
913− var <- AVar.empty
914− db <- IDBFactory.open "db" Nothing
915− { onUpgradeNeeded: Just (onUpgradeNeeded' var)
916− , onBlocked: Nothing
917− }
918− AVar.take var
919−
920− it "continue() - iterate to the next record" do
921− { db } <- setup
922− { storeParams: IDBDatabase.defaultParameters
923− , indexParams: IDBObjectStore.defaultParameters
924− , keyPath: []
925− , values:
926− [ "cupcake" :+: (Just $ toKey 4)
927− , "pancake" :+: (Just $ toKey 2)
928− , "pie" :+: (Just $ toKey 1)
929− , "pie" :+: (Just $ toKey 3)
930− ]
931− , onUpgradeNeeded: Nothing
932− }
933− let
934− cb vdone vvals =
935− { onComplete: launchAff' do
936− AVar.put unit vdone
937−
938− , onError: \error -> launchAff' do
939− fail $ "unexpected error: " <> show error
940−
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
947− }
948− vdone <- AVar.empty
949− vvals <- AVar.new
950− [ { v: "pie", k: toKey 1 }
951− , { v: "pancake", k: toKey 2 }
952− , { v: "pie", k: toKey 3 }
953− , { v: "cupcake", k: toKey 4 }
954− ]
955− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
956− store <- IDBTransaction.objectStore tx "store"
957− IDBObjectStore.openCursor store Nothing Next (cb vdone vvals)
958− AVar.take vdone
959− tearDown db
960−
961− it "continue() - attempt to iterate in the wrong direction" do
962− { db } <- setup
963− { storeParams: IDBDatabase.defaultParameters
964− , indexParams: IDBObjectStore.defaultParameters
965− , keyPath: []
966− , values:
967− [ "cupcake" :+: (Just $ toKey 4)
968− , "pancake" :+: (Just $ toKey 2)
969− , "pie" :+: (Just $ toKey 1)
970− , "pie" :+: (Just $ toKey 3)
971− ]
972− , onUpgradeNeeded: Nothing
973− }
974− let
975− cb vdone =
976− { onComplete: launchAff' do
977− fail $ "shouldn't complete"
978−
979− , onError: \error -> launchAff' do
980− fail $ "unexpected error: " <> show error
981−
982− , onSuccess: \cursor -> launchAff' do
983− res <- attempt $ IDBCursor.continue cursor (Just 1)
984− case res of
985− Left err -> do
986− name err `shouldEqual` "DataError"
987− AVar.put unit vdone
988− Right _ -> do
989− fail "expected continue to fail"
990− }
991− vdone <- AVar.empty
992− tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
993− store <- IDBTransaction.objectStore tx "store"
994− IDBObjectStore.openCursor store Nothing Next (cb vdone)
995− AVar.take vdone
996− tearDown db
997−
998− it "advance() - iterate cursor number of times specified by count" do
999− { db } <- setup
1000− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1001− , indexParams: IDBObjectStore.defaultParameters
1002− , keyPath: []
1003− , values:
1004− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: 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
1008− ]
1009− , onUpgradeNeeded: Nothing
1010− }
1011− let
1012− cb vdone vjump =
1013− { onComplete: launchAff' do
1014− AVar.put unit vdone
1015−
1016− , onError: \error -> launchAff' do
1017− fail $ "unexpected error: " <> show error
1018−
1019− , onSuccess: \cursor -> launchAff' do
1020− jump <- AVar.take vjump
1021− if jump then do
1022− IDBCursor.advance cursor 3
1023− else do
1024− let value = IDBCursor.value cursor
1025− value.pKey `shouldEqual` "pkey_3"
1026− value.iKey `shouldEqual` "ikey_3"
1027− IDBCursor.continue cursor none
1028− AVar.put false vjump
1029− }
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)
1035− AVar.take vdone
1036− tearDown db
1037−
1038− it "delete() - remove a record from the object store" do
1039− { db } <- setup
1040− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1041− , indexParams: IDBObjectStore.defaultParameters
1042− , keyPath: []
1043− , values:
1044− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1045− , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
1046− , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
1047− , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
1048− ]
1049− , onUpgradeNeeded: Nothing
1050− }
1051− let
1052− cb vdone store =
1053− { onComplete: launchAff' do
1054− mval <- map _.pKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
1055− mval `shouldEqual` (Nothing :: Maybe String)
1056− AVar.put unit vdone
1057−
1058− , onError: \error -> launchAff' do
1059− fail $ "unexpected error: " <> show error
1060−
1061− , onSuccess: \cursor -> launchAff' do
1062− let value = IDBCursor.value cursor
1063− value.pKey `shouldEqual` "pkey_0"
1064− IDBCursor.delete cursor
1065− IDBCursor.advance cursor 4
1066− }
1067− vdone <- AVar.empty
1068− tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
1069− store <- IDBTransaction.objectStore tx "store"
1070− IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1071− AVar.take vdone
1072− tearDown db
1073−
1074− it "update() - modify a record in the object store" do
1075− { db } <- setup
1076− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1077− , indexParams: IDBObjectStore.defaultParameters
1078− , keyPath: []
1079− , values:
1080− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1081− ]
1082− , onUpgradeNeeded: Nothing
1083− }
1084− let
1085− cb vdone store =
1086− { onComplete: launchAff' do
1087− mval <- map _.iKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
1088− mval `shouldEqual` (Just "patate")
1089− AVar.put unit vdone
1090−
1091− , onError: \error -> launchAff' do
1092− fail $ "unexpected error: " <> show error
1093−
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
1100− }
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)
1105− AVar.take vdone
1106− tearDown db
1107−
1108− it "update() - throw ReadOnlyError after update on ReadOnly transaction" do
1109− { db } <- setup
1110− { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1111− , indexParams: IDBObjectStore.defaultParameters
1112− , keyPath: []
1113− , values:
1114− [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1115− ]
1116− , onUpgradeNeeded: Nothing
1117− }
1118− let
1119− cb vdone =
1120− { onComplete: launchAff' do
1121− fail $ "shouldn't complete"
1122−
1123− , onError: \error -> launchAff' do
1124− fail $ "unexpected error: " <> show error
1125
400
1126− , onSuccess: \cursor -> launchAff' do
401+ db <- IDBFactory.open dbName Nothing
1127− res <- attempt $ IDBCursor.update cursor "patate"
402+ { onUpgradeNeeded : Just callback
1128− case res of
403+ , onBlocked : Nothing
1129− Left err -> do
1130− name err `shouldEqual` "ReadOnlyError"
1131− AVar.put unit vdone
1132− Right _ ->
1133− fail $ "expected ReadOnlyError"
1134− }
404+ }
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)
1139− AVar.take vdone
1140− tearDown db
405+ tearDown dbName dbVersion db
1141
406
yarn.lockdeleted−81
@@ -1,81 +0,0 @@
1−# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2−# yarn lockfile v1
3−
4−
5−base64-arraybuffer-es6@^0.7.0:
6− version "0.7.0"
7− resolved "https://registry.yarnpkg.com/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.7.0.tgz#dbe1e6c87b1bf1ca2875904461a7de40f21abc86"
8− integrity sha512-ESyU/U1CFZDJUdr+neHRhNozeCv72Y7Vm0m1DCbjX3KBjT6eYocvAJlSk6+8+HkVwXlT1FNxhGW6q3UKAlCvvw==
9−
10−domexception@^1.0.1:
11− version "1.0.1"
12− resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
13− integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
14− dependencies:
15− webidl-conversions "^4.0.2"
16−
17−fake-indexeddb@^4.0.1:
18− version "4.0.1"
19− resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-4.0.1.tgz#09bb2468e21d0832b2177e894765fb109edac8fb"
20− integrity sha512-hFRyPmvEZILYgdcLBxVdHLik4Tj3gDTu/g7s9ZDOiU3sTNiGx+vEu1ri/AMsFJUZ/1sdRbAVrEcKndh3sViBcA==
21− dependencies:
22− realistic-structured-clone "^3.0.0"
23−
24−lodash@^4.7.0:
25− version "4.17.21"
26− resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
27− integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
28−
29−punycode@^2.1.1:
30− version "2.3.0"
31− resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
32− integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
33−
34−realistic-structured-clone@^3.0.0:
35− version "3.0.0"
36− resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-3.0.0.tgz#7b518049ce2dad41ac32b421cd297075b00e3e35"
37− integrity sha512-rOjh4nuWkAqf9PWu6JVpOWD4ndI+JHfgiZeMmujYcPi+fvILUu7g6l26TC1K5aBIp34nV+jE1cDO75EKOfHC5Q==
38− dependencies:
39− domexception "^1.0.1"
40− typeson "^6.1.0"
41− typeson-registry "^1.0.0-alpha.20"
42−
43−tr46@^2.1.0:
44− version "2.1.0"
45− resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
46− integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
47− dependencies:
48− punycode "^2.1.1"
49−
50−typeson-registry@^1.0.0-alpha.20:
51− version "1.0.0-alpha.39"
52− resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz#9e0f5aabd5eebfcffd65a796487541196f4b1211"
53− integrity sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==
54− dependencies:
55− base64-arraybuffer-es6 "^0.7.0"
56− typeson "^6.0.0"
57− whatwg-url "^8.4.0"
58−
59−typeson@^6.0.0, typeson@^6.1.0:
60− version "6.1.0"
61− resolved "https://registry.yarnpkg.com/typeson/-/typeson-6.1.0.tgz#5b2a53705a5f58ff4d6f82f965917cabd0d7448b"
62− integrity sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==
63−
64−webidl-conversions@^4.0.2:
65− version "4.0.2"
66− resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
67− integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
68−
69−webidl-conversions@^6.1.0:
70− version "6.1.0"
71− resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
72− integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
73−
74−whatwg-url@^8.4.0:
75− version "8.7.0"
76− resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
77− integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
78− dependencies:
79− lodash "^4.7.0"
80− tr46 "^2.1.0"
81− webidl-conversions "^6.1.0"