git.iko.soy/purescript-indexed-DB
on master help sign in
.gitignore+2
since splitsnapshots
unifiedsplit
@@ -77,3 +77,5 @@ releases
77.purs*
77.purs*
78.psa*
78.psa*
79dist
79dist
80+.spago
81+test.js
README.md+64−10
@@ -1,13 +1,40 @@
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+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)
2=====
2=====
3
3
4This package offers complete bindings and type-safety upon the [IndexedDB API](https://w3c.github.io/IndexedDB).
4This package offers complete bindings and type-safety upon the [IndexedDB API](https://w3c.github.io/IndexedDB).
5
5
6## Overview
6## Overview
7
7
8+The `IDBCore` and `IDBFactory` are the two entry points required to create and connect to an
9+indexed database. From there, modules are divided such that each of them covers a specific IDB
10+interface.
11+
12+They are designed to be used as qualified imports such that each method gets prefixed with a
13+menaingful namespace (e.g `IDBIndex.get`, `IDBObjectStore.openCursor` ...)
14+
15+Here's a quick example of what it look likes.
8```purescript
16```purescript
17+module Main where
18+
19+import Prelude
20+
21+import Control.Monad.Aff (Aff, launchAff_)
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+
27+import Database.IndexedDB.Core
28+import Database.IndexedDB.IDBFactory as IDBFactory
29+import Database.IndexedDB.IDBDatabase as IDBDatabase
30+import Database.IndexedDB.IDBObjectStore as IDBObjectStore
31+import Database.IndexedDB.IDBIndex as IDBIndex
32+import Database.IndexedDB.IDBTransaction as IDBTransaction
33+import Database.IndexedDB.IDBKeyRange as IDBKeyRange
34+
35+
9main :: Eff (idb :: IDB, exception :: EXCEPTION, console :: CONSOLE) Unit
36main :: Eff (idb :: IDB, exception :: EXCEPTION, console :: CONSOLE) Unit
10−main = launchAff' do
37+main = launchAff_ do
11 db <- IDBFactory.open "db" Nothing { onBlocked : Nothing
38 db <- IDBFactory.open "db" Nothing { onBlocked : Nothing
12 , onUpgradeNeeded : Just onUpgradeNeeded
39 , onUpgradeNeeded : Just onUpgradeNeeded
13 }
40 }
@@ -18,23 +45,50 @@ main = launchAff' do
18 log $ maybe "not found" id val
45 log $ maybe "not found" id val
19
46
20
47
21−onUpgradeNeeded :: forall e. Database -> Transaction -> Eff (idb :: IDB, exception :: EXCEPTION | e) Unit
48+onUpgradeNeeded :: forall e. Database -> Transaction -> { oldVersion :: Int } -> Eff (idb :: IDB, exception :: EXCEPTION | e) Unit
22−onUpgradeNeeded db _ = launchAff' do
49+onUpgradeNeeded db _ _ = launchAff_ do
23− store <- IDBDatabase.createObjectStore db "store" IDBObjectStore.defaultParameters
50+ store <- IDBDatabase.createObjectStore db "store" IDBDatabase.defaultParameters
24 _ <- IDBObjectStore.add store "patate" (Just 1)
51 _ <- IDBObjectStore.add store "patate" (Just 1)
25 _ <- IDBObjectStore.add store { property: 42 } (Just 2)
52 _ <- IDBObjectStore.add store { property: 42 } (Just 2)
26− _ <- IDBObjectStore.createIndex store "index" ["property"] IDBIndex.defaultParameters
53+ _ <- IDBObjectStore.createIndex store "index" ["property"] IDBObjectStore.defaultParameters
27 pure unit
54 pure unit
28```
55```
29
56
57+## Notes
58+
59+### Errors
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+
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+
30## Changelog
71## Changelog
31
72
32−- Release incoming
73+#### v3.0.0
74+
75+- callback to `onUpgradeNeeded` event now provide a record with the database old version.
76+
77+#### v2.0.0
78+
79+- review interface implementation (use of opaque classes to improve readability without compromising
80+ the reusability). The API doesn't really change from a user perspective though.
81+
82+- make the Key more opaque (by having an IDBKey instance for Foreign types)
83+
84+- Upgrade purescript-exceptions to 3.1.0 and leverage the new `name` accessor
85+
33
86
34−#### TODO
87+#### v1.0.0
35
88
36−- Add support for `index.getAll` method
89+- [Indexed Database API 2.0](https://w3c.github.io/IndexedDB/) totally covered apart from
37−- Complete the specifications with the [official tests list](https://github.com/w3c/web-platform-tests/blob/master/IndexedDB/README.md) provided by W3C
90+ - `index.getAll` method (and the associated one for the IDBObjectStore)
91+ - binary keys
38
92
39## Documentation
93## Documentation
40
94
bower.jsondeleted−38
@@ -1,38 +0,0 @@
1−{
2− "name": "purescript-indexeddb",
3− "description": "An API wrapper around IndexedDB",
4− "version": "1.0.0",
5− "authors": [
6− "Matthias Benkort <matthias.benkort@truqu.com>"
7− ],
8− "ignore": [
9− "**/.*",
10− "node_modules",
11− "bower_components",
12− "output",
13− "test",
14− "dist",
15− "releases",
16− "package.json",
17− "karma.conf.js",
18− "karma.browserstack.conf.js",
19− "deploy.sh"
20− ],
21− "license": "MIT",
22− "homepage": "https://github.com/truqu/purescript-indexeddb",
23− "repository": {
24− "type": "git",
25− "url": "git://github.com/KtorZ/purescript-ifrit.git"
26− },
27− "dependencies": {
28− "purescript-maybe": "^3.0.0",
29− "purescript-aff": "^3.1.0",
30− "purescript-datetime": "^3.2.0"
31− },
32− "devDependencies": {
33− "purescript-spec": "^1.0.0",
34− "purescript-psci-support": "^3.0.0",
35− "purescript-now": "^3.0.0",
36− "purescript-spec-mocha": "https://github.com/truqu/purescript-spec-mocha.git#0.5.0"
37− }
38−}
deploy.shdeleted−3
@@ -1,3 +0,0 @@
1−#!/bin/sh
2−
3−test -n "$TRAVIS_TAG" && ( yes | pulp publish --no-push )
index.jsnew file+4
@@ -0,0 +1,4 @@
1+import "fake-indexeddb/auto";
2+import * as Main from './output/Test.Main/index.js';
3+
4+Main.main();
karma.browserstack.conf.jsdeleted−91
@@ -1,91 +0,0 @@
1−module.exports = (config) => {
2− config.set({
3− browsers: [
4− 'FirefoxMAC',
5− 'ChromeMAC',
6− // 'SafariMAC',
7− 'OperaMAC',
8−
9− 'FirefoxWIN',
10− 'ChromeWIN',
11− 'OperaWIN',
12− ],
13− files: [
14− 'dist/karma/index.js',
15− ],
16− frameworks: [
17− 'mocha',
18− ],
19− plugins: [
20− 'karma-browserstack-launcher',
21− 'karma-mocha',
22− ],
23− reporters: [
24− 'dots',
25− 'BrowserStack',
26− ],
27− singleRun: true,
28− client: {
29− mocha: {
30− timeout: 10000,
31− },
32− },
33− browserStack: {
34− username: process.env.BROWSERSTACK_USERNAME,
35− accessKey: process.env.BROWSERSTACK_ACCESSKEY,
36− timeout: 1500,
37− captureTimeout: 500,
38− },
39− customLaunchers: {
40− FirefoxMAC: {
41− base: 'BrowserStack',
42− browser: 'Firefox',
43− browser_version: '51',
44− os: 'OS X',
45− os_version: 'Sierra',
46− },
47− ChromeMAC: {
48− base: 'BrowserStack',
49− browser: 'Chrome',
50− browser_version: '58',
51− os: 'OS X',
52− os_version: 'Sierra',
53− },
54− SafariMAC: {
55− base: 'BrowserStack',
56− browser: 'Safari',
57− browser_version: '10.1',
58− os: 'OS X',
59− os_version: 'Sierra',
60− },
61− OperaMAC: {
62− base: 'BrowserStack',
63− browser: 'Opera',
64− browser_version: '46',
65− os: 'OS X',
66− os_version: 'Sierra',
67− },
68− FirefoxWIN: {
69− base: 'BrowserStack',
70− browser: 'Firefox',
71− browser_version: '51',
72− os: 'WINDOWS',
73− os_version: '10',
74− },
75− ChromeWIN: {
76− base: 'BrowserStack',
77− browser: 'Chrome',
78− browser_version: '58',
79− os: 'WINDOWS',
80− os_version: '10',
81− },
82− OperaWIN: {
83− base: 'BrowserStack',
84− browser: 'Opera',
85− browser_version: '46',
86− os: 'WINDOWS',
87− os_version: '10',
88− },
89− },
90− });
91−};
karma.conf.jsdeleted−25
@@ -1,25 +0,0 @@
1−module.exports = config => {
2− config.set({
3− autoWatch: true,
4− singleRun: true,
5− browsers: ["Chrome"],
6− files: [
7− "dist/karma/index.js",
8− ],
9− frameworks: [
10− "mocha",
11− ],
12− plugins: [
13− "karma-chrome-launcher",
14− "karma-firefox-launcher",
15− "karma-spec-reporter",
16− "karma-mocha",
17− ],
18− reporters: ["spec"],
19− client: {
20− mocha: {
21− timeout: 10000
22− }
23− }
24− });
25−};
package.json+9−36
@@ -1,42 +1,15 @@
1{
1{
2− "name": "purescript-indexeddb",
2+ "name": "purescript-indexed-DB",
3 "version": "1.0.0",
3 "version": "1.0.0",
4− "description": "A wrapper around the IndexedDB API",
4+ "main": "index.js",
5+ "repository": "https://github.com/ilyakooo0/purescript-indexed-DB.git",
6+ "author": "iko <mail@iko.soy>",
7+ "license": "MIT",
5 "scripts": {
8 "scripts": {
6− "prepare:release": "mkdir -p releases/github && cp -r README.md LICENSE src bower.json releases/github",
9+ "test": "spago build && node index.js"
7− "test:build": "mkdir -p dist/karma && pulp browserify -j 4 --main \"Test.Main\" -I test --to dist/karma/index.js",
8− "test:run": "karma start karma.conf.js",
9− "test:run:browserstack": "karma start karma.browserstack.conf.js",
10− "test:browserstack": "npm run test:build && npm run test:run:browserstack",
11− "test": "npm run test:build && npm run test:run",
12− "start": "find . -type f -regex '.*\\(src\\|test\\).*' ! -regex '.*bower_components.*\\|.*node_modules.*|.*\\.sw.*' | entr -s 'npm run test -s'"
13− },
14− "dependencies": {},
15− "devDependencies": {
16− "bower": "1.8.0",
17− "eslint": "3.19.0",
18− "eslint-config-airbnb": "15.0.1",
19− "eslint-plugin-import": "2.5.0",
20− "eslint-plugin-jsx-a11y": "5.0.3",
21− "eslint-plugin-react": "7.1.0",
22− "karma": "1.7.0",
23− "karma-browserstack-launcher": "1.3.0",
24− "karma-chrome-launcher": "2.1.1",
25− "karma-firefox-launcher": "1.0.1",
26− "karma-mocha": "1.3.0",
27− "karma-spec-reporter": "0.0.31",
28− "mocha": "3.4.2",
29− "pulp": "11.0.0",
30− "purescript": "0.11.5"
31 },
10 },
32− "repository": {
11+ "dependencies": {
33− "type": "git",
12+ "fake-indexeddb": "^4.0.1"
34− "url": "git+https://github.com/Truqu/purescript-indexeddb.git"
35− },
36− "author": "Matthias Benkort <matthias.benkort@truqu.com>",
37− "license": "MIT",
38− "bugs": {
39− "url": "https://github.com/Truqu/purescript-indexeddb/issues"
40 },
13 },
41− "homepage": "https://github.com/Truqu/purescript-indexeddb#readme"
14+ "type": "module"
42}
15}
packages.dhallnew file+105
@@ -0,0 +1,105 @@
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.dhallnew file+42
@@ -0,0 +1,42 @@
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+6−6
@@ -3,7 +3,7 @@ const toArray = function toArray(xs) {
3};
3};
4
4
5
5
6−exports._showCursor = function _showCursor(cursor) {
6+export function _showCursor(cursor) {
7 return '(IDBCursor ' +
7 return '(IDBCursor ' +
8 '{ direction: ' + cursor.direction +
8 '{ direction: ' + cursor.direction +
9 ', key: ' + cursor.key +
9 ', key: ' + cursor.key +
@@ -11,7 +11,7 @@ exports._showCursor = function _showCursor(cursor) {
11 ' })';
11 ' })';
12};
12};
13
13
14−exports._showDatabase = function _showDatabase(db) {
14+export function _showDatabase(db) {
15 return '(IDBDatabase ' +
15 return '(IDBDatabase ' +
16 '{ name: ' + db.name +
16 '{ name: ' + db.name +
17 ', objectStoreNames: [' + toArray(db.objectStoreNames).join(', ') + ']' +
17 ', objectStoreNames: [' + toArray(db.objectStoreNames).join(', ') + ']' +
@@ -19,7 +19,7 @@ exports._showDatabase = function _showDatabase(db) {
19 ' })';
19 ' })';
20};
20};
21
21
22−exports._showIndex = function _showIndex(index) {
22+export function _showIndex(index) {
23 return '(IDBIndex ' +
23 return '(IDBIndex ' +
24 '{ name: ' + index.name +
24 '{ name: ' + index.name +
25 ', keyPath: ' + index.keyPath +
25 ', keyPath: ' + index.keyPath +
@@ -28,7 +28,7 @@ exports._showIndex = function _showIndex(index) {
28 ' })';
28 ' })';
29};
29};
30
30
31−exports._showKeyRange = function _showKeyRange(range) {
31+export function _showKeyRange(range) {
32 return '(IDBKeyRange ' +
32 return '(IDBKeyRange ' +
33 '{ lower: ' + range.lower +
33 '{ lower: ' + range.lower +
34 ', upper: ' + range.upper +
34 ', upper: ' + range.upper +
@@ -37,7 +37,7 @@ exports._showKeyRange = function _showKeyRange(range) {
37 ' })';
37 ' })';
38};
38};
39
39
40−exports._showObjectStore = function _showObjectStore(store) {
40+export function _showObjectStore(store) {
41 return '(IDBObjectStore ' +
41 return '(IDBObjectStore ' +
42 '{ autoIncrement: ' + store.autoIncrement +
42 '{ autoIncrement: ' + store.autoIncrement +
43 ', indexNames: [' + toArray(store.indexNames).join(', ') + ']' +
43 ', indexNames: [' + toArray(store.indexNames).join(', ') + ']' +
@@ -46,7 +46,7 @@ exports._showObjectStore = function _showObjectStore(store) {
46 ' })';
46 ' })';
47};
47};
48
48
49−exports._showTransaction = function _showTransaction(tx) {
49+export function _showTransaction(tx) {
50 return '(IDBTransaction ' +
50 return '(IDBTransaction ' +
51 '{ error: ' + tx.error +
51 '{ error: ' + tx.error +
52 ', mode: ' + tx.mode +
52 ', mode: ' + tx.mode +
src/Database/IndexedDB/Core.purs+143−95
@@ -1,39 +1,72 @@
1-- | The Core module gathers types used across the library and provides basic Show instances for
1-- | The Core module gathers types used across the library and provides basic Show instances for
2-- | those types.
2-- | those types.
3−-- |
4−-- | NOTE:
5−-- | Errors normally thrown by the IDB* interfaces are wrapped in the `Aff` Monad as `Error`
6−-- | where the `message` corresponds to the error's name (e.g. "InvalidStateError").
7−-- | Pattern matching can therefore be done on any error message to handle specific errors thrown
8−-- | by the API.
9−
10module Database.IndexedDB.Core
3module Database.IndexedDB.Core
11− ( class FromString, parse
4+ -- * Effects
5+ (
12− , IDB
6+ -- IDB
13− , CursorDirection(..)
7+
14− , CursorSource(..)
8+ -- * Types
15− , Database
9+ Database
16 , Index
10 , Index
17 , KeyCursor
11 , KeyCursor
18 , KeyRange
12 , KeyRange
19− , KeyPath
20 , ObjectStore
13 , ObjectStore
21 , Transaction
14 , Transaction
22− , TransactionMode(..)
23 , ValueCursor
15 , ValueCursor
16+ , CursorDirection(..)
17+ , CursorSource(..)
18+ , KeyPath
19+ , TransactionMode(..)
20+
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
24 , module Database.IndexedDB.IDBKey
31 , module Database.IndexedDB.IDBKey
25 ) where
32 ) where
26
33
27−import Prelude (class Show)
34+import Prelude (class Show)
28
35
29−import Control.Monad.Eff (kind Effect)
36+import Data.Maybe (Maybe(..))
30−import Data.Maybe (Maybe(..))
37+import Data.String.Read (class Read)
31
38
32import Database.IndexedDB.IDBKey
39import Database.IndexedDB.IDBKey
33
40
34−-- | IDB Effects, manifestation that something happened with the IndexedDB
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.
35−foreign import data IDB :: Effect
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
36
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
37
70
38-- | A cursor has a direction that determines whether it moves in monotonically
71-- | A cursor has a direction that determines whether it moves in monotonically
39-- | increasing or decreasing order of the record keys when iterated, and if it
72-- | increasing or decreasing order of the record keys when iterated, and if it
@@ -46,7 +79,6 @@ data CursorDirection
46 | Prev
79 | Prev
47 | PrevUnique
80 | PrevUnique
48
81
49−
50-- | If the source of a cursor is an object store, the effective object store of
82-- | If the source of a cursor is an object store, the effective object store of
51-- | the cursor is that object store and the effective key of the cursor is the
83-- | the cursor is that object store and the effective key of the cursor is the
52-- | cursor’s position. If the source of a cursor is an index, the effective object
84-- | cursor’s position. If the source of a cursor is an index, the effective object
@@ -56,17 +88,6 @@ data CursorSource
56 = ObjectStore ObjectStore
88 = ObjectStore ObjectStore
57 | Index Index
89 | Index Index
58
90
59−
60−-- | A transaction has a mode that determines which types of interactions can be performed
61−-- | upon that transaction. The mode is set when the transaction is created and remains
62−-- | fixed for the life of the transaction.
63−data TransactionMode
64− = ReadOnly -- ^ The transaction is only allowed to read data.
65− | ReadWrite -- ^ The transaction is allowed to read, modify and delete data from existing object stores
66− | 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.
67−
68−
69−
70-- | A key path is a list of strings that defines how to extract a key from a value.
91-- | A key path is a list of strings that defines how to extract a key from a value.
71-- | A valid key path is one of:
92-- | A valid key path is one of:
72-- |
93-- |
@@ -76,119 +97,146 @@ data TransactionMode
76-- | - A non-empty list containing only strings conforming to the above requirements.
97-- | - A non-empty list containing only strings conforming to the above requirements.
77type KeyPath = Array String
98type KeyPath = Array String
78
99
100+-- | A transaction has a mode that determines which types of interactions can be performed
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.
79
107
80−-- | Each origin has an associated set of databases. A database has zero or more object
108+--------------------
81−-- | stores which hold the data stored in the database.
109+-- Classes
82−foreign import data Database :: Type
110+--
83
111
84−-- | An index allows looking up records in an object store using properties of the values
112+-- | A concrete cursor not only shares IDBCursor properties, but also some
85−-- | in the object stores records.
113+-- | specific attributes (see KeyCursor or CursorWithValue).
86−foreign import data Index :: Type
114+class (IDBCursor cursor) <= IDBConcreteCursor cursor
87
115
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
88
120
89−-- | A cursor is used to iterate over a range of records in an index or an object store
121+-- | The IDBDatabase interface represents a connection to a database.
90−-- | in a specific direction. A KeyCursor doesn't hold any value.
122+class IDBDatabase db
91−foreign import data KeyCursor :: Type
92
123
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
93
128
94−-- | A key range is a continuous interval over some data type used for keys.
129+-- | The IDBKeyRange interface represents a key range.
95−foreign import data KeyRange :: Type
130+class IDBKeyRange range
96
131
132+-- | The IDBtransaction interface.
133+class IDBTransaction tx
97
134
98−-- | An object store is the primary storage mechanism for storing data in a database.
135+-- | The IDBObjectStore interface represents an object store handle.
99−foreign import data ObjectStore :: Type
136+class IDBObjectStore store
100
137
138+--------------------
139+-- INSTANCES
140+--
101
141
102−-- | A Transaction is used to interact with the data in a database.
142+instance idbCursorKeyCursor :: IDBCursor KeyCursor
103−-- | Whenever data is read or written to the database it is done by using a transaction.
104−foreign import data Transaction :: Type
105
143
144+instance idbCursorValueCursor :: IDBCursor ValueCursor
106
145
107−-- | A cursor is used to iterate over a range of records in an index or an object store
146+instance idbConcreteCursorKeyCursor :: IDBConcreteCursor KeyCursor
108−-- | in a specific direction. A ValueCursor also holds the value corresponding to matching key.
109−foreign import data ValueCursor :: Type
110
147
148+instance idbConcreteCursorValueCursor :: IDBConcreteCursor ValueCursor
111
149
112−-- | FromString represents enumerations that can be represented as Strings.
150+instance idbDatabaseDatabase :: IDBDatabase Database
113−class FromString a where
114− parse :: String -> Maybe a
115
151
152+instance idbIndexIndex :: IDBIndex Index
116
153
117−foreign import _showCursor :: forall cursor. cursor -> String
154+instance idbIndexObjectStore :: IDBIndex ObjectStore
118−instance showKeyCursor :: Show KeyCursor where
119− show = _showCursor
120
155
156+instance idbKeyRangeKeyRange :: IDBKeyRange KeyRange
121
157
122−instance showValueCursor :: Show ValueCursor where
158+instance idbObjectStoreObjectStore :: IDBObjectStore ObjectStore
123− show = _showCursor
124
159
160+instance idbTransactionTransaction :: IDBTransaction Transaction
125
161
126−foreign import _showDatabase
127− :: Database
128− -> String
129−instance showDatabase :: Show Database where
162+instance showKeyCursor :: Show KeyCursor where
130− show = _showDatabase
163+ show = _showCursor
131
164
165+instance showValueCursor :: Show ValueCursor where
166+ show = _showCursor
132
167
133−foreign import _showIndex
134− :: Index
135− -> String
136instance showIndex :: Show Index where
168instance showIndex :: Show Index where
137 show = _showIndex
169 show = _showIndex
138
170
139−
140−foreign import _showKeyRange
141− :: KeyRange
142− -> String
143instance showKeyRange :: Show KeyRange where
171instance showKeyRange :: Show KeyRange where
144 show = _showKeyRange
172 show = _showKeyRange
145
173
146−
147−foreign import _showObjectStore
148− :: ObjectStore
149− -> String
150instance showObjectStore :: Show ObjectStore where
174instance showObjectStore :: Show ObjectStore where
151 show = _showObjectStore
175 show = _showObjectStore
152
176
153−
154−foreign import _showTransaction
155− :: Transaction
156− -> String
157instance showTransaction :: Show Transaction where
177instance showTransaction :: Show Transaction where
158 show = _showTransaction
178 show = _showTransaction
159
179
180+instance showDatabase :: Show Database where
181+ show = _showDatabase
160
182
161instance showCursorDirection :: Show CursorDirection where
183instance showCursorDirection :: Show CursorDirection where
162 show x =
184 show x =
163 case x of
185 case x of
164− Next -> "next"
186+ Next -> "next"
165 NextUnique -> "nextunique"
187 NextUnique -> "nextunique"
166− Prev -> "prev"
188+ Prev -> "prev"
167 PrevUnique -> "prevunique"
189 PrevUnique -> "prevunique"
168
190
169−
170instance showTransactionMode :: Show TransactionMode where
191instance showTransactionMode :: Show TransactionMode where
171 show x =
192 show x =
172 case x of
193 case x of
173− ReadOnly -> "readonly"
194+ ReadOnly -> "readonly"
174− ReadWrite -> "readwrite"
195+ ReadWrite -> "readwrite"
175 VersionChange -> "versionchange"
196 VersionChange -> "versionchange"
176
197
177−
178−instance fromStringCursorDirection :: FromString CursorDirection where
198+instance readCursorDirection :: Read CursorDirection where
179− parse s =
199+ read s =
180 case s of
200 case s of
181− "next" -> Just Next
201+ "next" -> Just Next
182 "nextunique" -> Just NextUnique
202 "nextunique" -> Just NextUnique
183− "prev" -> Just Prev
203+ "prev" -> Just Prev
184 "prevunique" -> Just PrevUnique
204 "prevunique" -> Just PrevUnique
185− _ -> Nothing
205+ _ -> Nothing
186−
187
206
188−instance fromStringTransactionMode :: FromString TransactionMode where
207+instance readTransactionMode :: Read TransactionMode where
189− parse s =
208+ read s =
190 case s of
209 case s of
191− "readonly" -> Just ReadOnly
210+ "readonly" -> Just ReadOnly
192− "readwrite" -> Just ReadWrite
211+ "readwrite" -> Just ReadWrite
193 "versionchange" -> Just VersionChange
212 "versionchange" -> Just VersionChange
194− _ -> Nothing
213+ _ -> 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+63−27
@@ -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(new Error(e.target.error.name));
3+ cb(e.target.error);
4 };
4 };
5};
5};
6
6
@@ -10,99 +10,135 @@ const successHandler = function successHandler(cb) {
10 };
10 };
11};
11};
12
12
13−
14−exports._advance = function _advance(cursor, count) {
13+export function _advance(cursor, count) {
15− return function aff(success, error) {
14+ return function aff(error, success) {
16 try {
15 try {
17 cursor.advance(count);
16 cursor.advance(count);
18 success();
17 success();
19 } catch (e) {
18 } catch (e) {
20− error(new Error(e.name));
19+ error(e);
21 }
20 }
21+
22+ return function canceler(_, cancelerError) {
23+ cancelerError(new Error("Can't cancel IDB Effects"));
24+ };
22 };
25 };
23};
26};
24
27
25−exports._continue = function _continue(cursor, key) {
28+export function _continue(cursor, key) {
26− return function aff(success, error) {
29+ return function aff(error, success) {
27 try {
30 try {
28 cursor.continue(key || undefined);
31 cursor.continue(key || undefined);
29 success();
32 success();
30 } catch (e) {
33 } catch (e) {
31− error(new Error(e.name));
34+ error(e);
32 }
35 }
36+
37+ return function canceler(_, cancelerError) {
38+ cancelerError(new Error("Can't cancel IDB Effects"));
39+ };
33 };
40 };
34};
41};
35
42
36−exports._continuePrimaryKey = function _continuePrimaryKey(cursor, key, primaryKey) {
43+export function _continuePrimaryKey(cursor, key, primaryKey) {
37− return function aff(success, error) {
44+ return function aff(error, success) {
38 try {
45 try {
39 cursor.continuePrimaryKey(key, primaryKey);
46 cursor.continuePrimaryKey(key, primaryKey);
40 success();
47 success();
41 } catch (e) {
48 } catch (e) {
42− error(new Error(e.name));
49+ error(e);
43 }
50 }
51+
52+ return function canceler(_, cancelerError) {
53+ cancelerError(new Error("Can't cancel IDB Effects"));
54+ };
44 };
55 };
45};
56};
46
57
47−exports._delete = function _delete(cursor) {
58+export function _delete(cursor) {
48− return function aff(success, error) {
59+ return function aff(error, success) {
49 try {
60 try {
50 const request = cursor.delete();
61 const request = cursor.delete();
51 request.onsuccess = successHandler(success);
62 request.onsuccess = successHandler(success);
52 request.onerror = errorHandler(error);
63 request.onerror = errorHandler(error);
53 } catch (e) {
64 } catch (e) {
54− error(new Error(e.name));
65+ error(e);
55 }
66 }
67+
68+ return function canceler(_, cancelerError) {
69+ cancelerError(new Error("Can't cancel IDB Effects"));
70+ };
56 };
71 };
57};
72};
58
73
59−exports._direction = function _direction(fromString, cursor) {
74+export function _direction(fromString, cursor) {
60 return fromString(cursor.direction);
75 return fromString(cursor.direction);
61};
76};
62
77
63−exports._key = function _key(cursor) {
78+export function _key(cursor) {
64− return function aff(success, error) {
79+ return function aff(error, success) {
65 try {
80 try {
66 success(cursor.key);
81 success(cursor.key);
67 } catch (e) {
82 } catch (e) {
68− error(new Error(e.name));
83+ error(e);
69 }
84 }
85+
86+ return function canceler(_, cancelerError) {
87+ cancelerError(new Error("Can't cancel IDB Effects"));
88+ };
70 };
89 };
71};
90};
72
91
73−exports._primaryKey = function _primaryKey(cursor) {
92+export function _primaryKey(cursor) {
74− return function aff(success, error) {
93+ return function aff(error, success) {
75 try {
94 try {
76 success(cursor.primaryKey);
95 success(cursor.primaryKey);
77 } catch (e) {
96 } catch (e) {
78− error(new Error(e.name));
97+ error(e);
79 }
98 }
99+
100+ return function canceler(_, cancelerError) {
101+ cancelerError(new Error("Can't cancel IDB Effects"));
102+ };
80 };
103 };
81};
104};
82
105
83−exports._source = function _source(IDBObjectStore, IDBIndex, cursor) {
106+export function _source(IDBObjectStore, IDBIndex, cursor) {
84 switch (cursor.source.constructor.name) {
107 switch (cursor.source.constructor.name) {
85 case 'IDBIndex':
108 case 'IDBIndex':
86 return IDBIndex(cursor.source);
109 return IDBIndex(cursor.source);
87 case 'IDBObjectStore':
110 case 'IDBObjectStore':
88 return IDBObjectStore(cursor.source);
111 return IDBObjectStore(cursor.source);
89 default:
112 default:
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,
90− throw new Error('UnexpectedCursorSource');
120+ value: 'UnexpectedCursorSource',
121+ },
122+ });
91 }
123 }
92};
124};
93
125
94−exports._update = function _update(cursor, value) {
126+export function _update(cursor, value) {
95− return function aff(success, error) {
127+ return function aff(error, success) {
96 try {
128 try {
97 const request = cursor.update(value);
129 const request = cursor.update(value);
98 request.onsuccess = successHandler(success);
130 request.onsuccess = successHandler(success);
99 request.onerror = errorHandler(error);
131 request.onerror = errorHandler(error);
100 } catch (e) {
132 } catch (e) {
101− error(new Error(e.name));
133+ error(e);
102 }
134 }
135+
136+ return function canceler(_, cancelerError) {
137+ cancelerError(new Error("Can't cancel IDB Effects"));
138+ };
103 };
139 };
104};
140};
105
141
106−exports._value = function _value(cursor) {
142+export function _value(cursor) {
107 return cursor.value;
143 return cursor.value;
108};
144};
src/Database/IndexedDB/IDBCursor.purs+111−162
@@ -1,237 +1,186 @@
1-- | A cursor is used to iterate over a range of records in an index or
1-- | A cursor is used to iterate over a range of records in an index or
2-- | an object store in a specific direction.
2-- | an object store in a specific direction.
3module Database.IndexedDB.IDBCursor
3module Database.IndexedDB.IDBCursor
4+ -- * Interface
5+ ( advance
6+ , continue
4− ( class IDBCursor, advance, continue, continuePrimaryKey, delete, update
7+ , continuePrimaryKey
8+ , delete
9+ , update
10+
11+ -- * Attributes
5 , direction
12 , direction
6 , key
13 , key
7 , primaryKey
14 , primaryKey
8 , source
15 , source
9− , direction'
10− , key'
11− , primaryKey'
12− , source'
13 , value
16 , value
14 ) where
17 ) where
15
18
16−import Prelude (Unit, ($), (>>>), map)
17−
18−import Control.Monad.Aff (Aff)
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−
25import Database.IndexedDB.Core
19import Database.IndexedDB.Core
26−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key(..), toKey, extractForeign)
27
20
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)
28
31
29--------------------
32--------------------
30-- INTERFACES
33-- INTERFACES
31--
34--
32−-- | Cursor objects implement the IDBCursor interface.
33−-- | There is only ever one IDBCursor instance representing a given cursor.
34−-- | There is no limit on how many cursors can be used at the same time.
35−class IDBCursor cursor where
36− -- | Advances the cursor through the next count records in range.
37− advance
38− :: forall e
39− . cursor
40− -> Int
41− -> Aff (idb :: IDB | e) Unit
42−
43− -- | Advances the cursor to the next record in range matching or after key.
44− continue
45− :: forall e k. (IDBKey k)
46− => cursor
47− -> Maybe k
48− -> Aff (idb :: IDB | e) Unit
49−
50− -- | 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.
51− continuePrimaryKey
52− :: forall e k. (IDBKey k)
53− => cursor
54− -> k
55− -> k
56− -> Aff (idb :: IDB | e) Unit
57−
58− -- | Delete the record pointed at by the cursor with a new value.
59− delete
60− :: forall e
61− . cursor
62− -> Aff (idb :: IDB | e) Unit
63−
64− -- | Update the record pointed at by the cursor with a new value.
65− -- |
66− -- | Throws a "DataError" DOMException if the effective object store uses
67− -- | in-line keys and the key would have changed.
68− update
69− :: forall val e
70− . cursor
71− -> val
72− -> Aff (idb :: IDB | e) Key
73
35
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
74
90
75--------------------
91--------------------
76-- ATTRIBUTES
92-- ATTRIBUTES
77--
93--
78−-- | Returns the direction (Next|NextUnique|Prev|PrevUnique) of the cursor.
79−direction'
80− :: KeyCursor
81− -> CursorDirection
82−direction' =
83− Fn.runFn2 _direction (parse >>> toNullable)
84−
85−
86−-- | Returns the key of the cursor. Throws a "InvalidStateError" DOMException
87−-- | if the cursor is advancing or is finished.
88−key'
89− :: forall e
90− . KeyCursor
91− -> Aff (idb :: IDB | e) Key
92−key' =
93− _key >>> map Key
94−
95−
96−-- | Returns the effective key of the cursor. Throws a "InvalidStateError" DOMException
97−-- | if the cursor is advancing or is finished.
98−primaryKey'
99− :: forall e
100− . KeyCursor
101− -> Aff (idb :: IDB | e) Key
102−primaryKey' =
103− _primaryKey >>> map Key
104−
105−
106−-- | Returns the IDBObjectStore or IDBIndex the cursor was opened from.
107−source'
108− :: KeyCursor
109− -> CursorSource
110−source' =
111− Fn.runFn3 _source ObjectStore Index
112−
113−
114−-- NOTE: Polymorphism not used here cause *we want* those methods to be distincs for
115−-- the concrete types mostly for consistency with the Database.IndexedDB.IDBIndex module
116−-- where the IDBIndex interfaces is shared by Index and ObjectStore, but attributes of
117−-- respective concrete types aren't shared.
118−
119
94
120-- | Returns the direction (Next|NextUnique|Prev|PrevUnique) of the cursor.
95-- | Returns the direction (Next|NextUnique|Prev|PrevUnique) of the cursor.
121direction
96direction
122− :: ValueCursor
97+ :: forall cursor
98+ . (IDBConcreteCursor cursor)
99+ => cursor
123 -> CursorDirection
100 -> CursorDirection
124direction =
101direction =
125− Fn.runFn2 _direction (parse >>> toNullable)
102+ Fn.runFn2 _direction (read >>> toNullable)
126−
127
103
128-- | Returns the key of the cursor. Throws a "InvalidStateError" DOMException
104-- | Returns the key of the cursor. Throws a "InvalidStateError" DOMException
129-- | if the cursor is advancing or is finished.
105-- | if the cursor is advancing or is finished.
130key
106key
131− :: forall e
107+ :: forall cursor
132− . ValueCursor
108+ . (IDBConcreteCursor cursor)
109+ => cursor
133− -> Aff (idb :: IDB | e) Key
110+ -> Aff Key
134key =
111key =
135− _key >>> map Key
112+ map toKey <<< fromEffectFnAff <<< _key
136−
137
113
138-- | Returns the effective key of the cursor. Throws a "InvalidStateError" DOMException
114-- | Returns the effective key of the cursor. Throws a "InvalidStateError" DOMException
139-- | if the cursor is advancing or is finished.
115-- | if the cursor is advancing or is finished.
140primaryKey
116primaryKey
141− :: forall e
117+ :: forall cursor
142− . ValueCursor
118+ . (IDBConcreteCursor cursor)
119+ => cursor
143− -> Aff (idb :: IDB | e) Key
120+ -> Aff Key
144primaryKey =
121primaryKey =
145− _primaryKey >>> map Key
122+ map toKey <<< fromEffectFnAff <<< _primaryKey
146−
147
123
148-- | Returns the IDBObjectStore or IDBIndex the cursor was opened from.
124-- | Returns the IDBObjectStore or IDBIndex the cursor was opened from.
149source
125source
150− :: ValueCursor
126+ :: forall cursor
127+ . (IDBConcreteCursor cursor)
128+ => cursor
151 -> CursorSource
129 -> CursorSource
152source =
130source =
153 Fn.runFn3 _source ObjectStore Index
131 Fn.runFn3 _source ObjectStore Index
154
132
155−
156value
133value
157 :: forall val
134 :: forall val
158− . ValueCursor
135+ . ValueCursor
159 -> val
136 -> val
160value =
137value =
161 _value >>> unsafeFromForeign
138 _value >>> unsafeFromForeign
162
139
163−
164−--------------------
165−-- INSTANCES
166−--
167−instance keyCursorKeyCursor :: IDBCursor KeyCursor where
168− advance = Fn.runFn2 _advance
169− continue c mk = Fn.runFn2 _continue c (toNullable $ map (toKey >>> extractForeign) mk)
170− continuePrimaryKey c k1 k2 = Fn.runFn3 _continuePrimaryKey c (extractForeign $ toKey k1) (extractForeign $ toKey k2)
171− delete = _delete
172− update c = toForeign >>> Fn.runFn2 _update c >>> map Key
173−
174−
175−instance valueCursorKeyCursor :: IDBCursor ValueCursor where
176− advance = Fn.runFn2 _advance
177− continue c mk = Fn.runFn2 _continue c (toNullable $ map (toKey >>> extractForeign) mk)
178− continuePrimaryKey c k1 k2 = Fn.runFn3 _continuePrimaryKey c (extractForeign $ toKey k1) (extractForeign $ toKey k2)
179− delete = _delete
180− update c = toForeign >>> Fn.runFn2 _update c >>> map Key
181−
182−
183--------------------
140--------------------
184-- FFI
141-- FFI
185--
142--
186−foreign import _advance
187− :: forall cursor e
188− . Fn2 cursor Int (Aff (idb :: IDB | e) Unit)
189
143
144+foreign import _advance
145+ :: forall cursor
146+ . Fn2 cursor Int (EffectFnAff Unit)
190
147
191foreign import _continue
148foreign import _continue
192− :: forall cursor e
149+ :: forall cursor
193− . Fn2 cursor (Nullable Foreign) (Aff (idb :: IDB | e) Unit)
150+ . Fn2 cursor (Nullable Foreign) (EffectFnAff Unit)
194−
195
151
196foreign import _continuePrimaryKey
152foreign import _continuePrimaryKey
197− :: forall cursor e
153+ :: forall cursor
198− . Fn3 cursor Foreign Foreign (Aff (idb :: IDB | e) Unit)
154+ . Fn3 cursor Foreign Foreign (EffectFnAff Unit)
199−
200
155
201foreign import _delete
156foreign import _delete
202− :: forall cursor e
157+ :: forall cursor
203− . cursor
158+ . cursor
204− -> (Aff (idb :: IDB | e) Unit)
159+ -> (EffectFnAff Unit)
205−
206
160
207foreign import _direction
161foreign import _direction
208 :: forall cursor
162 :: forall cursor
209− . Fn2 (String -> Nullable CursorDirection) cursor CursorDirection
163+ . Fn2 (String -> Nullable CursorDirection) cursor CursorDirection
210−
211
164
212foreign import _key
165foreign import _key
213− :: forall cursor e
166+ :: forall cursor
214− . cursor
167+ . cursor
215− -> Aff (idb :: IDB | e) Foreign
168+ -> EffectFnAff Key
216−
217
169
218foreign import _primaryKey
170foreign import _primaryKey
219− :: forall cursor e
171+ :: forall cursor
220− . cursor
172+ . cursor
221− -> Aff (idb :: IDB | e) Foreign
173+ -> EffectFnAff Key
222−
223
174
224foreign import _source
175foreign import _source
225 :: forall cursor
176 :: forall cursor
226− . Fn3 (ObjectStore -> CursorSource) (Index -> CursorSource) cursor CursorSource
177+ . Fn3 (ObjectStore -> CursorSource) (Index -> CursorSource) cursor CursorSource
227−
228
178
229foreign import _update
179foreign import _update
230− :: forall cursor e
180+ :: forall cursor
231− . Fn2 cursor Foreign (Aff (idb :: IDB | e) Foreign)
181+ . Fn2 cursor Foreign (EffectFnAff Foreign)
232−
233
182
234foreign import _value
183foreign import _value
235 :: forall cursor val
184 :: forall cursor val
236− . cursor
185+ . cursor
237 -> val
186 -> val
src/Database/IndexedDB/IDBDatabase.js+62−28
@@ -1,21 +1,25 @@
1−const $Core = require('Database.IndexedDB.Core/foreign');
1+const toArray = function toArray(xs) {
2−
2+ return Array.prototype.slice.apply(xs);
3−const toArray = $Core.toArray;
3+};
4
4
5
5
6−exports._close = function _close(db) {
6+export function _close(db) {
7− return function aff(success, error) {
7+ return function aff(error, success) {
8 try {
8 try {
9 db.close();
9 db.close();
10 success();
10 success();
11 } catch (e) {
11 } catch (e) {
12− error(new Error(e.name));
12+ error(e);
13 }
13 }
14+
15+ return function canceler(_, cancelerError) {
16+ cancelerError(new Error("Can't cancel IDB Effects"));
17+ };
14 };
18 };
15};
19};
16
20
17−exports._createObjectStore = function _createObjectStore(db, name, opts) {
21+export function _createObjectStore(db, name, opts) {
18− return function aff(success, error) {
22+ return function aff(error, success) {
19 var keyPath;
23 var keyPath;
20
24
21 try {
25 try {
@@ -39,77 +43,107 @@ exports._createObjectStore = function _createObjectStore(db, name, opts) {
39 });
43 });
40 success(store);
44 success(store);
41 } catch (e) {
45 } catch (e) {
42− error(new Error(e.name));
46+ error(e);
43 }
47 }
48+
49+ return function canceler(_, cancelerError) {
50+ cancelerError(new Error("Can't cancel IDB Effects"));
51+ };
44 };
52 };
45};
53};
46
54
47−exports._deleteObjectStore = function _deleteObjectStore(db, name) {
55+export function _deleteObjectStore(db, name) {
48− return function aff(success, error) {
56+ return function aff(error, success) {
49 try {
57 try {
50 db.deleteObjectStore(name);
58 db.deleteObjectStore(name);
51 success();
59 success();
52 } catch (e) {
60 } catch (e) {
53− error(new Error(e.name));
61+ error(e);
54 }
62 }
63+
64+ return function canceler(_, cancelerError) {
65+ cancelerError(new Error("Can't cancel IDB Effects"));
66+ };
55 };
67 };
56};
68};
57
69
58−exports._name = function _name(db) {
70+export function _name(db) {
59 return db.name;
71 return db.name;
60};
72};
61
73
62−exports._objectStoreNames = function _objectStoreNames(db) {
74+export function _objectStoreNames(db) {
63 return toArray(db.objectStoreNames);
75 return toArray(db.objectStoreNames);
64};
76};
65
77
66−exports._onAbort = function _onAbort(db, f) {
78+export function _onAbort(db, f) {
67− return function aff(success) {
79+ return function aff(error, success) {
68 db.onabort = function onabort() {
80 db.onabort = function onabort() {
69 f();
81 f();
70 };
82 };
71 success();
83 success();
84+
85+ return function canceler(_, cancelerError) {
86+ cancelerError(new Error("Can't cancel IDB Effects"));
87+ };
72 };
88 };
73};
89};
74
90
75−exports._onClose = function _onClose(db, f) {
91+export function _onClose(db, f) {
76− return function aff(success) {
92+ return function aff(error, success) {
77 db.onclose = function onclose() {
93 db.onclose = function onclose() {
78 f();
94 f();
79 };
95 };
80 success();
96 success();
97+
98+ return function canceler(_, cancelerError) {
99+ cancelerError(new Error("Can't cancel IDB Effects"));
100+ };
81 };
101 };
82};
102};
83
103
84−exports._onError = function _onError(db, f) {
104+export function _onError(db, f) {
85− return function aff(success) {
105+ return function aff(error, success) {
86 db.onerror = function onerror(e) {
106 db.onerror = function onerror(e) {
87− f(new Error(e.target.error.name))();
107+ f(e.target.error)();
88 };
108 };
89 success();
109 success();
110+
111+ return function canceler(_, cancelerError) {
112+ cancelerError(new Error("Can't cancel IDB Effects"));
113+ };
90 };
114 };
91};
115};
92
116
93−exports._onVersionChange = function _onVersionChange(db, f) {
117+export function _onVersionChange(db, f) {
94− return function aff(success) {
118+ return function aff(error, success) {
95 db.onversionchange = function onversionchange(e) {
119 db.onversionchange = function onversionchange(e) {
96 f({ oldVersion: e.oldVersion, newVersion: e.newVersion })();
120 f({ oldVersion: e.oldVersion, newVersion: e.newVersion })();
97 };
121 };
98 success();
122 success();
123+
124+ return function canceler(_, cancelerError) {
125+ cancelerError(new Error("Can't cancel IDB Effects"));
126+ };
99 };
127 };
100};
128};
101
129
102−exports._transaction = function _transaction(db, stores, mode) {
130+export function _transaction(db, stores, mode) {
103− return function aff(success, error) {
131+ return function aff(error, success) {
132+ var transaction;
104 try {
133 try {
105− const transaction = db.transaction(stores, mode);
134+ transaction = db.transaction(stores, mode);
106 success(transaction);
135 success(transaction);
107 } catch (e) {
136 } catch (e) {
108− error(new Error(e.name));
137+ error(e);
109 }
138 }
139+
140+ return function canceler(_, cancelerError, cancelerSuccess) {
141+ transaction.abort();
142+ cancelerSuccess();
143+ };
110 };
144 };
111};
145};
112
146
113−exports._version = function _version(db) {
147+export function _version(db) {
114 return db.version;
148 return db.version;
115};
149};
src/Database/IndexedDB/IDBDatabase.purs+132−132
@@ -1,215 +1,215 @@
1-- | Each origin has an associated set of databases. A database has zero or more object
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.
2-- | stores which hold the data stored in the database.
3module Database.IndexedDB.IDBDatabase
3module Database.IndexedDB.IDBDatabase
4+ -- * Types
5+ ( StoreName
6+ , ObjectStoreParameters
7+ , defaultParameters
8+
9+ -- * Interface
10+ , close
4− ( class IDBDatabase, close, createObjectStore, deleteObjectStore, transaction
11+ , createObjectStore
5− , StoreName
12+ , deleteObjectStore
13+ , transaction
14+
15+ -- * Attributes
6 , name
16 , name
7 , objectStoreNames
17 , objectStoreNames
8 , version
18 , version
19+
20+ -- * Event handlers
9 , onAbort
21 , onAbort
10 , onClose
22 , onClose
11 , onError
23 , onError
12 , onVersionChange
24 , onVersionChange
13 ) where
25 ) where
14
26
15−import Prelude (Unit, show)
16−
17−import Control.Monad.Aff (Aff)
18−import Control.Monad.Eff (Eff)
19−import Control.Monad.Eff.Exception (Error)
20−import Data.Function.Uncurried as Fn
21−import Data.Function.Uncurried (Fn2, Fn3)
22−
23import Database.IndexedDB.Core
27import Database.IndexedDB.Core
24−import Database.IndexedDB.IDBObjectStore (IDBObjectStoreParameters)
25
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, (<<<), ($))
26
36
27--------------------
37--------------------
28−-- INTERFACE
38+-- TYPES
29--
39--
30−-- | The IDBDatabase interface represents a connection to a database.
31−class IDBDatabase db where
32− -- | Closes the connection once all running transactions have finished.
33− close
34− :: forall e
35− . db
36− -> Aff (idb :: IDB | e) Unit
37−
38− -- | Creates a new object store with the given name and options and returns a new IDBObjectStore.
39− -- |
40− -- | Throws a "InvalidStateError" DOMException if not called within an upgrade transaction
41− createObjectStore
42− :: forall e
43− . db
44− -> StoreName
45− -> IDBObjectStoreParameters
46− -> Aff (idb :: IDB | e) ObjectStore
47−
48− -- | Deletes the object store with the given name.
49− -- |
50− -- | Throws a "InvalidStateError" DOMException if not called within an upgrade transaction.
51− deleteObjectStore
52− :: forall e
53− . db
54− -> StoreName
55− -> Aff (idb :: IDB | e) ObjectStore
56−
57− -- | Returns a new transaction with the given mode (ReadOnly|ReadWrite)
58− -- | and scope which in the form of an array of object store names.
59− transaction
60− :: forall e
61− . db
62− -> Array StoreName
63− -> TransactionMode
64− -> Aff (idb :: IDB | e) Transaction
65−
66
40
67-- | Type alias for StoreName
41-- | Type alias for StoreName
68type StoreName = String
42type StoreName = String
69
43
44+-- | Options provided when creating an object store.
45+type ObjectStoreParameters =
46+ { keyPath :: KeyPath
47+ , autoIncrement :: Boolean
48+ }
49+
50+defaultParameters :: ObjectStoreParameters
51+defaultParameters =
52+ { keyPath: []
53+ , autoIncrement: false
54+ }
55+
56+--------------------
57+-- INTERFACE
58+--
59+
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')
70
105
71--------------------
106--------------------
72-- ATTRIBUTES
107-- ATTRIBUTES
73--
108--
109+
74-- | Returns the name of the database.
110-- | Returns the name of the database.
75name
111name
76− :: Database
112+ :: Database
77− -> String
113+ -> String
78name =
114name =
79 _name
115 _name
80
116
81−
82-- | Returns a list of the names of object stores in the database.
117-- | Returns a list of the names of object stores in the database.
83objectStoreNames
118objectStoreNames
84− :: Database
119+ :: Database
85− -> Array String
120+ -> Array String
86objectStoreNames =
121objectStoreNames =
87 _objectStoreNames
122 _objectStoreNames
88
123
89−
90-- | Returns the version of the database.
124-- | Returns the version of the database.
91version
125version
92− :: Database
126+ :: Database
93− -> Int
127+ -> Int
94version =
128version =
95 _version
129 _version
96
130
97−
98--------------------
131--------------------
99-- EVENT HANDLERS
132-- EVENT HANDLERS
100--
133--
101-- | Event handler for the `abort` event.
134-- | Event handler for the `abort` event.
102onAbort
135onAbort
103− :: forall e e'
104− . Database
136+ :: Database
105− -> Eff ( | e') Unit
137+ -> Effect Unit
106− -> Aff (idb :: IDB | e) Unit
138+ -> Aff Unit
107onAbort db f =
139onAbort db f =
108− Fn.runFn2 _onAbort db f
140+ fromEffectFnAff $ Fn.runFn2 _onAbort db f
109−
110
141
111-- | Event handler for the `close` event.
142-- | Event handler for the `close` event.
112onClose
143onClose
113− :: forall e e'
114− . Database
144+ :: Database
115− -> Eff ( | e') Unit
145+ -> Effect Unit
116− -> Aff (idb :: IDB | e) Unit
146+ -> Aff Unit
117onClose db f =
147onClose db f =
118− Fn.runFn2 _onClose db f
148+ fromEffectFnAff $ Fn.runFn2 _onClose db f
119−
120
149
121-- | Event handler for the `error` event.
150-- | Event handler for the `error` event.
122onError
151onError
123− :: forall e e'
124− . Database
152+ :: Database
125− -> (Error -> Eff ( | e') Unit)
153+ -> (Error -> Effect Unit)
126− -> Aff (idb :: IDB | e) Unit
154+ -> Aff Unit
127onError db f =
155onError db f =
128− Fn.runFn2 _onError db f
156+ fromEffectFnAff $ Fn.runFn2 _onError db f
129−
130
157
131-- | Event handler for the `versionchange` event.
158-- | Event handler for the `versionchange` event.
132onVersionChange
159onVersionChange
133− :: forall e e'
134− . Database
160+ :: Database
135− -> ({ oldVersion :: Int, newVersion :: Int }
161+ -> ( { oldVersion :: Int, newVersion :: Int }
136− -> Eff ( | e') Unit)
162+ -> Effect Unit
163+ )
137− -> Aff (idb :: IDB | e) Unit
164+ -> Aff Unit
138onVersionChange db f =
165onVersionChange db f =
139− Fn.runFn2 _onVersionChange db f
166+ fromEffectFnAff $ Fn.runFn2 _onVersionChange db f
140−
141−
142−--------------------
143−-- INSTANCES
144−--
145−instance idbDatabaseDatabase :: IDBDatabase Database where
146− close =
147− _close
148−
149− createObjectStore db name' opts =
150− Fn.runFn3 _createObjectStore db name' opts
151−
152− deleteObjectStore db name' =
153− Fn.runFn2 _deleteObjectStore db name'
154−
155− transaction db stores mode' =
156− Fn.runFn3 _transaction db stores (show mode')
157−
158
167
159--------------------
168--------------------
160-- FFI
169-- FFI
161--
170--
162−foreign import _close
163− :: forall db e
164− . db
165− -> Aff (idb :: IDB | e) Unit
166
171
172+foreign import _close
173+ :: forall db
174+ . db
175+ -> EffectFnAff Unit
167
176
168foreign import _createObjectStore
177foreign import _createObjectStore
169− :: forall db e
178+ :: forall db
170− . Fn3 db String { keyPath :: Array String, autoIncrement :: Boolean } (Aff (idb :: IDB | e) ObjectStore)
179+ . Fn3 db String { keyPath :: Array String, autoIncrement :: Boolean } (EffectFnAff ObjectStore)
171−
172
180
173foreign import _deleteObjectStore
181foreign import _deleteObjectStore
174− :: forall db e
182+ :: forall db
175− . Fn2 db String (Aff (idb :: IDB | e) ObjectStore)
183+ . Fn2 db String (EffectFnAff ObjectStore)
176−
177
184
178foreign import _name
185foreign import _name
179− :: Database
186+ :: Database
180− -> String
187+ -> String
181−
182
188
183foreign import _objectStoreNames
189foreign import _objectStoreNames
184− :: Database
190+ :: Database
185− -> Array String
191+ -> Array String
186−
187
192
188foreign import _onAbort
193foreign import _onAbort
189− :: forall db e e'
194+ :: forall db
190− . Fn2 db (Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
195+ . Fn2 db (Effect Unit) (EffectFnAff Unit)
191−
192
196
193foreign import _onClose
197foreign import _onClose
194− :: forall db e e'
198+ :: forall db
195− . Fn2 db (Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
199+ . Fn2 db (Effect Unit) (EffectFnAff Unit)
196−
197
200
198foreign import _onError
201foreign import _onError
199− :: forall db e e'
202+ :: forall db
200− . Fn2 db (Error -> Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
203+ . Fn2 db (Error -> Effect Unit) (EffectFnAff Unit)
201−
202
204
203foreign import _onVersionChange
205foreign import _onVersionChange
204− :: forall db e e'
206+ :: forall db
205− . Fn2 db ({ oldVersion :: Int, newVersion :: Int } -> Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
207+ . Fn2 db ({ oldVersion :: Int, newVersion :: Int } -> Effect Unit) (EffectFnAff Unit)
206−
207
208
208foreign import _transaction
209foreign import _transaction
209− :: forall db e
210+ :: forall db
210− . Fn3 db (Array String) String (Aff (idb :: IDB | e) Transaction)
211+ . Fn3 db (Array String) String (EffectFnAff Transaction)
211−
212
212
213foreign import _version
213foreign import _version
214− :: Database
214+ :: Database
215− -> Int
215+ -> Int
src/Database/IndexedDB/IDBFactory.js+21−8
@@ -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(new Error(e.target.error.name));
3+ cb(e.target.error);
4 };
4 };
5};
5};
6
6
@@ -14,9 +14,12 @@ const noOp2 = function noOp2() {
14 return noOp;
14 return noOp;
15};
15};
16
16
17+const noOp3 = function noOp3() {
18+ return noOp2;
19+};
17
20
18−exports._deleteDatabase = function _deleteDatabase(name) {
21+export function _deleteDatabase(name) {
19− return function aff(success, error) {
22+ return function aff(error, success) {
20 try {
23 try {
21 const request = indexedDB.deleteDatabase(name);
24 const request = indexedDB.deleteDatabase(name);
22
25
@@ -26,15 +29,19 @@ exports._deleteDatabase = function _deleteDatabase(name) {
26
29
27 request.onerror = errorHandler(error);
30 request.onerror = errorHandler(error);
28 } catch (e) {
31 } catch (e) {
29− error(new Error(e.name));
32+ error(e);
30 }
33 }
34+
35+ return function canceler(_, cancelerError) {
36+ cancelerError(new Error("Can't cancel IDB Effects"));
37+ };
31 };
38 };
32};
39};
33
40
34−exports._open = function _open(fromMaybe, name, mver, req) {
41+export function _open(fromMaybe, name, mver, req) {
35 const ver = fromMaybe(undefined)(mver);
42 const ver = fromMaybe(undefined)(mver);
36
43
37− return function aff(success, error) {
44+ return function aff(error, success) {
38 try {
45 try {
39 const request = indexedDB.open(name, ver);
46 const request = indexedDB.open(name, ver);
40 request.onsuccess = function onSuccess(e) {
47 request.onsuccess = function onSuccess(e) {
@@ -46,12 +53,18 @@ exports._open = function _open(fromMaybe, name, mver, req) {
46 };
53 };
47
54
48 request.onupgradeneeded = function onUpgradeNeeded(e) {
55 request.onupgradeneeded = function onUpgradeNeeded(e) {
56+ const meta = { oldVersion: e.oldVersion };
57+ // eslint-disable-next-line max-len
49− fromMaybe(noOp2)(req.onUpgradeNeeded)(e.target.result)(e.target.transaction)();
58+ fromMaybe(noOp3)(req.onUpgradeNeeded)(e.target.result)(e.target.transaction)(meta)();
50 };
59 };
51
60
52 request.onerror = errorHandler(error);
61 request.onerror = errorHandler(error);
53 } catch (e) {
62 } catch (e) {
54− error(new Error(e.name));
63+ error(e);
55 }
64 }
65+
66+ return function canceler(_, cancelerError) {
67+ cancelerError(new Error("Can't cancel IDB Effects"));
68+ };
56 };
69 };
57};
70};
src/Database/IndexedDB/IDBFactory.purs+36−32
@@ -1,47 +1,55 @@
1-- | Database objects are accessed through methods on the IDBFactory interface.
1-- | Database objects are accessed through methods on the IDBFactory interface.
2-- | A single object implementing this interface is present in the global scope
2-- | A single object implementing this interface is present in the global scope
3-- | of environments that support Indexed DB operations.
3-- | of environments that support Indexed DB operations.
4−module Database.IndexedDB.IDBFactory where
4+module Database.IndexedDB.IDBFactory
5+ -- * Types
6+ ( Callbacks
7+ , DatabaseName
8+ , Version
5
9
6−import Prelude (Unit)
10+ -- * Interface
7−
11+ , deleteDatabase
8−import Control.Monad.Aff (Aff)
12+ , open
9−import Control.Monad.Eff (Eff)
13+ ) where
10−import Data.Function.Uncurried as Fn
11−import Data.Function.Uncurried (Fn4)
12−import Data.Maybe (Maybe, fromMaybe)
13
14
14import Database.IndexedDB.Core
15import Database.IndexedDB.Core
15
16
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, ($), (<<<))
16
24
17--------------------
25--------------------
18−-- INTERFACE
26+-- TYPES
19--
27--
28+
20-- Type alias for binding listeners to an initial open action.
29-- Type alias for binding listeners to an initial open action.
21−type Callbacks e =
30+type Callbacks =
22− { onBlocked :: Maybe (Eff (| e) Unit)
31+ { onBlocked :: Maybe (Effect Unit)
23− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Eff (| e) Unit)
32+ , onUpgradeNeeded :: Maybe (Database -> Transaction -> { oldVersion :: Int } -> Effect Unit)
24 }
33 }
25
34
26−
27-- | Type alias for DatabaseName.
35-- | Type alias for DatabaseName.
28type DatabaseName = String
36type DatabaseName = String
29
37
30−
31-- | Type alias for Version.
38-- | Type alias for Version.
32type Version = Int
39type Version = Int
33
40
41+--------------------
42+-- INTERFACE
43+--
34
44
35-- | Attempts to delete the named database. If the database already exists
45-- | Attempts to delete the named database. If the database already exists
36-- | and there are open connections that don’t close in response to a
46-- | and there are open connections that don’t close in response to a
37-- | `versionchange` event, the request will be blocked until all they close.
47-- | `versionchange` event, the request will be blocked until all they close.
38deleteDatabase
48deleteDatabase
39− :: forall e
40− . DatabaseName
49+ :: DatabaseName
41− -> Aff (idb :: IDB | e) Int
50+ -> Aff Int
42deleteDatabase =
51deleteDatabase =
43− _deleteDatabase
52+ fromEffectFnAff <<< _deleteDatabase
44−
45
53
46-- | Attempts to open a connection to the named database with the specified version.
54-- | Attempts to open a connection to the named database with the specified version.
47-- | If the database already exists with a lower version and there are open connections
55-- | If the database already exists with a lower version and there are open connections
@@ -52,24 +60,20 @@ deleteDatabase =
52-- | When the version isn't provided (`Nothing`), attempts to open a connection to the
60-- | When the version isn't provided (`Nothing`), attempts to open a connection to the
53-- | named database with the current version, or 1 if it does not already exist.
61-- | named database with the current version, or 1 if it does not already exist.
54open
62open
55− :: forall e e'
56− . DatabaseName
63+ :: DatabaseName
57− -> Maybe Version
64+ -> Maybe Version
58− -> Callbacks e'
65+ -> Callbacks
59− -> Aff (idb :: IDB | e) Database
66+ -> Aff Database
60open name mver req =
67open name mver req =
61− Fn.runFn4 _open fromMaybe name mver req
68+ fromEffectFnAff $ Fn.runFn4 _open fromMaybe name mver req
62−
63
69
64--------------------
70--------------------
65-- FFI
71-- FFI
66--
72--
67foreign import _deleteDatabase
73foreign import _deleteDatabase
68− :: forall e
69− . String
74+ :: String
70− -> Aff (idb :: IDB | e) Int
75+ -> EffectFnAff Int
71−
72
76
73foreign import _open
77foreign import _open
74− :: forall a e e'
78+ :: forall a
75− . Fn4 (a -> Maybe a -> a) String (Maybe Int) (Callbacks e') (Aff (idb :: IDB | e) Database)
79+ . Fn4 (a -> Maybe a -> a) String (Maybe Int) (Callbacks) (EffectFnAff Database)
src/Database/IndexedDB/IDBIndex/Internal.js → src/Database/IndexedDB/IDBIndex.jsrenamed+52−28
@@ -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(new Error(e.target.error.name));
3+ cb(e.target.error);
4 };
4 };
5};
5};
6
6
@@ -11,7 +11,7 @@ const successHandler = function successHandler(cb) {
11};
11};
12
12
13
13
14−exports._keyPath = function _keyPath(index) {
14+export function _keyPath(index) {
15 const path = index.keyPath;
15 const path = index.keyPath;
16
16
17 if (Array.isArray(path)) {
17 if (Array.isArray(path)) {
@@ -25,43 +25,51 @@ exports._keyPath = function _keyPath(index) {
25 return [];
25 return [];
26};
26};
27
27
28−exports._multiEntry = function _multiEntry(index) {
28+export function _multiEntry(index) {
29 return index.multiEntry;
29 return index.multiEntry;
30};
30};
31
31
32−exports._name = function _name(index) {
32+export function _name(index) {
33 return index.name;
33 return index.name;
34};
34};
35
35
36−exports._objectStore = function _objectStore(index) {
36+export function _objectStore(index) {
37 return index.obectStore;
37 return index.obectStore;
38};
38};
39
39
40−exports._unique = function _unique(index) {
40+export function _unique(index) {
41 return index.unique;
41 return index.unique;
42};
42};
43
43
44−exports._count = function _count(index, query) {
44+export function _count(index, query) {
45− return function aff(success, error) {
45+ return function aff(error, success) {
46 try {
46 try {
47 const request = index.count(query);
47 const request = index.count(query);
48 request.onsuccess = successHandler(success);
48 request.onsuccess = successHandler(success);
49 request.onerror = errorHandler(error);
49 request.onerror = errorHandler(error);
50 } catch (e) {
50 } catch (e) {
51− error(new Error(e.name));
51+ error(e);
52 }
52 }
53+
54+ return function canceler(_, cancelerError) {
55+ cancelerError(new Error("Can't cancel IDB Effects"));
56+ };
53 };
57 };
54};
58};
55
59
56−exports._get = function _get(index, range) {
60+export function _get(index, range) {
57− return function aff(success, error) {
61+ return function aff(error, success) {
58 try {
62 try {
59 const request = index.get(range);
63 const request = index.get(range);
60 request.onsuccess = successHandler(success);
64 request.onsuccess = successHandler(success);
61 request.onerror = errorHandler(error);
65 request.onerror = errorHandler(error);
62 } catch (e) {
66 } catch (e) {
63− error(new Error(e.name));
67+ error(e);
64 }
68 }
69+
70+ return function canceler(_, cancelerError) {
71+ cancelerError(new Error("Can't cancel IDB Effects"));
72+ };
65 };
73 };
66};
74};
67
75
@@ -71,8 +79,8 @@ exports._get = function _get(index, range) {
71 *
79 *
72 * However, it may be doable to convert the result to some key / value structure with values of
80 * However, it may be doable to convert the result to some key / value structure with values of
73 * different types.
81 * different types.
74−exports._getAll = function _getAll(index, query, count) {
82+export function _getAll(index, query, count) {
75− return function aff(success, error) {
83+ return function aff(error, success) {
76 const request = index.getAll(query, count);
84 const request = index.getAll(query, count);
77 request.onsuccess = successHandler(success);
85 request.onsuccess = successHandler(success);
78 request.onerror = errorHandler(error);
86 request.onerror = errorHandler(error);
@@ -80,32 +88,40 @@ exports._getAll = function _getAll(index, query, count) {
80};
88};
81*/
89*/
82
90
83−exports._getAllKeys = function _getAllKeys(index, range, count) {
91+export function _getAllKeys(index, range, count) {
84− return function aff(success, error) {
92+ return function aff(error, success) {
85 try {
93 try {
86 const request = index.getAllKeys(range, count || undefined);
94 const request = index.getAllKeys(range, count || undefined);
87 request.onsuccess = successHandler(success);
95 request.onsuccess = successHandler(success);
88 request.onerror = errorHandler(error);
96 request.onerror = errorHandler(error);
89 } catch (e) {
97 } catch (e) {
90− error(new Error(e.name));
98+ error(e);
91 }
99 }
100+
101+ return function canceler(_, cancelerError) {
102+ cancelerError(new Error("Can't cancel IDB Effects"));
103+ };
92 };
104 };
93};
105};
94
106
95−exports._getKey = function _getKey(index, range) {
107+export function _getKey(index, range) {
96− return function aff(success, error) {
108+ return function aff(error, success) {
97 try {
109 try {
98 const request = index.getKey(range);
110 const request = index.getKey(range);
99 request.onsuccess = successHandler(success);
111 request.onsuccess = successHandler(success);
100 request.onerror = errorHandler(error);
112 request.onerror = errorHandler(error);
101 } catch (e) {
113 } catch (e) {
102− error(new Error(e.name));
114+ error(e);
103 }
115 }
116+
117+ return function canceler(_, cancelerError) {
118+ cancelerError(new Error("Can't cancel IDB Effects"));
119+ };
104 };
120 };
105};
121};
106
122
107−exports._openCursor = function _openCursor(index, query, dir, cb) {
123+export function _openCursor(index, query, dir, cb) {
108− return function aff(success, error) {
124+ return function aff(error, success) {
109 try {
125 try {
110 const request = index.openCursor(query, dir);
126 const request = index.openCursor(query, dir);
111 request.onsuccess = function onSuccess(e) {
127 request.onsuccess = function onSuccess(e) {
@@ -116,17 +132,21 @@ exports._openCursor = function _openCursor(index, query, dir, cb) {
116 }
132 }
117 };
133 };
118 request.onerror = function onError(e) {
134 request.onerror = function onError(e) {
119− cb.onError(new Error(e.target.error.name));
135+ cb.onError(e.target.error);
120 };
136 };
121 success();
137 success();
122 } catch (e) {
138 } catch (e) {
123− error(new Error(e.name));
139+ error(e);
124 }
140 }
141+
142+ return function canceler(_, cancelerError) {
143+ cancelerError(new Error("Can't cancel IDB Effects"));
144+ };
125 };
145 };
126};
146};
127
147
128−exports._openKeyCursor = function _openKeyCursor(index, query, dir, cb) {
148+export function _openKeyCursor(index, query, dir, cb) {
129− return function aff(success, error) {
149+ return function aff(error, success) {
130 try {
150 try {
131 const request = index.openKeyCursor(query, dir);
151 const request = index.openKeyCursor(query, dir);
132 request.onsuccess = function onSuccess(e) {
152 request.onsuccess = function onSuccess(e) {
@@ -137,11 +157,15 @@ exports._openKeyCursor = function _openKeyCursor(index, query, dir, cb) {
137 }
157 }
138 };
158 };
139 request.onerror = function onError(e) {
159 request.onerror = function onError(e) {
140− cb.onError(new Error(e.target.error.name));
160+ cb.onError(e.target.error);
141 };
161 };
142 success();
162 success();
143 } catch (e) {
163 } catch (e) {
144− error(new Error(e.name));
164+ error(e);
145 }
165 }
166+
167+ return function canceler(_, cancelerError) {
168+ cancelerError(new Error("Can't cancel IDB Effects"));
169+ };
146 };
170 };
147};
171};
src/Database/IndexedDB/IDBIndex.purs+197−7
@@ -1,16 +1,206 @@
1-- | An index allows looking up records in an object store using properties of the values
1-- | An index allows looking up records in an object store using properties of the values
2-- | in the object stores records.
2-- | in the object stores records.
3module Database.IndexedDB.IDBIndex
3module Database.IndexedDB.IDBIndex
4− ( module Database.IndexedDB.IDBIndex.Internal
4+ -- * Types
5− ) where
5+ ( Callbacks
6+
7+ -- * Interface
8+ , count
9+ , get
10+ , getAllKeys
11+ , getKey
12+ , openCursor
13+ , openKeyCursor
6
14
7−import Database.IndexedDB.IDBIndex.Internal
15+ -- * Attributes
8− ( class IDBIndex, count, get, getAllKeys, getKey, openCursor, openKeyCursor
9− , IDBIndexParameters
10 , keyPath
16 , keyPath
11 , multiEntry
17 , multiEntry
12 , name
18 , name
13 , objectStore
19 , objectStore
14 , unique
20 , unique
15− , defaultParameters
21+ ) where
16− )
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.pursdeleted−256
@@ -1,256 +0,0 @@
1−-- | An index allows looking up records in an object store using properties of the values
2−-- | in the object stores records.
3−module Database.IndexedDB.IDBIndex.Internal where
4−
5−import Prelude
6−
7−import Control.Monad.Aff (Aff)
8−import Control.Monad.Eff (Eff)
9−import Control.Monad.Eff.Exception (Error)
10−import Data.Foreign (Foreign, unsafeFromForeign)
11−import Data.Function.Uncurried as Fn
12−import Data.Function.Uncurried (Fn2, Fn3, Fn4)
13−import Data.Maybe (Maybe)
14−import Data.Nullable (Nullable, toMaybe, toNullable)
15−
16−import Database.IndexedDB.Core (IDB, CursorDirection, Index, Key, KeyCursor, KeyRange, KeyPath, ObjectStore, ValueCursor)
17−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key(..))
18−
19−
20−--------------------
21−-- INTERFACES
22−--
23−-- | The IDBIndex interface represents an index handle.
24−-- | Any of these methods throw an "TransactionInactiveError" DOMException
25−-- | if called when the transaction is not active.
26−class IDBIndex index where
27− -- | Retrieves the number of records matching the key range in query.
28− count
29− :: forall e
30− . index
31− -> Maybe KeyRange
32− -> Aff (idb :: IDB | e) Int
33−
34− -- | Retrieves the value of the first record matching the given key range in query.
35− -- |
36− -- | NOTE
37− -- | The coercion from `a` to any type is unsafe and might throw a runtime error if incorrect.
38− get
39− :: forall a e
40− . index
41− -> KeyRange
42− -> Aff (idb :: IDB | e) (Maybe a)
43−
44− -- | Retrieves the keys of records matching the given key range in query
45− -- | (up to the number given if given).
46− getAllKeys
47− :: forall e
48− . index
49− -> Maybe KeyRange
50− -> Maybe Int
51− -> Aff (idb :: IDB | e) (Array Key)
52−
53− -- | Retrieves the key of the first record matching the given key or key range in query.
54− getKey
55− :: forall e
56− . index
57− -> KeyRange
58− -> Aff (idb :: IDB | e) (Maybe Key)
59−
60− -- | Opens a ValueCursor over the records matching query, ordered by direction.
61− -- | If query is `Nothing`, all records in index are matched.
62− openCursor
63− :: forall e e'
64− . index
65− -> Maybe KeyRange
66− -> CursorDirection
67− -> Callbacks ValueCursor e'
68− -> Aff (idb :: IDB | e) Unit
69−
70− -- | Opens a KeyCursor over the records matching query, ordered by direction.
71− -- | If query is `Nothing`, all records in index are matched.
72− openKeyCursor
73− :: forall e e'
74− . index
75− -> Maybe KeyRange
76− -> CursorDirection
77− -> Callbacks KeyCursor e'
78− -> Aff (idb :: IDB | e) Unit
79−
80−
81−-- | Flags to set on the index.
82−-- |
83−-- | An index has a `unique` flag. When this flag is set, the index enforces that no
84−-- | two records in the index has the same key. If a record in the index’s referenced
85−-- | object store is attempted to be inserted or modified such that evaluating the index’s
86−-- | key path on the records new value yields a result which already exists in the index,
87−-- | then the attempted modification to the object store fails.
88−-- |
89−-- | An index has a `multiEntry` flag. This flag affects how the index behaves when the
90−-- | result of evaluating the index’s key path yields an array key. If the `multiEntry` flag
91−-- | is unset, then a single record whose key is an array key is added to the index.
92−-- | If the `multiEntry` flag is true, then the one record is added to the index for each
93−-- | of the subkeys.
94−type IDBIndexParameters =
95− { unique :: Boolean
96− , multiEntry :: Boolean
97− }
98−
99−
100−-- | Callbacks to manipulate a cursor from an Open*Cursor call
101−type Callbacks cursor e =
102− { onSuccess :: cursor -> Eff ( | e) Unit
103− , onError :: Error -> Eff ( | e) Unit
104− , onComplete :: Eff ( | e) Unit
105− }
106−
107−
108−defaultParameters :: IDBIndexParameters
109−defaultParameters =
110− { unique : false
111− , multiEntry : false
112− }
113−
114−
115−--------------------
116−-- ATTRIBUTES
117−--
118−-- | Returns the key path of the index.
119−keyPath
120− :: Index
121− -> KeyPath
122−keyPath =
123− _keyPath
124−
125−
126−-- | Returns true if the index's multiEntry flag is set.
127−multiEntry
128− :: Index
129− -> Boolean
130−multiEntry =
131− _multiEntry
132−
133−
134−-- | Returns the name of the index.
135−name
136− :: Index
137− -> String
138−name =
139− _name
140−
141−
142−-- | Returns the IDBObjectStore the index belongs to.
143−objectStore
144− :: Index
145− -> ObjectStore
146−objectStore =
147− _objectStore
148−
149−
150−-- | Returns true if the index's unique flag is set.
151−unique
152− :: Index
153− -> Boolean
154−unique =
155− _unique
156−
157−
158−--------------------
159−-- INSTANCES
160−--
161−instance idbIndexIndex :: IDBIndex Index where
162− count index range =
163− Fn.runFn2 _count index (toNullable range)
164−
165− get index range =
166− (toMaybe >>> map unsafeFromForeign) <$> Fn.runFn2 _get index range
167−
168− getAllKeys index range count =
169− map Key <$> Fn.runFn3 _getAllKeys index (toNullable range) (toNullable count)
170−
171− getKey index range =
172− (toMaybe >>> map Key) <$> Fn.runFn2 _getKey index range
173−
174− openCursor index range dir cb =
175− Fn.runFn4 _openCursor index (toNullable range) (show dir) cb
176−
177− openKeyCursor index range dir cb =
178− Fn.runFn4 _openKeyCursor index (toNullable range) (show dir) cb
179−
180−
181−instance idbIndexObjectStore :: IDBIndex ObjectStore where
182− count store range =
183− Fn.runFn2 _count store (toNullable range)
184−
185− get store range =
186− (toMaybe >>> map unsafeFromForeign) <$> Fn.runFn2 _get store range
187−
188− getAllKeys store range count =
189− map Key <$> Fn.runFn3 _getAllKeys store (toNullable range) (toNullable count)
190−
191− getKey store range =
192− (toMaybe >>> map Key) <$> Fn.runFn2 _getKey store range
193−
194− openCursor store range dir cb =
195− Fn.runFn4 _openCursor store (toNullable range) (show dir) cb
196−
197− openKeyCursor store range dir cb =
198− Fn.runFn4 _openKeyCursor store (toNullable range) (show dir) cb
199−
200−
201−--------------------
202−-- FFI
203−--
204−foreign import _keyPath
205− :: Index
206− -> Array String
207−
208−
209−foreign import _multiEntry
210− :: Index
211− -> Boolean
212−
213−
214−foreign import _name
215− :: Index
216− -> String
217−
218−
219−foreign import _objectStore
220− :: Index
221− -> ObjectStore
222−
223−
224−foreign import _unique
225− :: Index
226− -> Boolean
227−
228−
229−foreign import _count
230− :: forall index e
231− . Fn2 index (Nullable KeyRange) (Aff (idb :: IDB | e) Int)
232−
233−
234−foreign import _get
235− :: forall index e
236− . Fn2 index KeyRange (Aff (idb :: IDB | e) (Nullable Foreign))
237−
238−
239−foreign import _getAllKeys
240− :: forall index e
241− . Fn3 index (Nullable KeyRange) (Nullable Int) (Aff (idb :: IDB | e) (Array Foreign))
242−
243−
244−foreign import _getKey
245− :: forall index e
246− . Fn2 index KeyRange (Aff (idb :: IDB | e) (Nullable Foreign))
247−
248−
249−foreign import _openCursor
250− :: forall index e e'
251− . Fn4 index (Nullable KeyRange) String (Callbacks ValueCursor e') (Aff (idb :: IDB | e) Unit)
252−
253−
254−foreign import _openKeyCursor
255− :: forall index e e'
256− . Fn4 index (Nullable KeyRange) String (Callbacks KeyCursor e') (Aff (idb :: IDB | e) Unit)
src/Database/IndexedDB/IDBKey.purs+8−1
@@ -5,4 +5,11 @@ module Database.IndexedDB.IDBKey
5 ( module Database.IndexedDB.IDBKey.Internal
5 ( module Database.IndexedDB.IDBKey.Internal
6 ) where
6 ) where
7
7
8−import Database.IndexedDB.IDBKey.Internal(class IDBKey, Key, none, toKey, fromKey, unsafeFromKey)
8+import Database.IndexedDB.IDBKey.Internal
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−exports._dateTimeToForeign = function _dateTimeToForeign(y, m, d, h, mi, s, ms) {
1+export 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−exports._readDateTime = function _readDateTime(parse, right, left, date) {
5+export 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 @@ exports._readDateTime = function _readDateTime(parse, right, left, date) {
24 return right(mdate);
24 return right(mdate);
25};
25};
26
26
27−exports._unsafeReadDateTime = function _unsafeReadDateTime(parse, date) {
27+export 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+96−114
@@ -2,44 +2,37 @@
2-- |
2-- |
3-- | NOTE: Binary keys aren't supported yet.
3-- | NOTE: Binary keys aren't supported yet.
4module Database.IndexedDB.IDBKey.Internal
4module Database.IndexedDB.IDBKey.Internal
5− ( Key(..)
5+ ( Key
6− , none
6+ , class IDBKey
7+ , toKey
8+ , fromKey
7− , class IDBKey, toKey , fromKey , unsafeFromKey
9+ , unsafeFromKey
8− , extractForeign
10+ , none
9− ) where
11+ ) where
10
12
11import Prelude
13import Prelude
12
14
13−import Control.Alt ((<|>))
15+import Control.Alt ((<|>))
14−import Control.Monad.Except (ExceptT(..), runExceptT)
16+import Control.Monad.Except (ExceptT(..), runExceptT)
15−import Data.Date as Date
17+import Data.Date as Date
16−import Data.DateTime (DateTime(..), Time(..))
18+import Data.DateTime (DateTime(..), Time(..))
19+import Data.Either (Either(..), either, isRight)
17−import Data.Enum (fromEnum, toEnum)
20+import Data.Enum (fromEnum, toEnum)
18−import Data.Foreign as Foreign
21+import Foreign as Foreign
19−import Data.Foreign (Foreign, F)
22+import Foreign (Foreign, F)
20−import Data.Function.Uncurried as Fn
23+import Data.Function.Uncurried as Fn
21−import Data.Function.Uncurried (Fn2, Fn4, Fn7)
24+import Data.Function.Uncurried (Fn2, Fn4, Fn7)
25+import Data.Identity (Identity(..))
22−import Data.List.NonEmpty (NonEmptyList(..))
26+import Data.List.NonEmpty (NonEmptyList(..))
23−import Data.List.Types (List(..))
27+import Data.List.Types (List(..))
24−import Data.NonEmpty (NonEmpty(..))
28+import Data.Maybe (Maybe(..))
25−import Data.Either (Either(..), either, isRight)
26−import Data.Maybe (Maybe(..))
29+import Data.NonEmpty (NonEmpty(..))
27−import Data.Identity (Identity(..))
28−import Data.Nullable (Nullable, toNullable)
30+import Data.Nullable (Nullable, toNullable)
29−import Data.Time as Time
31+import Data.Time as Time
30−import Data.Traversable (traverse)
32+import Data.Traversable (traverse)
31−
32
33
33newtype Key = Key Foreign
34newtype Key = Key Foreign
34
35
35−
36−extractForeign
37− :: Key
38− -> Foreign
39−extractForeign (Key f) =
40− f
41−
42−
43--------------------
36--------------------
44-- INTERFACES
37-- INTERFACES
45--
38--
@@ -47,94 +40,90 @@ extractForeign (Key f) =
47-- | to a known type (e.g if you only strings as keys, or perfectly knows the
40-- | to a known type (e.g if you only strings as keys, or perfectly knows the
48-- | type of a given key).
41-- | type of a given key).
49class IDBKey a where
42class IDBKey a where
50− toKey :: a -> Key
43+ toKey :: a -> Key
51− fromKey :: Key -> F a
44+ fromKey :: Key -> F a
52 unsafeFromKey :: Key -> a
45 unsafeFromKey :: Key -> a
53
46
54−
55none :: Maybe Key
47none :: Maybe Key
56none =
48none =
57 Nothing
49 Nothing
58
50
59−
60--------------------
51--------------------
61-- INSTANCES
52-- INSTANCES
62--
53--
63instance eqKey :: Eq Key where
54instance eqKey :: Eq Key where
64 eq a b = (runExceptT >>> runIdentity >>> isRight) $
55 eq a b = (runExceptT >>> runIdentity >>> isRight) $
65− eq <$> ((fromKey a) :: F Int) <*> fromKey b
56+ eq <$> ((fromKey a) :: F Int) <*> fromKey b
66− <|>
57+ <|>
67− eq <$> ((fromKey a) :: F Number) <*> fromKey b
58+ eq <$> ((fromKey a) :: F Number) <*> fromKey b
68− <|>
59+ <|>
69− eq <$> ((fromKey a) :: F String) <*> fromKey b
60+ eq <$> ((fromKey a) :: F String) <*> fromKey b
70− <|>
61+ <|>
71− eq <$> ((fromKey a) :: F DateTime) <*> fromKey b
62+ eq <$> ((fromKey a) :: F DateTime) <*> fromKey b
72− <|>
63+ <|>
73− eq <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
64+ eq <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
74 where
65 where
75− runIdentity :: forall a. Identity a -> a
66+ runIdentity :: forall a. Identity a -> a
76− runIdentity (Identity x) = x
67+ runIdentity (Identity x) = x
77−
78
68
79instance ordKey :: Ord Key where
69instance ordKey :: Ord Key where
80− compare a b = (runExceptT >>> runIdentity >>> either (const LT) id) $
70+ compare a b = (runExceptT >>> runIdentity >>> either (const LT) identity) $
81− compare <$> ((fromKey a) :: F Int) <*> fromKey b
71+ compare <$> ((fromKey a) :: F Int) <*> fromKey b
82− <|>
72+ <|>
83− compare <$> ((fromKey a) :: F Number) <*> fromKey b
73+ compare <$> ((fromKey a) :: F Number) <*> fromKey b
84− <|>
74+ <|>
85− compare <$> ((fromKey a) :: F String) <*> fromKey b
75+ compare <$> ((fromKey a) :: F String) <*> fromKey b
86− <|>
76+ <|>
87− compare <$> ((fromKey a) :: F DateTime) <*> fromKey b
77+ compare <$> ((fromKey a) :: F DateTime) <*> fromKey b
88− <|>
78+ <|>
89− compare <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
79+ compare <$> ((fromKey a) :: F (Array Key)) <*> fromKey b
90 where
80 where
91− runIdentity :: forall a. Identity a -> a
81+ runIdentity :: forall a. Identity a -> a
92− runIdentity (Identity x) = x
82+ runIdentity (Identity x) = x
93−
94
83
95instance showKey :: Show Key where
84instance showKey :: Show Key where
96 show a = (runExceptT >>> format) $
85 show a = (runExceptT >>> format) $
97− (show <$> (fromKey a :: F Int))
86+ (show <$> (fromKey a :: F Int))
98− <|>
87+ <|>
99− (show <$> (fromKey a :: F Number))
88+ (show <$> (fromKey a :: F Number))
100− <|>
89+ <|>
101− (show <$> (fromKey a :: F String))
90+ (show <$> (fromKey a :: F String))
102− <|>
91+ <|>
103− (show <$> (fromKey a :: F DateTime))
92+ (show <$> (fromKey a :: F DateTime))
104− <|>
93+ <|>
105− (show <$> (fromKey a :: F (Array Key)))
94+ (show <$> (fromKey a :: F (Array Key)))
106 where
95 where
107− format :: forall a. Identity (Either a String) -> String
96+ format :: forall a. Identity (Either a String) -> String
108− format (Identity x) =
97+ format (Identity x) =
109− either (const "(Key)") (\s -> "(Key " <> s <> ")") x
98+ either (const "(Key)") (\s -> "(Key " <> s <> ")") x
110−
111
99
112instance idbKeyKey :: IDBKey Key where
100instance idbKeyKey :: IDBKey Key where
113− toKey = id
101+ toKey = identity
114− fromKey = pure
102+ fromKey = pure
115− unsafeFromKey = id
103+ unsafeFromKey = identity
116
104
105+instance idbKeyForeign :: IDBKey Foreign where
106+ toKey = Key
107+ fromKey (Key f) = pure f
108+ unsafeFromKey (Key f) = f
117
109
118instance idbKeyInt :: IDBKey Int where
110instance idbKeyInt :: IDBKey Int where
119− toKey = Foreign.toForeign >>> Key
111+ toKey = Foreign.unsafeToForeign >>> Key
120− fromKey (Key f) = Foreign.readInt f
112+ fromKey (Key f) = Foreign.readInt f
121 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
113 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
122
114
123−
124instance idbKeyNumber :: IDBKey Number where
115instance idbKeyNumber :: IDBKey Number where
125− toKey = Foreign.toForeign >>> Key
116+ toKey = Foreign.unsafeToForeign >>> Key
126− fromKey (Key f) = Foreign.readNumber f
117+ fromKey (Key f) = Foreign.readNumber f
127 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
118 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
128
119
129−
130instance idbKeyString :: IDBKey String where
120instance idbKeyString :: IDBKey String where
131− toKey = Foreign.toForeign >>> Key
121+ toKey = Foreign.unsafeToForeign >>> Key
132− fromKey (Key f) = Foreign.readString f
122+ fromKey (Key f) = Foreign.readString f
133 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
123 unsafeFromKey (Key f) = Foreign.unsafeFromForeign f
134
124
135−
136instance idbKeyDate :: IDBKey DateTime where
125instance idbKeyDate :: IDBKey DateTime where
137− toKey (DateTime d t) = Key $ Fn.runFn7 _dateTimeToForeign
126+ toKey (DateTime d t) = Key $ Fn.runFn7 _dateTimeToForeign
138 (fromEnum $ Date.year d)
127 (fromEnum $ Date.year d)
139 (fromEnum $ Date.month d)
128 (fromEnum $ Date.month d)
140 (fromEnum $ Date.day d)
129 (fromEnum $ Date.day d)
@@ -142,58 +131,51 @@ instance idbKeyDate :: IDBKey DateTime where
142 (fromEnum $ Time.minute t)
131 (fromEnum $ Time.minute t)
143 (fromEnum $ Time.second t)
132 (fromEnum $ Time.second t)
144 (fromEnum $ Time.millisecond t)
133 (fromEnum $ Time.millisecond t)
145− fromKey (Key f) = Fn.runFn4 _readDateTime dateTime dateTimeF dateTimeE f
134+ fromKey (Key f) = Fn.runFn4 _readDateTime dateTime dateTimeF dateTimeE f
146 unsafeFromKey (Key f) = Fn.runFn2 _unsafeReadDateTime dateTime f
135 unsafeFromKey (Key f) = Fn.runFn2 _unsafeReadDateTime dateTime f
147
136
148−
149instance idbKeyArray :: IDBKey a => IDBKey (Array a) where
137instance idbKeyArray :: IDBKey a => IDBKey (Array a) where
150− toKey = Foreign.toForeign >>> Key
138+ toKey = Foreign.unsafeToForeign >>> Key
151− fromKey (Key f) = Foreign.readArray f >>= traverse (Key >>> fromKey)
139+ fromKey (Key f) = Foreign.readArray f >>= traverse (Key >>> fromKey)
152 unsafeFromKey (Key f) = map unsafeFromKey (Foreign.unsafeFromForeign f)
140 unsafeFromKey (Key f) = map unsafeFromKey (Foreign.unsafeFromForeign f)
153
141
154−
155-- FFI constructor to build a DateTime from years, months, days, hours, minutes, seconds and millis
142-- FFI constructor to build a DateTime from years, months, days, hours, minutes, seconds and millis
156dateTime
143dateTime
157− :: Int -- ^ years
144+ :: Int -- ^ years
158− -> Int -- ^ months
145+ -> Int -- ^ months
159− -> Int -- ^ days
146+ -> Int -- ^ days
160− -> Int -- ^ hours
147+ -> Int -- ^ hours
161− -> Int -- ^ minutes
148+ -> Int -- ^ minutes
162− -> Int -- ^ seconds
149+ -> Int -- ^ seconds
163− -> Int -- ^ milliseconds
150+ -> Int -- ^ milliseconds
164− -> Nullable DateTime
151+ -> Nullable DateTime
165dateTime y m d h mi s ms =
152dateTime y m d h mi s ms =
166 toNullable $ DateTime
153 toNullable $ DateTime
167− <$> (Date.canonicalDate <$> toEnum y <*> toEnum m <*> toEnum d)
154+ <$> (Date.canonicalDate <$> toEnum y <*> toEnum m <*> toEnum d)
168− <*> (Time <$> toEnum h <*> toEnum mi <*> toEnum s <*> toEnum ms)
155+ <*> (Time <$> toEnum h <*> toEnum mi <*> toEnum s <*> toEnum ms)
169−
170
156
171-- FFI constructor to convert a JS `Date` into a successful `F DateTime`
157-- FFI constructor to convert a JS `Date` into a successful `F DateTime`
172dateTimeF
158dateTimeF
173− :: DateTime
159+ :: DateTime
174− -> F DateTime
160+ -> F DateTime
175dateTimeF =
161dateTimeF =
176 Right >>> Identity >>> ExceptT
162 Right >>> Identity >>> ExceptT
177
163
178−
179-- FFI constructor to convert a string into an errored `F DateTime`
164-- FFI constructor to convert a string into an errored `F DateTime`
180dateTimeE
165dateTimeE
181− :: String
166+ :: String
182− -> F DateTime
167+ -> F DateTime
183dateTimeE =
168dateTimeE =
184 Foreign.TypeMismatch "Date" >>> flip NonEmpty Nil >>> NonEmptyList >>> Left >>> Identity >>> ExceptT
169 Foreign.TypeMismatch "Date" >>> flip NonEmpty Nil >>> NonEmptyList >>> Left >>> Identity >>> ExceptT
185
170
186−
187--------------------
171--------------------
188-- FFI
172-- FFI
189--
173--
190foreign import _dateTimeToForeign
174foreign import _dateTimeToForeign
191− :: Fn7 Int Int Int Int Int Int Int Foreign
175+ :: Fn7 Int Int Int Int Int Int Int Foreign
192−
193
176
194foreign import _readDateTime
177foreign import _readDateTime
195− :: Fn4 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) (DateTime -> F DateTime) (String -> F DateTime) Foreign (F DateTime)
178+ :: Fn4 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) (DateTime -> F DateTime) (String -> F DateTime) Foreign (F DateTime)
196−
197
179
198foreign import _unsafeReadDateTime
180foreign import _unsafeReadDateTime
199− :: Fn2 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) Foreign DateTime
181+ :: Fn2 (Int -> Int -> Int -> Int -> Int -> Int -> Int -> Nullable DateTime) Foreign DateTime
src/Database/IndexedDB/IDBKeyRange.js+9−9
@@ -1,4 +1,4 @@
1−exports._bound = function _bound(lower, upper, lowerOpen, upperOpen) {
1+export 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 @@ exports._bound = function _bound(lower, upper, lowerOpen, upperOpen) {
6 }
6 }
7};
7};
8
8
9−exports._includes = function _includes(range, key) {
9+export function _includes(range, key) {
10 return range.includes(key);
10 return range.includes(key);
11};
11};
12
12
13−exports._lower = function _lower(range) {
13+export function _lower(range) {
14 return range.lower;
14 return range.lower;
15};
15};
16
16
17−exports._lowerBound = function _lowerBound(lower, open) {
17+export function _lowerBound(lower, open) {
18 return IDBKeyRange.lowerBound(lower, open);
18 return IDBKeyRange.lowerBound(lower, open);
19};
19};
20
20
21−exports._lowerOpen = function _lowerOpen(range) {
21+export function _lowerOpen(range) {
22 return range.lowerOpen;
22 return range.lowerOpen;
23};
23};
24
24
25−exports._only = function _only(key) {
25+export function _only(key) {
26 return IDBKeyRange.only(key);
26 return IDBKeyRange.only(key);
27};
27};
28
28
29−exports._upper = function _upper(range) {
29+export function _upper(range) {
30 return range.upper;
30 return range.upper;
31};
31};
32
32
33−exports._upperBound = function _upperBound(upper, open) {
33+export function _upperBound(upper, open) {
34 return IDBKeyRange.upperBound(upper, open);
34 return IDBKeyRange.upperBound(upper, open);
35};
35};
36
36
37−exports._upperOpen = function _upperOpen(range) {
37+export function _upperOpen(range) {
38 return range.upperOpen;
38 return range.upperOpen;
39};
39};
src/Database/IndexedDB/IDBKeyRange.purs+81−79
@@ -1,70 +1,76 @@
1-- | A key has an associated type which is one of: number, date, string, binary, or array.
1-- | A key has an associated type which is one of: number, date, string, binary, or array.
2module Database.IndexedDB.IDBKeyRange
2module Database.IndexedDB.IDBKeyRange
3− ( class IDBKeyRange, includes
3+ -- * Types
4+ ( Open
5+
6+ -- * Constructors
4 , only
7 , only
5 , lowerBound
8 , lowerBound
6 , upperBound
9 , upperBound
7 , bound
10 , bound
11+
12+ -- * Interface
13+ , includes
14+
15+ -- * Attributes
8 , lower
16 , lower
9 , upper
17 , upper
10 , lowerOpen
18 , lowerOpen
11 , upperOpen
19 , upperOpen
12 ) where
20 ) where
13
21
14−import Prelude
22+import Prelude (($), (>>>), map)
15−
16−import Data.Foreign (Foreign)
17−import Data.Function.Uncurried as Fn
18−import Data.Function.Uncurried (Fn2, Fn4)
19−import Data.Maybe (Maybe)
20−import Data.Nullable (Nullable, toMaybe)
21
23
22−import Database.IndexedDB.Core (KeyRange)
24+import Foreign (Foreign)
23−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key(..), toKey, extractForeign)
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)
24
29
30+import Database.IndexedDB.Core (class IDBKeyRange, KeyRange)
31+import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key, toKey, unsafeFromKey)
25
32
26--------------------
33--------------------
27−-- INTERFACES
34+-- TYPES
28--
35--
29−-- | The IDBKeyRange interface represents a key range.
30−class IDBKeyRange range where
31− -- | Returns true if key is included in the range, and false otherwise.
32− includes :: forall k. (IDBKey k) => range -> k -> Boolean
33
36
34-- | Type alias for open
37-- | Type alias for open
35type Open = Boolean
38type Open = Boolean
36
39
40+--------------------
41+-- CONSTRUCTORS
42+--
37
43
38-- | Returns a new IDBKeyRange spanning only key.
44-- | Returns a new IDBKeyRange spanning only key.
39only
45only
40− :: forall a. (IDBKey a)
46+ :: forall a
47+ . (IDBKey a)
41− => a
48+ => a
42− -> KeyRange
49+ -> KeyRange
43only key =
50only key =
44− _only (extractForeign $ toKey key)
51+ _only (unsafeFromKey $ toKey key)
45−
46
52
47-- | Returns a new IDBKeyRange starting at key with no upper bound.
53-- | Returns a new IDBKeyRange starting at key with no upper bound.
48-- | If `Open` is `true`, key is not included in the range.
54-- | If `Open` is `true`, key is not included in the range.
49lowerBound
55lowerBound
50− :: forall a. (IDBKey a)
56+ :: forall a
57+ . (IDBKey a)
51− => a
58+ => a
52− -> Open
59+ -> Open
53− -> KeyRange
60+ -> KeyRange
54lowerBound key open =
61lowerBound key open =
55− Fn.runFn2 _lowerBound (extractForeign $ toKey key) open
62+ Fn.runFn2 _lowerBound (unsafeFromKey $ toKey key) open
56−
57
63
58-- | Returns a new IDBKeyRange with no lower bound and ending at key.
64-- | Returns a new IDBKeyRange with no lower bound and ending at key.
59-- | If `Open` is `true`, key is not included in the range.
65-- | If `Open` is `true`, key is not included in the range.
60upperBound
66upperBound
61− :: forall a. (IDBKey a)
67+ :: forall a
68+ . (IDBKey a)
62− => a
69+ => a
63− -> Open
70+ -> Open
64− -> KeyRange
71+ -> KeyRange
65upperBound key open =
72upperBound key open =
66− Fn.runFn2 _upperBound (extractForeign $ toKey key) open
73+ Fn.runFn2 _upperBound (unsafeFromKey $ toKey key) open
67−
68
74
69-- | Returns a new IDBKeyRange spanning from `lower` to `upper`.
75-- | Returns a new IDBKeyRange spanning from `lower` to `upper`.
70-- | If `lowerOpen` is `true`, `lower` is not included in the range.
76-- | If `lowerOpen` is `true`, `lower` is not included in the range.
@@ -72,96 +78,92 @@ upperBound key open =
72-- |
78-- |
73-- | It throws a `DataError` if the bound is invalid.
79-- | It throws a `DataError` if the bound is invalid.
74bound
80bound
75− :: forall a. (IDBKey a)
81+ :: forall key
82+ . (IDBKey key)
76− => { lower :: a, upper :: a, lowerOpen :: Boolean, upperOpen :: Boolean }
83+ => { lower :: key, upper :: key, lowerOpen :: Boolean, upperOpen :: Boolean }
77− -> Maybe KeyRange
84+ -> Maybe KeyRange
78bound { lower: key1, upper: key2, lowerOpen: open1, upperOpen: open2 } =
85bound { lower: key1, upper: key2, lowerOpen: open1, upperOpen: open2 } =
79 toMaybe
86 toMaybe
80− $ Fn.runFn4 _bound (extractForeign $ toKey key1) (extractForeign $ toKey key2) open1 open2
87+ $ Fn.runFn4 _bound (unsafeFromKey $ toKey key1) (unsafeFromKey $ toKey key2) open1 open2
81
88
89+--------------------
90+-- INTERFACE
91+--
92+
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
82
103
83--------------------
104--------------------
84-- ATTRIBUTES
105-- ATTRIBUTES
85--
106--
86-- | Returns lower bound if any.
107-- | Returns lower bound if any.
87lower
108lower
88− :: KeyRange
109+ :: KeyRange
89− -> Maybe Key
110+ -> Maybe Key
90lower =
111lower =
91− _lower >>> toMaybe >>> map Key
112+ _lower >>> toMaybe >>> map toKey
92−
93
113
94-- | Returns upper bound if any.
114-- | Returns upper bound if any.
95upper
115upper
96− :: KeyRange
116+ :: KeyRange
97− -> Maybe Key
117+ -> Maybe Key
98upper =
118upper =
99− _upper >>> toMaybe >>> map Key
119+ _upper >>> toMaybe >>> map toKey
100−
101
120
102-- | Returns true if the lower open flag is set, false otherwise.
121-- | Returns true if the lower open flag is set, false otherwise.
103lowerOpen
122lowerOpen
104− :: KeyRange
123+ :: KeyRange
105− -> Boolean
124+ -> Boolean
106lowerOpen =
125lowerOpen =
107 _lowerOpen
126 _lowerOpen
108
127
109−
110-- | Returns true if the upper open flag is set, false otherwise.
128-- | Returns true if the upper open flag is set, false otherwise.
111upperOpen
129upperOpen
112− :: KeyRange
130+ :: KeyRange
113− -> Boolean
131+ -> Boolean
114upperOpen =
132upperOpen =
115 _upperOpen
133 _upperOpen
116
134
117−
118--------------------
135--------------------
119−-- INSTANCES
136+-- FFI
120--
137--
121−instance idbKeyRangeKeyRange :: IDBKeyRange KeyRange where
122− includes range =
123− toKey >>> extractForeign >>> Fn.runFn2 _includes range
124
138
139+foreign import _only
140+ :: Foreign
141+ -> KeyRange
142+
143+foreign import _lowerBound
144+ :: Fn2 Foreign Boolean KeyRange
145+
146+foreign import _upperBound
147+ :: Fn2 Foreign Boolean KeyRange
125
148
126−--------------------
127−-- FFI
128−--
129foreign import _bound
149foreign import _bound
130 :: Fn4 Foreign Foreign Boolean Boolean (Nullable KeyRange)
150 :: Fn4 Foreign Foreign Boolean Boolean (Nullable KeyRange)
131
151
132−
133foreign import _includes
152foreign import _includes
134 :: forall range
153 :: forall range
135− . Fn2 range Foreign Boolean
154+ . Fn2 range Foreign Boolean
136−
137
155
138foreign import _lower
156foreign import _lower
139 :: KeyRange
157 :: KeyRange
140 -> Nullable Foreign
158 -> Nullable Foreign
141
159
142−
143−foreign import _lowerBound
144− :: Fn2 Foreign Boolean KeyRange
145−
146−
147−foreign import _lowerOpen
148− :: KeyRange
149− -> Boolean
150−
151−
152−foreign import _only
153− :: Foreign
154− -> KeyRange
155−
156−
157foreign import _upper
160foreign import _upper
158 :: KeyRange
161 :: KeyRange
159 -> Nullable Foreign
162 -> Nullable Foreign
160
163
161−
162−foreign import _upperBound
164+foreign import _lowerOpen
165+ :: KeyRange
163− :: Fn2 Foreign Boolean KeyRange
166+ -> Boolean
164−
165
167
166foreign import _upperOpen
168foreign import _upperOpen
167 :: KeyRange
169 :: KeyRange
src/Database/IndexedDB/IDBObjectStore.js+55−28
@@ -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(new Error(e.target.error.name));
3+ cb(e.target.error);
4 };
4 };
5};
5};
6
6
@@ -15,36 +15,44 @@ const toArray = function toArray(xs) {
15};
15};
16
16
17
17
18−exports._add = function _add(store, value, key) {
18+export function _add(store, value, key) {
19− return function aff(success, error) {
19+ return function aff(error, success) {
20 try {
20 try {
21 const request = store.add(value, key || undefined);
21 const request = store.add(value, key || undefined);
22 request.onsuccess = successHandler(success);
22 request.onsuccess = successHandler(success);
23 request.onerror = errorHandler(error);
23 request.onerror = errorHandler(error);
24 } catch (e) {
24 } catch (e) {
25− error(new Error(e.name));
25+ error(e);
26 }
26 }
27+
28+ return function canceler(_, cancelerError) {
29+ cancelerError(new Error("Can't cancel IDB Effects"));
30+ };
27 };
31 };
28};
32};
29
33
30−exports._autoIncrement = function _autoIncrement(store) {
34+export function _autoIncrement(store) {
31 return store.autoIncrement;
35 return store.autoIncrement;
32};
36};
33
37
34−exports._clear = function _clear(store) {
38+export function _clear(store) {
35− return function aff(success, error) {
39+ return function aff(error, success) {
36 try {
40 try {
37 const request = store.clear();
41 const request = store.clear();
38 request.onsuccess = successHandler(success);
42 request.onsuccess = successHandler(success);
39 request.onerror = errorHandler(error);
43 request.onerror = errorHandler(error);
40 } catch (e) {
44 } catch (e) {
41− error(new Error(e.name));
45+ error(e);
42 }
46 }
47+
48+ return function canceler(_, cancelerError) {
49+ cancelerError(new Error("Can't cancel IDB Effects"));
50+ };
43 };
51 };
44};
52};
45
53
46−exports._createIndex = function _createIndex(store, name, path, params) {
54+export function _createIndex(store, name, path, params) {
47− return function aff(success, error) {
55+ return function aff(error, success) {
48 var keyPath;
56 var keyPath;
49
57
50 try {
58 try {
@@ -64,50 +72,66 @@ exports._createIndex = function _createIndex(store, name, path, params) {
64 const index = store.createIndex(name, keyPath, params);
72 const index = store.createIndex(name, keyPath, params);
65 success(index);
73 success(index);
66 } catch (e) {
74 } catch (e) {
67− error(new Error(e.name));
75+ error(e);
68 }
76 }
77+
78+ return function canceler(_, cancelerError) {
79+ cancelerError(new Error("Can't cancel IDB Effects"));
80+ };
69 };
81 };
70};
82};
71
83
72−exports._deleteIndex = function _deleteIndex(store, name) {
84+export function _deleteIndex(store, name) {
73− return function aff(success, error) {
85+ return function aff(error, success) {
74 try {
86 try {
75 store.deleteIndex(name);
87 store.deleteIndex(name);
76 success();
88 success();
77 } catch (e) {
89 } catch (e) {
78− error(new Error(e.name));
90+ error(e);
79 }
91 }
92+
93+ return function canceler(_, cancelerError) {
94+ cancelerError(new Error("Can't cancel IDB Effects"));
95+ };
80 };
96 };
81};
97};
82
98
83−exports._delete = function _delete(store, query) {
99+export function _delete(store, query) {
84− return function aff(success, error) {
100+ return function aff(error, success) {
85 try {
101 try {
86 const request = store.delete(query);
102 const request = store.delete(query);
87 request.onsuccess = successHandler(success);
103 request.onsuccess = successHandler(success);
88 request.onerror = errorHandler(error);
104 request.onerror = errorHandler(error);
89 } catch (e) {
105 } catch (e) {
90− error(new Error(e.name));
106+ error(e);
91 }
107 }
108+
109+ return function canceler(_, cancelerError) {
110+ cancelerError(new Error("Can't cancel IDB Effects"));
111+ };
92 };
112 };
93};
113};
94
114
95−exports._index = function _index(store, name) {
115+export function _index(store, name) {
96− return function aff(success, error) {
116+ return function aff(error, success) {
97 try {
117 try {
98 const index = store.index(name);
118 const index = store.index(name);
99 success(index);
119 success(index);
100 } catch (e) {
120 } catch (e) {
101− error(new Error(e.name));
121+ error(e);
102 }
122 }
123+
124+ return function canceler(_, cancelerError) {
125+ cancelerError(new Error("Can't cancel IDB Effects"));
126+ };
103 };
127 };
104};
128};
105
129
106−exports._indexNames = function _indexNames(store) {
130+export function _indexNames(store) {
107 return toArray(store.indexNames);
131 return toArray(store.indexNames);
108};
132};
109
133
110−exports._keyPath = function _keyPath(store) {
134+export function _keyPath(store) {
111 const path = store.keyPath;
135 const path = store.keyPath;
112
136
113 if (Array.isArray(path)) {
137 if (Array.isArray(path)) {
@@ -121,23 +145,26 @@ exports._keyPath = function _keyPath(store) {
121 return [];
145 return [];
122};
146};
123
147
124−exports._name = function _name(store) {
148+export function _name(store) {
125 return store.name;
149 return store.name;
126};
150};
127
151
128−exports._put = function _put(store, value, key) {
152+export function _put(store, value, key) {
129− return function aff(success, error) {
153+ return function aff(error, success) {
130 try {
154 try {
131 const request = store.put(value, key || undefined);
155 const request = store.put(value, key || undefined);
132 request.onsuccess = successHandler(success);
156 request.onsuccess = successHandler(success);
133 request.onerror = errorHandler(error);
157 request.onerror = errorHandler(error);
134 } catch (e) {
158 } catch (e) {
135− error(new Error(e.name));
159+ error(e);
136 }
160 }
161+
162+ return function canceler(_, cancelerError) {
163+ cancelerError(new Error("Can't cancel IDB Effects"));
164+ };
137 };
165 };
138};
166};
139
167
140−exports._transaction = function _transaction(store) {
168+export function _transaction(store) {
141 return store.transaction;
169 return store.transaction;
142};
170};
143−
src/Database/IndexedDB/IDBObjectStore.purs+160−156
@@ -1,124 +1,170 @@
1-- | An object store is the primary storage mechanism for storing data in a database.
1-- | An object store is the primary storage mechanism for storing data in a database.
2module Database.IndexedDB.IDBObjectStore
2module Database.IndexedDB.IDBObjectStore
3− ( class IDBObjectStore, add, clear, createIndex, delete, deleteIndex, index, put
3+ -- * Types
4− , module Database.IndexedDB.IDBIndex.Internal
4+ ( IndexName
5− , IDBObjectStoreParameters
5+ , IndexParameters
6− , IndexName
6+ , defaultParameters
7+
8+ -- * Interface
9+ , add
10+ , clear
11+ , createIndex
12+ , delete
13+ , deleteIndex
14+ , index
15+ , put
16+
17+ -- * Attributes
7 , autoIncrement
18 , autoIncrement
8 , indexNames
19 , indexNames
9 , keyPath
20 , keyPath
10 , name
21 , name
11 , transaction
22 , transaction
12− , defaultParameters
13− ) where
14−
15−import Prelude (Unit, ($), (<$>), (>>>))
16
23
17−import Control.Monad.Aff (Aff)
24+ -- * Re-Exports
18−import Data.Foreign (Foreign)
25+ , module Database.IndexedDB.IDBIndex
19−import Data.Function.Uncurried as Fn
26+ ) where
20−import Data.Function.Uncurried (Fn2, Fn3, Fn4)
21−import Data.Maybe (Maybe)
22−import Data.Nullable (Nullable, toNullable)
23
27
24−import Database.IndexedDB.Core (IDB, Index, KeyRange, KeyPath, ObjectStore, Transaction)
28+import Database.IndexedDB.Core
25−import Database.IndexedDB.IDBIndex.Internal (class IDBIndex, IDBIndexParameters, count, get, getAllKeys, getKey, openCursor, openKeyCursor)
26−import Database.IndexedDB.IDBKey.Internal (class IDBKey, Key(Key), extractForeign, toKey)
27
29
30+import Data.Function.Uncurried (Fn2, Fn3, Fn4)
31+import Data.Function.Uncurried as Fn
32+import Data.Maybe (Maybe)
33+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, ($), (<$>), (>>>), (<<<))
28
40
29--------------------
41--------------------
30−-- INTERFACES
42+-- TYPES
31--
43--
32−-- | The IDBObjectStore interface represents an object store handle.
33−class IDBObjectStore store where
34− -- | Adds or updates a record in store with the given value and key.
35− -- |
36− -- | If the store uses in-line keys and key is specified a "DataError" DOMException
37− -- | will be thrown.
38− -- |
39− -- | If add() is used, and if a record with the key already exists the request will fail,
40− -- | with a "ConstraintError" DOMException.
41− add
42− :: forall v k e. (IDBKey k)
43− => store
44− -> v
45− -> Maybe k
46− -> Aff (idb :: IDB | e) Key
47−
48− -- | Deletes all records in store.
49− clear
50− :: forall e
51− . store
52− -> Aff (idb :: IDB | e) Unit
53−
54− -- | Creates a new index in store with the given name, keyPath and options and
55− -- | returns a new IDBIndex. If the keyPath and options define constraints that
56− -- | cannot be satisfied with the data already in store the upgrade transaction
57− -- | will abort with a "ConstraintError" DOMException.
58− -- |
59− -- | Throws an "InvalidStateError" DOMException if not called within an upgrade transaction.
60− createIndex
61− :: forall e
62− . store
63− -> IndexName
64− -> KeyPath
65− -> IDBIndexParameters
66− -> Aff (idb :: IDB | e) Index
67−
68− -- | Deletes records in store with the given key or in the given key range in query.
69− delete
70− :: forall e
71− . store
72− -> KeyRange
73− -> Aff (idb :: IDB | e) Unit
74−
75− -- | Deletes the index in store with the given name.
76− -- |
77− -- | Throws an "InvalidStateError" DOMException if not called within an upgrade transaction.
78− deleteIndex
79− :: forall e
80− . store
81− -> IndexName
82− -> Aff (idb :: IDB | e) Unit
83−
84− -- | Returns an IDBIndex for the index named name in store.
85− index
86− :: forall e
87− . store
88− -> IndexName
89− -> Aff (idb :: IDB | e) Index
90−
91− -- | Adds or updates a record in store with the given value and key.
92− -- |
93− -- | If the store uses in-line keys and key is specified a "DataError" DOMException
94− -- | will be thrown.
95− -- |
96− -- | If put() is used, any existing record with the key will be replaced.
97− put
98− :: forall v k e. (IDBKey k)
99− => store
100− -> v
101− -> Maybe k
102− -> Aff (idb :: IDB | e) Key
103−
104
44
105-- | Type alias for IndexName
45-- | Type alias for IndexName
106type IndexName = String
46type IndexName = String
107
47
108−
48+-- | Flags to set on the index.
109−-- | Options provided when creating an object store.
49+-- |
110−type IDBObjectStoreParameters =
50+-- | An index has a `unique` flag. When this flag is set, the index enforces that no
111− { keyPath :: KeyPath
51+-- | two records in the index has the same key. If a record in the index’s referenced
112− , autoIncrement :: Boolean
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
113 }
64 }
114
65
115−
116−defaultParameters :: IDBObjectStoreParameters
66+defaultParameters :: IndexParameters
117defaultParameters =
67defaultParameters =
118− { keyPath : []
68+ { unique: false
119− , autoIncrement : false
69+ , multiEntry: false
120 }
70 }
121
71
72+--------------------
73+-- INTERFACES
74+--
75+
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)
122
168
123--------------------
169--------------------
124-- ATTRIBUTES
170-- ATTRIBUTES
@@ -130,7 +176,6 @@ autoIncrement
130autoIncrement =
176autoIncrement =
131 _autoIncrement
177 _autoIncrement
132
178
133−
134--| Returns a list of the names of indexes in the store.
179--| Returns a list of the names of indexes in the store.
135indexNames
180indexNames
136 :: ObjectStore
181 :: ObjectStore
@@ -138,7 +183,6 @@ indexNames
138indexNames =
183indexNames =
139 _indexNames
184 _indexNames
140
185
141−
142-- | Returns the key path of the store, or empty array if none
186-- | Returns the key path of the store, or empty array if none
143keyPath
187keyPath
144 :: ObjectStore
188 :: ObjectStore
@@ -146,7 +190,6 @@ keyPath
146keyPath =
190keyPath =
147 _keyPath
191 _keyPath
148
192
149−
150-- | Returns the name of the store.
193-- | Returns the name of the store.
151name
194name
152 :: ObjectStore
195 :: ObjectStore
@@ -154,7 +197,6 @@ name
154name =
197name =
155 _name
198 _name
156
199
157−
158-- | Returns the associated transaction.
200-- | Returns the associated transaction.
159transaction
201transaction
160 :: ObjectStore
202 :: ObjectStore
@@ -162,91 +204,53 @@ transaction
162transaction =
204transaction =
163 _transaction
205 _transaction
164
206
165−
166−--------------------
167−-- INSTANCES
168−--
169−instance idbObjectStoreObjectStore :: IDBObjectStore ObjectStore where
170− add store value key =
171− Key <$> Fn.runFn3 _add store value (toNullable $ (toKey >>> extractForeign) <$> key)
172−
173− clear =
174− _clear
175−
176− createIndex store name' path params =
177− Fn.runFn4 _createIndex store name' path params
178−
179− delete store range =
180− Fn.runFn2 _delete store range
181−
182− deleteIndex store name' =
183− Fn.runFn2 _deleteIndex store name'
184−
185− index store name' =
186− Fn.runFn2 _index store name'
187−
188− put store value key =
189− Key <$> Fn.runFn3 _put store value (toNullable $ (toKey >>> extractForeign) <$> key)
190−
191−
192--------------------
207--------------------
193-- FFI
208-- FFI
194--
209--
195foreign import _add
210foreign import _add
196− :: forall value e
211+ :: forall val store
197− . Fn3 ObjectStore value (Nullable Foreign) (Aff (idb :: IDB | e) Foreign)
212+ . Fn3 store val (Nullable Foreign) (EffectFnAff Foreign)
198−
199
213
200foreign import _autoIncrement
214foreign import _autoIncrement
201 :: ObjectStore
215 :: ObjectStore
202 -> Boolean
216 -> Boolean
203
217
204−
205foreign import _clear
218foreign import _clear
206− :: forall e
219+ :: forall store
207− . ObjectStore
220+ . store
208− -> Aff (idb :: IDB | e) Unit
221+ -> EffectFnAff Unit
209−
210
222
211foreign import _createIndex
223foreign import _createIndex
212− :: forall e
224+ :: forall store
213− . Fn4 ObjectStore String (Array String) { unique :: Boolean, multiEntry :: Boolean } (Aff (idb :: IDB | e) Index)
225+ . Fn4 store String (Array String) { unique :: Boolean, multiEntry :: Boolean } (EffectFnAff Index)
214−
215
226
216foreign import _delete
227foreign import _delete
217− :: forall e
228+ :: forall store
218− . Fn2 ObjectStore KeyRange (Aff (idb :: IDB | e) Unit)
229+ . Fn2 store KeyRange (EffectFnAff Unit)
219−
220
230
221foreign import _deleteIndex
231foreign import _deleteIndex
222− :: forall e
232+ :: forall store
223− . Fn2 ObjectStore String (Aff (idb :: IDB | e) Unit)
233+ . Fn2 store String (EffectFnAff Unit)
224−
225
234
226foreign import _index
235foreign import _index
227− :: forall e
236+ :: forall store
228− . Fn2 ObjectStore String (Aff (idb :: IDB | e) Index)
237+ . Fn2 store String (EffectFnAff Index)
229−
230
238
231foreign import _indexNames
239foreign import _indexNames
232 :: ObjectStore
240 :: ObjectStore
233 -> Array String
241 -> Array String
234
242
235−
236foreign import _keyPath
243foreign import _keyPath
237 :: ObjectStore
244 :: ObjectStore
238 -> Array String
245 -> Array String
239
246
240−
241foreign import _name
247foreign import _name
242 :: ObjectStore
248 :: ObjectStore
243 -> String
249 -> String
244
250
245−
246foreign import _put
251foreign import _put
247− :: forall value e
252+ :: forall val store
248− . Fn3 ObjectStore value (Nullable Foreign) (Aff (idb :: IDB | e) Foreign)
253+ . Fn3 store val (Nullable Foreign) (EffectFnAff Foreign)
249−
250
254
251foreign import _transaction
255foreign import _transaction
252 :: ObjectStore
256 :: ObjectStore
src/Database/IndexedDB/IDBTransaction.js+38−18
@@ -1,25 +1,29 @@
1−exports._abort = function _abort(tx) {
1+export function _abort(tx) {
2− return function aff(success, error) {
2+ return function aff(error, success) {
3 try {
3 try {
4 tx.abort();
4 tx.abort();
5 success();
5 success();
6 } catch (e) {
6 } catch (e) {
7− error(new Error(e.name));
7+ error(e);
8 }
8 }
9+
10+ return function canceler(_, cancelerError) {
11+ cancelerError(new Error("Can't cancel IDB Effects"));
12+ };
9 };
13 };
10};
14};
11
15
12−exports._db = function _db(tx) {
16+export function _db(tx) {
13 return tx.db;
17 return tx.db;
14};
18};
15
19
16−exports._error = function _error(tx) {
20+export function _error(tx) {
17 return tx.error == null
21 return tx.error == null
18 ? null
22 ? null
19− : new Error(tx.error.name);
23+ : tx.error;
20};
24};
21
25
22−exports._mode = function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
26+export function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
23 if (tx.mode === 'readwrite') {
27 if (tx.mode === 'readwrite') {
24 return ReadWrite;
28 return ReadWrite;
25 } else if (tx.mode === 'versionchange') {
29 } else if (tx.mode === 'versionchange') {
@@ -29,44 +33,60 @@ exports._mode = function _mode(ReadOnly, ReadWrite, VersionChange, tx) {
29 return ReadOnly;
33 return ReadOnly;
30};
34};
31
35
32−exports._objectStore = function _objectStore(tx, name) {
36+export function _objectStore(tx, name) {
33− return function aff(success, error) {
37+ return function aff(error, success) {
34 try {
38 try {
35 const store = tx.objectStore(name);
39 const store = tx.objectStore(name);
36 success(store);
40 success(store);
37 } catch (e) {
41 } catch (e) {
38− error(new Error(e.name));
42+ error(e);
39 }
43 }
44+
45+ return function canceler(_, cancelerError) {
46+ cancelerError(new Error("Can't cancel IDB Effects"));
47+ };
40 };
48 };
41};
49};
42
50
43−exports._objectStoreNames = function _objectStoreNames(tx) {
51+export function _objectStoreNames(tx) {
44 return tx.objectStoreNames;
52 return tx.objectStoreNames;
45};
53};
46
54
47−exports._onAbort = function _onAbort(tx, f) {
55+export function _onAbort(tx, f) {
48− return function aff(success) {
56+ return function aff(error, success) {
49 tx.onabort = function onabort() {
57 tx.onabort = function onabort() {
50 f();
58 f();
51 };
59 };
52 success();
60 success();
61+
62+ return function canceler(_, cancelerError) {
63+ cancelerError(new Error("Can't cancel IDB Effects"));
64+ };
53 };
65 };
54};
66};
55
67
56−exports._onComplete = function _onComplete(tx, f) {
68+export function _onComplete(tx, f) {
57− return function aff(success) {
69+ return function aff(error, success) {
58 tx.oncomplete = function oncomplete() {
70 tx.oncomplete = function oncomplete() {
59 f();
71 f();
60 };
72 };
61 success();
73 success();
74+
75+ return function canceler(_, cancelerError) {
76+ cancelerError(new Error("Can't cancel IDB Effects"));
77+ };
62 };
78 };
63};
79};
64
80
65−exports._onError = function _onError(tx, f) {
81+export function _onError(tx, f) {
66− return function aff(success) {
82+ return function aff(error, success) {
67 tx.onerror = function onerror(e) {
83 tx.onerror = function onerror(e) {
68− f(new Error(e.target.error.name))();
84+ f(e.target.error)();
69 };
85 };
70 success();
86 success();
87+
88+ return function canceler(_, cancelerError) {
89+ cancelerError(new Error("Can't cancel IDB Effects"));
90+ };
71 };
91 };
72};
92};
src/Database/IndexedDB/IDBTransaction.purs+66−83
@@ -1,58 +1,66 @@
1−-- | A Transaction is used to interact with the data in a database.
1+-- | An object store is the primary storage mechanism for storing data in a database.
2−-- | Whenever data is read or written to the database it is done by using a transaction.
3module Database.IndexedDB.IDBTransaction
2module Database.IndexedDB.IDBTransaction
3+ -- * Interface
4+ ( abort
4− (class IDBTransaction, abort, objectStore
5+ , objectStore
6+
7+ -- * Attributes
5 , error
8 , error
6 , mode
9 , mode
10+
11+ -- * Event Handlers
7 , onAbort
12 , onAbort
8 , onComplete
13 , onComplete
9 , onError
14 , onError
10 ) where
15 ) where
11
16
12−import Prelude (Unit, (>>>))
13−
14−import Control.Monad.Aff (Aff)
15−import Control.Monad.Eff (Eff)
16−import Control.Monad.Eff.Exception (Error)
17−import Data.Function.Uncurried as Fn
18−import Data.Function.Uncurried (Fn2, Fn4)
19−import Data.Maybe (Maybe)
20−import Data.Nullable (Nullable, toMaybe)
21−
22−import Database.IndexedDB.Core (IDB, Database, ObjectStore, Transaction, TransactionMode(..))
17+import Database.IndexedDB.Core
23
18
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, ($), (<<<), (>>>))
24
28
25--------------------
29--------------------
26-- INTERFACES
30-- INTERFACES
27--
31--
28−-- | The IDBtransaction interface.
29−class IDBTransaction tx where
30− -- | Aborts the transaction. All pending requests will fail with a "AbortError"
31− -- | DOMException and all changes made to the database will be reverted.
32− abort
33− :: forall e
34− . tx
35− -> Aff (idb :: IDB | e) Unit
36−
37− -- | Returns an IDBObjectStore in the transaction's scope.
38− objectStore
39− :: forall e
40− . tx
41− -> String
42− -> Aff (idb :: IDB | e) ObjectStore
43
32
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
44
52
45--------------------
53--------------------
46-- ATTRIBUTES
54-- ATTRIBUTES
47--
55--
56+
48−-- | Returns the transaction’s connection.
57+--- | Returns the transaction’s connection.
49db
58db
50 :: Transaction
59 :: Transaction
51 -> Database
60 -> Database
52db =
61db =
53 _db
62 _db
54
63
55−
56-- | If the transaction was aborted, returns the error (a DOMException) providing the reason.
64-- | If the transaction was aborted, returns the error (a DOMException) providing the reason.
57error
65error
58 :: Transaction
66 :: Transaction
@@ -68,7 +76,6 @@ mode
68mode =
76mode =
69 Fn.runFn4 _mode ReadOnly ReadWrite VersionChange
77 Fn.runFn4 _mode ReadOnly ReadWrite VersionChange
70
78
71−
72-- | Returns a list of the names of object stores in the transaction’s scope.
79-- | Returns a list of the names of object stores in the transaction’s scope.
73-- | For an upgrade transaction this is all object stores in the database.
80-- | For an upgrade transaction this is all object stores in the database.
74objectStoreNames
81objectStoreNames
@@ -80,91 +87,67 @@ objectStoreNames =
80--------------------
87--------------------
81-- EVENT HANDLERS
88-- EVENT HANDLERS
82--
89--
90+
83-- | Event handler for the `abort` event.
91-- | Event handler for the `abort` event.
84onAbort
92onAbort
85− :: forall e e'
86− . Transaction
93+ :: Transaction
87− -> Eff ( | e') Unit
94+ -> Effect Unit
88− -> Aff (idb :: IDB | e) Unit
95+ -> Aff Unit
89−onAbort db f =
96+onAbort db' f =
90− Fn.runFn2 _onAbort db f
97+ fromEffectFnAff $ Fn.runFn2 _onAbort db' f
91−
92
98
93-- | Event handler for the `complete` event.
99-- | Event handler for the `complete` event.
94onComplete
100onComplete
95− :: forall e e'
96− . Transaction
101+ :: Transaction
97− -> Eff ( | e') Unit
102+ -> Effect Unit
98− -> Aff (idb :: IDB | e) Unit
103+ -> Aff Unit
99−onComplete db f =
104+onComplete db' f =
100− Fn.runFn2 _onComplete db f
105+ fromEffectFnAff $ Fn.runFn2 _onComplete db' f
101−
102
106
103-- | Event handler for the `error` event.
107-- | Event handler for the `error` event.
104onError
108onError
105− :: forall e e'
106− . Transaction
109+ :: Transaction
107− -> (Error -> Eff ( | e') Unit)
110+ -> (Error -> Effect Unit)
108− -> Aff (idb :: IDB | e) Unit
111+ -> Aff Unit
109onError db' f =
112onError db' f =
110− Fn.runFn2 _onError db' f
113+ fromEffectFnAff $ Fn.runFn2 _onError db' f
111−
112−
113−--------------------
114−-- INSTANCES
115−--
116−instance idbTransactionTransaction :: IDBTransaction Transaction where
117− objectStore tx name =
118− Fn.runFn2 _objectStore tx name
119−
120− abort =
121− _abort
122−
123
114
124--------------------
115--------------------
125-- FFI
116-- FFI
126--
117--
127−foreign import _abort
128− :: forall tx e
129− . tx
130− -> Aff (idb :: IDB | e) Unit
131
118
119+foreign import _abort
120+ :: forall tx
121+ . tx
122+ -> EffectFnAff Unit
132
123
133foreign import _db
124foreign import _db
134 :: Transaction
125 :: Transaction
135 -> Database
126 -> Database
136
127
137−
138foreign import _error
128foreign import _error
139 :: Transaction
129 :: Transaction
140 -> (Nullable Error)
130 -> (Nullable Error)
141
131
142−
143foreign import _mode
132foreign import _mode
144 :: Fn4 TransactionMode TransactionMode TransactionMode Transaction TransactionMode
133 :: Fn4 TransactionMode TransactionMode TransactionMode Transaction TransactionMode
145
134
146−
147foreign import _objectStoreNames
135foreign import _objectStoreNames
148 :: Transaction
136 :: Transaction
149 -> Array String
137 -> Array String
150
138
151−
152foreign import _objectStore
139foreign import _objectStore
153− :: forall tx e
140+ :: forall tx
154− . Fn2 tx String (Aff (idb :: IDB | e) ObjectStore)
141+ . Fn2 tx String (EffectFnAff ObjectStore)
155−
156
142
157foreign import _onAbort
143foreign import _onAbort
158− :: forall tx e e'
144+ :: forall tx
159− . Fn2 tx (Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
145+ . Fn2 tx (Effect Unit) (EffectFnAff Unit)
160−
161
146
162foreign import _onComplete
147foreign import _onComplete
163− :: forall tx e e'
148+ :: forall tx
164− . Fn2 tx (Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
149+ . Fn2 tx (Effect Unit) (EffectFnAff Unit)
165−
166
150
167foreign import _onError
151foreign import _onError
168− :: forall tx e e'
152+ :: forall tx
169− . Fn2 tx (Error -> Eff ( | e') Unit) (Aff (idb :: IDB | e) Unit)
153+ . Fn2 tx (Error -> Effect Unit) (EffectFnAff Unit)
170−
test/Main.purs+974−904
@@ -2,995 +2,1060 @@ module Test.Main where
2
2
3import Prelude
3import Prelude
4
4
5−import Control.Monad.Aff (Aff, launchAff, forkAff, delay, attempt)
5+import Data.Array (head, drop)
6−import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', modifyVar, peekVar, putVar, takeVar)
7−import Control.Monad.Aff.Console (log)
8−import Control.Monad.Eff (Eff)
9−import Control.Monad.Eff.Class (liftEff)
10−import Control.Monad.Eff.Exception (EXCEPTION, message)
11−import Control.Monad.Eff.Now (NOW, now)
12−import Data.Date as Date
6+import Data.Date as Date
13−import Data.DateTime as DateTime
7+import Data.DateTime (DateTime(..), Time(..))
14−import Data.DateTime (DateTime(..), Time(..))
15−import Data.DateTime.Instant (toDateTime)
8+import Data.DateTime.Instant (toDateTime)
16−import Data.Either (Either(..))
9+import Data.Either (Either(..))
17−import Data.Enum (toEnum)
10+import Data.Enum (toEnum)
18−import Data.Maybe (Maybe(..), isNothing, maybe)
11+import Data.Maybe (Maybe(..), isNothing, maybe)
19−import Data.Array (head, drop)
20−import Data.Time.Duration (Milliseconds(..))
12+import Data.Time.Duration (Milliseconds(..))
21−import Data.Traversable (traverse)
13+import Data.Traversable (traverse)
22−import Data.Tuple (Tuple(..), uncurry)
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)
23−import Test.Spec (describe, describeOnly, it)
32+import Test.Spec (describe, it)
24−import Test.Spec.Assertions (shouldEqual, fail)
33+import Test.Spec.Assertions (shouldEqual, fail)
25−import Test.Spec.Mocha (MOCHA, runMocha)
34+import Test.Spec.Reporter (consoleReporter)
26−
35+import Test.Spec.Runner (runSpec)
27−import Database.IndexedDB.Core
28−import Database.IndexedDB.IDBKey
29−import Database.IndexedDB.IDBCursor as IDBCursor
30−import Database.IndexedDB.IDBDatabase as IDBDatabase
31−import Database.IndexedDB.IDBFactory as IDBFactory
32−import Database.IndexedDB.IDBIndex as IDBIndex
33−import Database.IndexedDB.IDBKeyRange as IDBKeyRange
34−import Database.IndexedDB.IDBObjectStore as IDBObjectStore
35−import Database.IndexedDB.IDBTransaction as IDBTransaction
36−
37
36
38infixr 7 Tuple as :+:
37infixr 7 Tuple as :+:
39
38
40−launchAff' :: forall a e. Aff e a -> Eff (exception :: EXCEPTION | e) Unit
39+launchAff' :: forall a. Aff a -> Effect Unit
41−launchAff' aff =
40+launchAff' =
42− pure unit <* (launchAff aff)
41+ launchAff_ <<< void
42+
43+modifyAVar :: forall a. (a -> a) -> AVar a -> Aff Unit
44+modifyAVar fn v = do
45+ val <- AVar.take v
46+ AVar.put (fn val) v
43
47
44−-- main :: forall eff. Eff (now :: NOW, mocha :: MOCHA, idb :: IDB, exception :: EXCEPTION, avar :: AVAR | eff) Unit
48+main :: Effect Unit
45−main = runMocha do
49+main = do
50+ launchAff_ $ runSpec [ consoleReporter ] $ do
46− describe "IDBFactory" do
51+ describe "IDBFactory" do
47− let
52+ let
48 tearDown name version db = do
53 tearDown name version db = do
49 IDBDatabase.close db
54 IDBDatabase.close db
50 version' <- IDBFactory.deleteDatabase name
55 version' <- IDBFactory.deleteDatabase name
56+ liftEffect $ log $ show version'
51 version' `shouldEqual` version
57 version' `shouldEqual` version
52
58
53− it "open default" do
59+ it "open default" do
60+ let
54− let name = "db-default"
61+ name = "db-default"
55 version = 1
62 version = 1
56− db <- IDBFactory.open name Nothing
63+ db <- IDBFactory.open name Nothing
57− { onUpgradeNeeded : Nothing
64+ { onUpgradeNeeded: Nothing
58− , onBlocked : Nothing
65+ , onBlocked: Nothing
59− }
66+ }
60− IDBDatabase.name db `shouldEqual` name
67+ IDBDatabase.name db `shouldEqual` name
61− tearDown name version db
68+ tearDown name version db
62−
63
69
64− it "open specific version" do
70+ it "open specific version" do
71+ let
65− let name = "db-specific"
72+ name = "db-specific"
66 version = 14
73 version = 14
67− db <- IDBFactory.open name (Just version)
74+ db <- IDBFactory.open name (Just version)
68− { onUpgradeNeeded : Nothing
75+ { onUpgradeNeeded: Nothing
69− , onBlocked : Nothing
76+ , onBlocked: Nothing
70− }
77+ }
71− IDBDatabase.name db `shouldEqual` name
78+ IDBDatabase.name db `shouldEqual` name
72− tearDown name version db
79+ tearDown name version db
73−
74
80
75− it "open specific version -> close -> open latest" do
81+ it "open specific version -> close -> open latest" do
82+ let
76− let name = "db-latest"
83+ name = "db-latest"
77 version = 14
84 version = 14
78− db <- IDBFactory.open name (Just version)
85+ db01 <- IDBFactory.open name (Just version)
79− { onUpgradeNeeded : Nothing
86+ { onUpgradeNeeded: Nothing
80− , onBlocked : Nothing
87+ , onBlocked: Nothing
81− }
88+ }
82− IDBDatabase.name db `shouldEqual` name
89+ IDBDatabase.name db01 `shouldEqual` name
83− IDBDatabase.close db
90+ IDBDatabase.close db01
84− db <- IDBFactory.open name Nothing
91+ db02 <- IDBFactory.open name Nothing
85− { onUpgradeNeeded : Nothing
92+ { onUpgradeNeeded: Nothing
86− , onBlocked : Nothing
93+ , onBlocked: Nothing
87− }
94+ }
88− tearDown name version db
95+ tearDown name version db02
89−
96+
90−
91− it "open + onUpgradeNeed" do
97+ it "open + onUpgradeNeed" do
98+ let
92− let name = "db-upgrade-needed"
99+ name = "db-upgrade-needed"
93 version = 1
100 version = 1
94− callback var db _ = do
101+ callback (Tuple varName varVersion) db _ { oldVersion } = do
95− _ <- launchAff $ modifyVar (const $ IDBDatabase.name db) var
102+ _ <- launchAff $ modifyAVar (const $ IDBDatabase.name db) varName
103+ _ <- launchAff $ modifyAVar (const $ oldVersion) varVersion
96 pure unit
104 pure unit
97− var <- makeVar' "-"
105+ varName <- AVar.new "-"
106+ varVersion <- AVar.new (-1)
98− db <- IDBFactory.open name Nothing
107+ db <- IDBFactory.open name Nothing
99− { onUpgradeNeeded : Just (callback var)
108+ { onUpgradeNeeded: Just (callback (Tuple varName varVersion))
100− , onBlocked : Nothing
109+ , onBlocked: Nothing
101− }
110+ }
102− name <- peekVar var
111+ name' <- AVar.read varName
112+ version' <- AVar.read varVersion
103− name `shouldEqual` name
113+ name' `shouldEqual` name
114+ version' `shouldEqual` 0
104− tearDown name version db
115+ tearDown name version db
105−
116+
106−
107− it "open + onBlocked" do
117+ it "open + onBlocked" do
118+ let
108− let name = "db-blocked"
119+ name = "db-blocked"
109 version = 14
120 version = 14
110 callback var = do
121 callback var = do
111− _ <- launchAff $ modifyVar (const $ "db-blocked") var
122+ _ <- launchAff $ modifyAVar (const $ "db-blocked") var
112 pure unit
123 pure unit
113
124
114− var <- makeVar' "-"
125+ var <- AVar.new "-"
115− db01 <- IDBFactory.open name Nothing
126+ db01 <- IDBFactory.open name Nothing
116− { onUpgradeNeeded : Nothing
127+ { onUpgradeNeeded: Nothing
117− , onBlocked : Nothing
128+ , onBlocked: Nothing
118− }
129+ }
119− _ <- forkAff do
130+ _ <- forkAff do
120− delay (Milliseconds 100.0)
131+ delay (Milliseconds 100.0)
121− IDBDatabase.close db01
132+ IDBDatabase.close db01
122
133
123− db02 <- IDBFactory.open name (Just version)
134+ db02 <- IDBFactory.open name (Just version)
124− { onUpgradeNeeded : Nothing
135+ { onUpgradeNeeded: Nothing
125− , onBlocked : Just (callback var)
136+ , onBlocked: Just (callback var)
126− }
137+ }
127− name <- peekVar var
138+ name' <- AVar.read var
128− name `shouldEqual` name
139+ name' `shouldEqual` name
129− tearDown name version db02
140+ tearDown name version db02
130−
141+
131− describe "IDBKeyRange" do
142+ describe "IDBKeyRange" do
132− it "only(int)" do
143+ it "only(int)" do
144+ let
133− let key = 14
145+ key = 14
134 range = IDBKeyRange.only key
146 range = IDBKeyRange.only key
135− IDBKeyRange.includes range (toKey key) `shouldEqual` true
147+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
136
148
137− it "only(string)" do
149+ it "only(string)" do
150+ let
138− let key = "patate"
151+ key = "patate"
139 range = IDBKeyRange.only key
152 range = IDBKeyRange.only key
140− IDBKeyRange.includes range (toKey key) `shouldEqual` true
153+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
141
154
142− it "only(float)" do
155+ it "only(float)" do
156+ let
143− let key = 14.42
157+ key = 14.42
144 range = IDBKeyRange.only key
158 range = IDBKeyRange.only key
145− IDBKeyRange.includes range (toKey key) `shouldEqual` true
159+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
146
160
147− it "only(date)" do
161+ it "only(date)" do
162+ let
148− let mkey = DateTime
163+ mkey = DateTime
149 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
164 <$> (Date.canonicalDate <$> toEnum 2017 <*> toEnum 6 <*> toEnum 23)
150 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
165 <*> (Time <$> toEnum 17 <*> toEnum 59 <*> toEnum 34 <*> toEnum 42)
151
166
152− case mkey of
167+ case mkey of
153− Nothing ->
168+ Nothing ->
154− fail "unable to create datetime"
169+ fail "unable to create datetime"
155− Just key -> do
170+ Just key -> do
156− let range = IDBKeyRange.only key
171+ let range = IDBKeyRange.only key
157− IDBKeyRange.includes range (toKey key) `shouldEqual` true
172+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
158
173
159− it "only([int])" do
174+ it "only([int])" do
175+ let
160− let key = [14, 42]
176+ key = [ 14, 42 ]
161 range = IDBKeyRange.only key
177 range = IDBKeyRange.only key
162− IDBKeyRange.includes range (toKey key) `shouldEqual` true
178+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
163
179
164− it "only([string])" do
180+ it "only([string])" do
181+ let
165− let key = ["patate", "autruche"]
182+ key = [ "patate", "autruche" ]
166 range = IDBKeyRange.only key
183 range = IDBKeyRange.only key
167− IDBKeyRange.includes range (toKey key) `shouldEqual` true
184+ IDBKeyRange.includes range (toKey key) `shouldEqual` true
168
185
169− it "lowerBound(14, open)" do
186+ it "lowerBound(14, open)" do
187+ let
170− let key = 14
188+ key = 14
171− open = true
189+ open = true
172 range = IDBKeyRange.lowerBound key open
190 range = IDBKeyRange.lowerBound key open
173− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
191+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
174− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
192+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
175− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
193+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
176−
194+
177− it "lowerBound(14, close)" do
195+ it "lowerBound(14, close)" do
196+ let
178− let key = 14
197+ key = 14
179− open = false
198+ open = false
180 range = IDBKeyRange.lowerBound key open
199 range = IDBKeyRange.lowerBound key open
181− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
200+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` true
182− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
201+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
183− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
202+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` false
184−
203+
185− it "upperBound(14, open)" do
204+ it "upperBound(14, open)" do
205+ let
186− let key = 14
206+ key = 14
187− open = true
207+ open = true
188 range = IDBKeyRange.upperBound key open
208 range = IDBKeyRange.upperBound key open
189− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
209+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
190− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
210+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
191− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
211+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
192−
212+
193− it "upperBound(14, close)" do
213+ it "upperBound(14, close)" do
214+ let
194− let key = 14
215+ key = 14
195− open = false
216+ open = false
196 range = IDBKeyRange.upperBound key open
217 range = IDBKeyRange.upperBound key open
197− IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
218+ IDBKeyRange.includes range (toKey (key + 1)) `shouldEqual` false
198− IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
219+ IDBKeyRange.includes range (toKey key) `shouldEqual` (not open)
199− IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
220+ IDBKeyRange.includes range (toKey (key - 1)) `shouldEqual` true
200−
221+
201− it "bound(42, 14, open, open) => Nothing" do
222+ it "bound(42, 14, open, open) => Nothing" do
223+ let
202− let lower = 42
224+ lower = 42
203− upper = 14
225+ upper = 14
204 lowerOpen = true
226 lowerOpen = true
205 upperOpen = true
227 upperOpen = true
206− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
228+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
207− isNothing mrange `shouldEqual` true
229+ isNothing mrange `shouldEqual` true
208
230
209− it "bound(14, 42, open, open)" do
231+ it "bound(14, 42, open, open)" do
232+ let
210− let lower = 14
233+ lower = 14
211− upper = 42
234+ upper = 42
212 lowerOpen = true
235 lowerOpen = true
213 upperOpen = true
236 upperOpen = true
214− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
237+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
215− case mrange of
238+ case mrange of
216− Nothing ->
239+ Nothing ->
217− fail "invalid range provided"
240+ fail "invalid range provided"
218− Just range -> do
241+ Just range -> do
219− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
242+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
220− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
243+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
221− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
244+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
222− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
245+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
223− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
246+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
224− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
247+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
225−
248+
226− it "bound(14, 42, open, close)" do
249+ it "bound(14, 42, open, close)" do
250+ let
227− let lower = 14
251+ lower = 14
228− upper = 42
252+ upper = 42
229 lowerOpen = true
253 lowerOpen = true
230 upperOpen = false
254 upperOpen = false
231− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
255+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
232− case mrange of
256+ case mrange of
233− Nothing ->
257+ Nothing ->
234− fail "invalid range provided"
258+ fail "invalid range provided"
235− Just range -> do
259+ Just range -> do
236− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
260+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
237− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
261+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
238− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
262+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
239− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
263+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
240− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
264+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
241− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
265+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
242−
266+
243− it "bound(14, 42, close, open)" do
267+ it "bound(14, 42, close, open)" do
268+ let
244− let lower = 14
269+ lower = 14
245− upper = 42
270+ upper = 42
246 lowerOpen = false
271 lowerOpen = false
247 upperOpen = true
272 upperOpen = true
248− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
273+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
249− case mrange of
274+ case mrange of
250− Nothing ->
275+ Nothing ->
251− fail "invalid range provided"
276+ fail "invalid range provided"
252− Just range -> do
277+ Just range -> do
253− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
278+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
254− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
279+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
255− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
280+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
256− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
281+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
257− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
282+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
258− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
283+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
259−
284+
260− it "bound(14, 42, close, close)" do
285+ it "bound(14, 42, close, close)" do
286+ let
261− let lower = 14
287+ lower = 14
262− upper = 42
288+ upper = 42
263 lowerOpen = false
289 lowerOpen = false
264 upperOpen = false
290 upperOpen = false
265− mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
291+ mrange = IDBKeyRange.bound { lower, upper, lowerOpen, upperOpen }
266− case mrange of
292+ case mrange of
267− Nothing ->
293+ Nothing ->
268− fail "invalid range provided"
294+ fail "invalid range provided"
269− Just range -> do
295+ Just range -> do
270− IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
296+ IDBKeyRange.includes range (toKey (lower + 1)) `shouldEqual` true
271− IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
297+ IDBKeyRange.includes range (toKey (upper - 1)) `shouldEqual` true
272− IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
298+ IDBKeyRange.includes range (toKey (lower - 1)) `shouldEqual` false
273− IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
299+ IDBKeyRange.includes range (toKey (upper + 1)) `shouldEqual` false
274− IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
300+ IDBKeyRange.includes range (toKey lower) `shouldEqual` (not lowerOpen)
275− IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
301+ IDBKeyRange.includes range (toKey upper) `shouldEqual` (not upperOpen)
276−
302+
277− it "can access attributes of a range" do
303+ it "can access attributes of a range" do
278− let range = IDBKeyRange.lowerBound 14 false
304+ let range = IDBKeyRange.lowerBound 14 false
279− IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
305+ IDBKeyRange.lower range `shouldEqual` (Just $ toKey 14)
280− IDBKeyRange.upper range `shouldEqual` none
306+ IDBKeyRange.upper range `shouldEqual` none
281− IDBKeyRange.lowerOpen range `shouldEqual` false
307+ IDBKeyRange.lowerOpen range `shouldEqual` false
282− IDBKeyRange.upperOpen range `shouldEqual` true
308+ IDBKeyRange.upperOpen range `shouldEqual` true
283−
309+
284− describe "IDBDatabase" do
310+ describe "IDBDatabase" do
285− let
311+ let
286 tearDown db = do
312 tearDown db = do
287 IDBDatabase.close db
313 IDBDatabase.close db
288 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
314 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
289 pure unit
315 pure unit
290
316
291 setup storeParams = do
317 setup storeParams = do
318+ let
292− let onUpgradeNeeded var db _ = launchAff' do
319+ onUpgradeNeeded var db _ _ = launchAff' do
293− store <- IDBDatabase.createObjectStore db "store" storeParams
320+ store <- IDBDatabase.createObjectStore db "store" storeParams
294− _ <- putVar var { db, store }
321+ _ <- AVar.put { db, store } var
295− pure unit
322+ pure unit
296−
323+
297− var <- makeVar
324+ var <- AVar.empty
298− db <- IDBFactory.open "db" Nothing
325+ _ <- IDBFactory.open "db" Nothing
299− { onUpgradeNeeded : Just (onUpgradeNeeded var)
326+ { onUpgradeNeeded: Just (onUpgradeNeeded var)
300− , onBlocked : Nothing
327+ , onBlocked: Nothing
301 }
328 }
302
329
303− takeVar var
330+ AVar.take var
304−
331+
305− it "createObjectStore (keyPath: [], autoIncrement: true)" do
332+ it "createObjectStore (keyPath: [], autoIncrement: true)" do
306− { db, store } <- setup { keyPath: [], autoIncrement: true }
333+ { db, store } <- setup { keyPath: [], autoIncrement: true }
307− IDBObjectStore.name store `shouldEqual` "store"
334+ IDBObjectStore.name store `shouldEqual` "store"
308− IDBObjectStore.keyPath store `shouldEqual` []
335+ IDBObjectStore.keyPath store `shouldEqual` []
309− IDBObjectStore.autoIncrement store `shouldEqual` true
336+ IDBObjectStore.autoIncrement store `shouldEqual` true
310− IDBObjectStore.indexNames store `shouldEqual` []
337+ IDBObjectStore.indexNames store `shouldEqual` []
311− tearDown db
338+ tearDown db
312−
339+
313− it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
340+ it "createObjectStore (keyPath: [\"patate\"], autoIncrement: true)" do
314− { db, store } <- setup { keyPath: ["patate"], autoIncrement: true }
341+ { db, store } <- setup { keyPath: [ "patate" ], autoIncrement: true }
315− IDBObjectStore.name store `shouldEqual` "store"
342+ IDBObjectStore.name store `shouldEqual` "store"
316− IDBObjectStore.keyPath store `shouldEqual` ["patate"]
343+ IDBObjectStore.keyPath store `shouldEqual` [ "patate" ]
317− IDBObjectStore.autoIncrement store `shouldEqual` true
344+ IDBObjectStore.autoIncrement store `shouldEqual` true
318− IDBObjectStore.indexNames store `shouldEqual` []
345+ IDBObjectStore.indexNames store `shouldEqual` []
319− tearDown db
346+ tearDown db
320−
347+
321− it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
348+ it "createObjectStore (keyPath: [\"a\", \"b\"], autoIncrement: false)" do
322− { db, store } <- setup { keyPath: ["patate", "autruche"], autoIncrement: false }
349+ { db, store } <- setup { keyPath: [ "patate", "autruche" ], autoIncrement: false }
323− IDBObjectStore.name store `shouldEqual` "store"
350+ IDBObjectStore.name store `shouldEqual` "store"
324− IDBObjectStore.keyPath store `shouldEqual` ["patate", "autruche"]
351+ IDBObjectStore.keyPath store `shouldEqual` [ "patate", "autruche" ]
325− IDBObjectStore.autoIncrement store `shouldEqual` false
352+ IDBObjectStore.autoIncrement store `shouldEqual` false
326− IDBObjectStore.indexNames store `shouldEqual` []
353+ IDBObjectStore.indexNames store `shouldEqual` []
327− tearDown db
354+ tearDown db
328−
355+
329− it "deleteObjectStore" do
356+ it "deleteObjectStore" do
357+ let
330− let onUpgradeNeeded var db _ = launchAff' do
358+ onUpgradeNeeded var db _ _ = launchAff' do
331 _ <- IDBDatabase.deleteObjectStore db "store"
359 _ <- IDBDatabase.deleteObjectStore db "store"
332− putVar var true
360+ AVar.put true var
333−
361+
334− var <- makeVar
362+ var <- AVar.empty
335− { db, store } <- setup IDBObjectStore.defaultParameters
363+ { db } <- setup IDBDatabase.defaultParameters
336− IDBDatabase.close db
364+ IDBDatabase.close db
365+ db' <- IDBFactory.open "db" (Just 999)
337− db <- IDBFactory.open "db" (Just 999) { onUpgradeNeeded : Just (onUpgradeNeeded var)
366+ { onUpgradeNeeded: Just (onUpgradeNeeded var)
338− , onBlocked : Nothing
367+ , onBlocked: Nothing
339− }
368+ }
340− deleted <- takeVar var
369+ deleted <- AVar.take var
341− deleted `shouldEqual` true
370+ deleted `shouldEqual` true
342− tearDown db
371+ tearDown db'
343−
344
372
345− describe "IDBObjectStore" do
373+ describe "IDBObjectStore" do
346− let
374+ let
347 tearDown db = do
375 tearDown db = do
348 IDBDatabase.close db
376 IDBDatabase.close db
349 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
377 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
350 pure unit
378 pure unit
351
379
352 setup { storeParams, onUpgradeNeeded } = do
380 setup { storeParams, onUpgradeNeeded } = do
381+ let
353− let onUpgradeNeeded' var db _ = launchAff' do
382+ onUpgradeNeeded' var db _ _ = launchAff' do
354− store <- IDBDatabase.createObjectStore db "store" storeParams
383+ store <- IDBDatabase.createObjectStore db "store" storeParams
355− liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure store)
384+ liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure store)
356− putVar var { db, store }
385+ AVar.put { db, store } var
357−
386+
358− var <- makeVar
387+ var <- AVar.empty
359− db <- IDBFactory.open "db" Nothing
388+ _ <- IDBFactory.open "db" Nothing
360− { onUpgradeNeeded : Just (onUpgradeNeeded' var)
389+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
361− , onBlocked : Nothing
390+ , onBlocked: Nothing
362 }
391 }
363
392
364− takeVar var
393+ AVar.take var
365−
394+
366− it "add()" do
395+ it "add()" do
367− date <- liftEff $ toDateTime <$> now
396+ date <- liftEffect $ toDateTime <$> now
368− { db } <- setup
397+ { db } <- setup
369− { storeParams: { autoIncrement: true, keyPath: [] }
398+ { storeParams: { autoIncrement: true, keyPath: [] }
370− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
399+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
371− -- no key
400+ -- no key
372− key <- IDBObjectStore.add store "patate" none
401+ key <- IDBObjectStore.add store "patate" none
373− (toKey 1) `shouldEqual` key
402+ (toKey 1) `shouldEqual` key
374−
403+
375− -- int key
404+ -- int key
376− key <- IDBObjectStore.add store "patate" (Just 14)
405+ key' <- IDBObjectStore.add store "patate" (Just 14)
377− (toKey 14) `shouldEqual` key
406+ (toKey 14) `shouldEqual` key'
378−
407+
379− -- number key
408+ -- number key
380− key <- IDBObjectStore.add store "patate" (Just 14.42)
409+ key'' <- IDBObjectStore.add store "patate" (Just 14.42)
381− (toKey 14.42) `shouldEqual` key
410+ (toKey 14.42) `shouldEqual` key''
382−
411+
383− -- string key
412+ -- string key
384− key <- IDBObjectStore.add store "patate" (Just "key")
413+ key''' <- IDBObjectStore.add store "patate" (Just "key")
385− (toKey "key") `shouldEqual` key
414+ (toKey "key") `shouldEqual` key'''
386−
415+
387− -- date key
416+ -- date key
388− key <- IDBObjectStore.add store "patate" (Just date)
417+ key'''' <- IDBObjectStore.add store "patate" (Just date)
389− (toKey date) `shouldEqual` key
418+ (toKey date) `shouldEqual` key''''
390−
419+
391− -- array key
420+ -- array key
392− key <- IDBObjectStore.add store "patate" (Just $ toKey [14, 42])
421+ key''''' <- IDBObjectStore.add store "patate" (Just $ toKey [ 14, 42 ])
393− (toKey [14, 42]) `shouldEqual` key
422+ (toKey [ 14, 42 ]) `shouldEqual` key'''''
394− }
423+ }
395− tearDown db
424+ tearDown db
396−
425+
397− it "clear()" do
426+ it "clear()" do
398− { db } <- setup
427+ { db } <- setup
399− { storeParams: IDBObjectStore.defaultParameters
428+ { storeParams: IDBDatabase.defaultParameters
400− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
429+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
401− key <- IDBObjectStore.add store "patate" (Just 14)
430+ key <- IDBObjectStore.add store "patate" (Just 14)
402− _ <- IDBObjectStore.clear store
431+ _ <- IDBObjectStore.clear store
403− val <- IDBObjectStore.get store (IDBKeyRange.only key)
432+ val <- IDBObjectStore.get store (IDBKeyRange.only key)
404− val `shouldEqual` (Nothing :: Maybe String)
433+ val `shouldEqual` (Nothing :: Maybe String)
405− }
406− tearDown db
407−
408− it "count()" do
409− { db } <- setup
410− { storeParams: IDBObjectStore.defaultParameters
411− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
412− key <- IDBObjectStore.add store "patate" (Just 14)
413− key <- IDBObjectStore.add store "autruche" (Just 42)
414− n <- IDBObjectStore.count store Nothing
415− n `shouldEqual` 2
416− }
417− tearDown db
418−
419− it "getKey()" do
420− { db } <- setup
421− { storeParams: IDBObjectStore.defaultParameters
422− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
423− key <- IDBObjectStore.add store "patate" (Just 14)
424− mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 14)
425− mkey `shouldEqual` (Just key)
426−
427− mkey <- IDBObjectStore.getKey store (IDBKeyRange.only 42)
428− mkey `shouldEqual` none
429 }
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+ }
430− tearDown db
459+ tearDown db
431−
460+
432− it "getAllKeys()" do
461+ it "getAllKeys()" do
433− { db } <- setup
462+ { db } <- setup
434− { storeParams: IDBObjectStore.defaultParameters
463+ { storeParams: IDBDatabase.defaultParameters
435− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
464+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
436− key1 <- IDBObjectStore.add store "patate" (Just 14)
465+ key1 <- IDBObjectStore.add store "patate" (Just 14)
437− key2 <- IDBObjectStore.add store "autruche" (Just 42)
466+ key2 <- IDBObjectStore.add store "autruche" (Just 42)
438− key3 <- IDBObjectStore.add store 14 (Just 1337)
467+ key3 <- IDBObjectStore.add store 14 (Just 1337)
439−
468+
440− -- no bounds
469+ -- no bounds
441− keys <- IDBObjectStore.getAllKeys store Nothing Nothing
470+ keys <- IDBObjectStore.getAllKeys store Nothing Nothing
442− keys `shouldEqual` [key1, key2, key3]
471+ keys `shouldEqual` [ key1, key2, key3 ]
443−
472+
444− -- lower bound
473+ -- lower bound
445− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
474+ keys' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 14 true) Nothing
446− keys `shouldEqual` [key2, key3]
475+ keys' `shouldEqual` [ key2, key3 ]
447−
476+
448− -- upper bound
477+ -- upper bound
449− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
478+ keys'' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.upperBound 42 false) Nothing
450− keys `shouldEqual` [key1, key2]
479+ keys'' `shouldEqual` [ key1, key2 ]
451−
480+
452− -- count
481+ -- count
453− keys <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
482+ keys''' <- IDBObjectStore.getAllKeys store (Just $ IDBKeyRange.lowerBound 1 true) (Just 2)
454− keys `shouldEqual` [key1, key2]
483+ keys''' `shouldEqual` [ key1, key2 ]
455− }
484+ }
456− tearDown db
485+ tearDown db
457−
486+
458− it "openCursor()" do
487+ it "openCursor()" do
459− let cb =
488+ let
489+ cb =
460− { onSuccess : const $ pure unit
490+ { onSuccess: const $ pure unit
461− , onError : show >>> fail >>> launchAff'
491+ , onError: show >>> fail >>> launchAff'
462 , onComplete: pure unit
492 , onComplete: pure unit
463 }
493 }
464− { db } <- setup
494+ { db } <- setup
465− { storeParams: IDBObjectStore.defaultParameters
495+ { storeParams: IDBDatabase.defaultParameters
466− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
496+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
467− _ <- IDBObjectStore.openCursor store Nothing Next cb
497+ _ <- IDBObjectStore.openCursor store Nothing Next cb
468− _ <- IDBObjectStore.openCursor store Nothing NextUnique cb
498+ _ <- IDBObjectStore.openCursor store Nothing NextUnique cb
469− _ <- IDBObjectStore.openCursor store Nothing Prev cb
499+ _ <- IDBObjectStore.openCursor store Nothing Prev cb
470− _ <- IDBObjectStore.openCursor store Nothing PrevUnique cb
500+ _ <- IDBObjectStore.openCursor store Nothing PrevUnique cb
471− _ <- IDBObjectStore.openCursor store (Just $ IDBKeyRange.upperBound 1 true) Next cb
501+ _ <- IDBObjectStore.openCursor store (Just $ IDBKeyRange.upperBound 1 true) Next cb
472− pure unit
502+ pure unit
473− }
503+ }
474− tearDown db
504+ tearDown db
475
505
476− it "openKeyCursor()" do
506+ it "openKeyCursor()" do
477− let cb =
507+ let
508+ cb =
478− { onSuccess : const $ pure unit
509+ { onSuccess: const $ pure unit
479− , onError : show >>> fail >>> launchAff'
510+ , onError: show >>> fail >>> launchAff'
480 , onComplete: pure unit
511 , onComplete: pure unit
481 }
512 }
482− { db } <- setup
513+ { db } <- setup
483− { storeParams: IDBObjectStore.defaultParameters
514+ { storeParams: IDBDatabase.defaultParameters
484− , onUpgradeNeeded: Just $ \_ store -> launchAff' do
515+ , onUpgradeNeeded: Just $ \_ store -> launchAff' do
485− _ <- IDBObjectStore.openKeyCursor store Nothing Next cb
516+ _ <- IDBObjectStore.openKeyCursor store Nothing Next cb
486− _ <- IDBObjectStore.openKeyCursor store Nothing NextUnique cb
517+ _ <- IDBObjectStore.openKeyCursor store Nothing NextUnique cb
487− _ <- IDBObjectStore.openKeyCursor store Nothing Prev cb
518+ _ <- IDBObjectStore.openKeyCursor store Nothing Prev cb
488− _ <- IDBObjectStore.openKeyCursor store Nothing PrevUnique cb
519+ _ <- IDBObjectStore.openKeyCursor store Nothing PrevUnique cb
489− _ <- IDBObjectStore.openKeyCursor store (Just $ IDBKeyRange.lowerBound 1 true) Next cb
520+ _ <- IDBObjectStore.openKeyCursor store (Just $ IDBKeyRange.lowerBound 1 true) Next cb
490− pure unit
521+ pure unit
491− }
522+ }
492− tearDown db
523+ tearDown db
493
524
494− describe "IDBIndex" do
525+ describe "IDBIndex" do
495− let
526+ let
496 tearDown db = do
527 tearDown db = do
497 IDBDatabase.close db
528 IDBDatabase.close db
498 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
529 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
499 pure unit
530 pure unit
500
531
532+ setup
501− setup :: forall value e e'.
533+ :: forall value
502− { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
534+ . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
503− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
535+ , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
504− , values :: Array (Tuple value (Maybe Key))
536+ , values :: Array (Tuple value (Maybe Key))
505− , keyPath :: Array String
537+ , keyPath :: Array String
506− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Eff (idb :: IDB, avar :: AVAR, exception :: EXCEPTION | e') Unit)
538+ , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
539+ }
507− } -> Aff (idb :: IDB, avar :: AVAR | e) { db :: Database, index :: Index, store :: ObjectStore }
540+ -> Aff { db :: Database, index :: Index, store :: ObjectStore }
508 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
541 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
542+ let
509− let onUpgradeNeeded' var db tx = launchAff' do
543+ onUpgradeNeeded' var db tx _ = launchAff' do
510− store <- IDBDatabase.createObjectStore db "store" storeParams
544+ store <- IDBDatabase.createObjectStore db "store" storeParams
511− _ <- traverse (uncurry (IDBObjectStore.add store)) values
545+ _ <- traverse (uncurry (IDBObjectStore.add store)) values
512− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
546+ index <- IDBObjectStore.createIndex store "index" keyPath indexParams
513− liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
547+ liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
514− putVar var { db, index, store }
548+ AVar.put { db, index, store } var
515−
549+
516− var <- makeVar
550+ var <- AVar.empty
517− db <- IDBFactory.open "db" Nothing
551+ _ <- IDBFactory.open "db" Nothing
518− { onUpgradeNeeded : Just (onUpgradeNeeded' var)
552+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
519− , onBlocked : Nothing
553+ , onBlocked: Nothing
520 }
554 }
521− takeVar var
555+ AVar.take var
522−
556+
523−
524− it "returns an IDBIndex and the properties are set correctly" do
557+ it "returns an IDBIndex and the properties are set correctly" do
525− { db, index } <- setup
558+ { db, index } <- setup
526− { storeParams : IDBObjectStore.defaultParameters
559+ { storeParams: IDBDatabase.defaultParameters
527− , indexParams : IDBIndex.defaultParameters
560+ , indexParams: IDBObjectStore.defaultParameters
528− , onUpgradeNeeded : Nothing
561+ , onUpgradeNeeded: Nothing
529− , keyPath : []
562+ , keyPath: []
530− , values : []
563+ , values: []
531− }
564+ }
532− IDBIndex.name index `shouldEqual` "index"
565+ IDBIndex.name index `shouldEqual` "index"
533− IDBIndex.keyPath index `shouldEqual` []
566+ IDBIndex.keyPath index `shouldEqual` []
534− IDBIndex.unique index `shouldEqual` IDBIndex.defaultParameters.unique
567+ IDBIndex.unique index `shouldEqual` IDBObjectStore.defaultParameters.unique
535− IDBIndex.multiEntry index `shouldEqual` IDBIndex.defaultParameters.multiEntry
568+ IDBIndex.multiEntry index `shouldEqual` IDBObjectStore.defaultParameters.multiEntry
536− tearDown db
569+ tearDown db
537−
570+
538− it "attempt to create an index that requires unique values on an object store already contains duplicates" do
571+ it "attempt to create an index that requires unique values on an object store already contains duplicates" do
539− let onAbort var = launchAff' (putVar var true)
572+ let onAbort var = launchAff' (AVar.put true var)
540− txVar <- makeVar
573+ txVar <- AVar.empty
541− dbVar <- makeVar
574+ dbVar <- AVar.empty
542− res <- attempt $ setup
575+ res <- attempt $ setup
543− { storeParams : IDBObjectStore.defaultParameters
576+ { storeParams: IDBDatabase.defaultParameters
544− , indexParams : { unique : true
577+ , indexParams:
578+ { unique: true
545− , multiEntry : false
579+ , multiEntry: false
546− }
580+ }
547− , keyPath : ["indexedProperty"]
581+ , keyPath: [ "indexedProperty" ]
582+ , values:
548− , values : [ { indexedProperty: "bar" } :+: (Just $ toKey 1)
583+ [ { indexedProperty: "bar" } :+: (Just $ toKey 1)
549− , { indexedProperty: "bar" } :+: (Just $ toKey 2)
584+ , { indexedProperty: "bar" } :+: (Just $ toKey 2)
550− ]
585+ ]
551− , onUpgradeNeeded : Just $ \db tx _ -> launchAff' do
586+ , onUpgradeNeeded: Just $ \db tx _ -> launchAff' do
552− IDBTransaction.onAbort tx (onAbort txVar)
587+ IDBTransaction.onAbort tx (onAbort txVar)
553− IDBDatabase.onAbort db (onAbort dbVar)
588+ IDBDatabase.onAbort db (onAbort dbVar)
554− }
589+ }
555− case res of
590+ case res of
556− Right _ ->
591+ Right _ ->
557− fail "expected abort"
592+ fail "expected abort"
558− _ -> do
593+ _ -> do
559− shouldEqual true =<< takeVar txVar
594+ shouldEqual true =<< AVar.take txVar
560− shouldEqual true =<< takeVar dbVar
595+ shouldEqual true =<< AVar.take dbVar
561−
596+
562−
563− it "the index is usable right after being made" do
597+ it "the index is usable right after being made" do
564− { db } <- setup
598+ { db } <- setup
565− { storeParams : { keyPath : ["key"]
599+ { storeParams:
600+ { keyPath: [ "key" ]
566− , autoIncrement : false
601+ , autoIncrement: false
567− }
602+ }
568− , indexParams : IDBIndex.defaultParameters
603+ , indexParams: IDBObjectStore.defaultParameters
569− , keyPath : ["indexedProperty"]
604+ , keyPath: [ "indexedProperty" ]
605+ , values:
570− , values : [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
606+ [ { key: "key1", indexedProperty: "indexed_1" } :+: Nothing
571− , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
607+ , { key: "key2", indexedProperty: "indexed_2" } :+: Nothing
572− , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
608+ , { key: "key3", indexedProperty: "indexed_3" } :+: Nothing
573− ]
609+ ]
574− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
610+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
575− val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
611+ val <- IDBIndex.get index (IDBKeyRange.only "indexed_2")
576− ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
612+ ((\r -> r.key) <$> val) `shouldEqual` (Just $ toKey "key2")
577− }
613+ }
578− tearDown db
614+ tearDown db
579−
615+
580− it "empty keyPath" do
616+ it "empty keyPath" do
581− { db } <- setup
617+ { db } <- setup
582− { storeParams : IDBObjectStore.defaultParameters
618+ { storeParams: IDBDatabase.defaultParameters
583− , indexParams : IDBIndex.defaultParameters
619+ , indexParams: IDBObjectStore.defaultParameters
584− , keyPath : []
620+ , keyPath: []
621+ , values:
585− , values : [ "object_1" :+: (Just $ toKey 1)
622+ [ "object_1" :+: (Just $ toKey 1)
586− , "object_2" :+: (Just $ toKey 2)
623+ , "object_2" :+: (Just $ toKey 2)
587− , "object_3" :+: (Just $ toKey 3)
624+ , "object_3" :+: (Just $ toKey 3)
588− ]
625+ ]
589− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
626+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
590− val <- IDBIndex.get index (IDBKeyRange.only "object_3")
627+ val <- IDBIndex.get index (IDBKeyRange.only "object_3")
591− val `shouldEqual` (Just "object_3")
628+ val `shouldEqual` (Just "object_3")
592− }
629+ }
593− tearDown db
630+ tearDown db
594−
631+
595− it "index can be valid keys [date]" do
632+ it "index can be valid keys [date]" do
596− date <- liftEff $ toDateTime <$> now
633+ date <- liftEffect $ toDateTime <$> now
597− { db } <- setup
634+ { db } <- setup
598− { storeParams : { keyPath: ["key"]
635+ { storeParams:
636+ { keyPath: [ "key" ]
599− , autoIncrement: false
637+ , autoIncrement: false
600− }
638+ }
601− , indexParams : IDBIndex.defaultParameters
639+ , indexParams: IDBObjectStore.defaultParameters
602− , keyPath : ["i"]
640+ , keyPath: [ "i" ]
641+ , values:
603− , values : [ { key: "date", i: (toKey date) } :+: Nothing
642+ [ { key: "date", i: (toKey date) } :+: Nothing
604− ]
643+ ]
605− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
644+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
606− val <- IDBIndex.get index (IDBKeyRange.only date)
645+ val <- IDBIndex.get index (IDBKeyRange.only date)
607− ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
646+ ((\r -> r.key) <$> val) `shouldEqual` (Just "date")
608− }
647+ }
609− tearDown db
648+ tearDown db
610−
649+
611− it "index can be valid keys [num]" do
650+ it "index can be valid keys [num]" do
612− let num = 14
651+ let num = 14
613− { db } <- setup
652+ { db } <- setup
614− { storeParams : { keyPath: ["key"]
653+ { storeParams:
654+ { keyPath: [ "key" ]
615− , autoIncrement: false
655+ , autoIncrement: false
616− }
656+ }
617− , indexParams : IDBIndex.defaultParameters
657+ , indexParams: IDBObjectStore.defaultParameters
618− , keyPath : ["i"]
658+ , keyPath: [ "i" ]
659+ , values:
619− , values : [ { key: "num", i: (toKey num) } :+: Nothing
660+ [ { key: "num", i: (toKey num) } :+: Nothing
620− ]
661+ ]
621− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
662+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
622− val <- IDBIndex.get index (IDBKeyRange.only num)
663+ val <- IDBIndex.get index (IDBKeyRange.only num)
623− ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
664+ ((\r -> r.key) <$> val) `shouldEqual` (Just "num")
624− }
665+ }
625− tearDown db
666+ tearDown db
626−
667+
627− it "index can be valid keys [array]" do
668+ it "index can be valid keys [array]" do
628− let array = ["patate", "autruche"]
669+ let array = [ "patate", "autruche" ]
629− { db } <- setup
670+ { db } <- setup
630− { storeParams : { keyPath: ["key"]
671+ { storeParams:
672+ { keyPath: [ "key" ]
631− , autoIncrement: false
673+ , autoIncrement: false
632− }
674+ }
633− , indexParams : IDBIndex.defaultParameters
675+ , indexParams: IDBObjectStore.defaultParameters
634− , keyPath : ["i"]
676+ , keyPath: [ "i" ]
677+ , values:
635− , values : [ { key: "array", i: (toKey array) } :+: Nothing
678+ [ { key: "array", i: (toKey array) } :+: Nothing
636− ]
679+ ]
637− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
680+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
638− val <- IDBIndex.get index (IDBKeyRange.only array)
681+ val <- IDBIndex.get index (IDBKeyRange.only array)
639− ((\r -> r.key) <$> val) `shouldEqual` (Just "array")
682+ ((\r -> r.key) <$> val) `shouldEqual` (Just "array")
640− }
683+ }
641− tearDown db
684+ tearDown db
642−
685+
643− it "openKeyCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
686+ it "openKeyCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
644− res <- attempt $ setup
687+ res <- attempt $ setup
645− { storeParams : { keyPath: ["key"], autoIncrement: false }
688+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
646− , indexParams : IDBIndex.defaultParameters
689+ , indexParams: IDBObjectStore.defaultParameters
647− , keyPath : ["indexedProperty"]
690+ , keyPath: [ "indexedProperty" ]
691+ , values:
648− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
692+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
649− ]
693+ ]
650− , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
694+ , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
651− let cb =
695+ let
696+ cb =
652− { onSuccess : const $ pure unit
697+ { onSuccess: const $ pure unit
653− , onError : show >>> fail >>> launchAff'
698+ , onError: show >>> fail >>> launchAff'
654 , onComplete: pure unit
699 , onComplete: pure unit
655 }
700 }
656− IDBTransaction.onAbort tx (pure unit)
701+ IDBTransaction.onAbort tx (pure unit)
657− IDBDatabase.onAbort db (pure unit)
702+ IDBDatabase.onAbort db (pure unit)
658− IDBTransaction.abort tx
703+ IDBTransaction.abort tx
659− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
704+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
660− case cursor of
705+ case cursor of
661− Right _ -> fail "expected InvalidStateError"
706+ Right _ -> fail "expected InvalidStateError"
662− Left err -> message err `shouldEqual` "InvalidStateError"
707+ Left err -> name err `shouldEqual` "InvalidStateError"
663− }
708+ }
664− case res of
709+ case res of
665− Right _ -> fail "expected InvalidStateError"
710+ Right _ -> fail "expected InvalidStateError"
666− _ -> pure unit
711+ _ -> pure unit
667−
712+
668− it "openKeyCursor() - throw TransactionInactiveError on aborted transaction" do
713+ it "openKeyCursor() - throw TransactionInactiveError on aborted transaction" do
669− { db } <- setup
714+ { db } <- setup
670− { storeParams : { keyPath: ["key"], autoIncrement: false }
715+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
671− , indexParams : IDBIndex.defaultParameters
716+ , indexParams: IDBObjectStore.defaultParameters
672− , keyPath : ["indexedProperty"]
717+ , keyPath: [ "indexedProperty" ]
718+ , values:
673− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
719+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
674− ]
720+ ]
675− , onUpgradeNeeded : Nothing
721+ , onUpgradeNeeded: Nothing
676− }
722+ }
677− let cb =
723+ let
724+ cb =
678− { onSuccess : const $ pure unit
725+ { onSuccess: const $ pure unit
679− , onError : show >>> fail >>> launchAff'
726+ , onError: show >>> fail >>> launchAff'
680 , onComplete: pure unit
727 , onComplete: pure unit
681 }
728 }
682− tx <- IDBDatabase.transaction db ["store"] ReadOnly
729+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
683− store <- IDBTransaction.objectStore tx "store"
730+ store <- IDBTransaction.objectStore tx "store"
684− index <- IDBObjectStore.index store "index"
731+ index <- IDBObjectStore.index store "index"
685− IDBTransaction.onAbort tx (pure unit)
732+ IDBTransaction.onAbort tx (pure unit)
686− IDBTransaction.abort tx
733+ IDBTransaction.abort tx
687− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
734+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
688− case cursor of
735+ case cursor of
689− Right _ -> fail "expected TransactionInactiveError"
736+ Right _ -> fail "expected TransactionInactiveError"
690− Left err -> message err `shouldEqual` "TransactionInactiveError"
737+ Left err -> name err `shouldEqual` "TransactionInactiveError"
691−
738+
692− tearDown db
739+ tearDown db
693−
740+
694− it "openKeyCursor() - throw InvalidStateError when the index is deleted" do
741+ it "openKeyCursor() - throw InvalidStateError when the index is deleted" do
695− { db } <- setup
742+ { db } <- setup
696− { storeParams : { keyPath: ["key"], autoIncrement: false }
743+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
697− , indexParams : IDBIndex.defaultParameters
744+ , indexParams: IDBObjectStore.defaultParameters
698− , keyPath : ["indexedProperty"]
745+ , keyPath: [ "indexedProperty" ]
746+ , values:
699− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
747+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
700− ]
748+ ]
701− , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
749+ , onUpgradeNeeded: Just $ \_ tx index -> launchAff' do
702− let cb =
750+ let
751+ cb =
703− { onSuccess : const $ pure unit
752+ { onSuccess: const $ pure unit
704− , onError : show >>> fail >>> launchAff'
753+ , onError: show >>> fail >>> launchAff'
705 , onComplete: pure unit
754 , onComplete: pure unit
706 }
755 }
707− store <- IDBTransaction.objectStore tx "store"
756+ store <- IDBTransaction.objectStore tx "store"
708− IDBObjectStore.deleteIndex store "index"
757+ IDBObjectStore.deleteIndex store "index"
709− cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
758+ cursor <- attempt $ IDBIndex.openKeyCursor index Nothing Next cb
710− case cursor of
759+ case cursor of
711− Right _ -> fail "expected InvalidStateError"
760+ Right _ -> fail "expected InvalidStateError"
712− Left err -> message err `shouldEqual` "InvalidStateError"
761+ Left err -> name err `shouldEqual` "InvalidStateError"
713− }
762+ }
714−
763+
715− tearDown db
764+ tearDown db
716−
765+
717− it "openCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
766+ it "openCursor() - throw InvalidStateError on index deleted by aborted upgrade" do
718− res <- attempt $ setup
767+ res <- attempt $ setup
719− { storeParams : { keyPath: ["key"], autoIncrement: false }
768+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
720− , indexParams : IDBIndex.defaultParameters
769+ , indexParams: IDBObjectStore.defaultParameters
721− , keyPath : ["indexedProperty"]
770+ , keyPath: [ "indexedProperty" ]
771+ , values:
722− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
772+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
723− ]
773+ ]
724− , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
774+ , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
725− let cb =
775+ let
776+ cb =
726− { onSuccess : const $ pure unit
777+ { onSuccess: const $ pure unit
727− , onError : show >>> fail >>> launchAff'
778+ , onError: show >>> fail >>> launchAff'
728 , onComplete: pure unit
779 , onComplete: pure unit
729 }
780 }
730− IDBTransaction.onAbort tx (pure unit)
781+ IDBTransaction.onAbort tx (pure unit)
731− IDBDatabase.onAbort db (pure unit)
782+ IDBDatabase.onAbort db (pure unit)
732− IDBTransaction.abort tx
783+ IDBTransaction.abort tx
733− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
784+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
734− case cursor of
785+ case cursor of
735− Right _ -> fail "expected InvalidStateError"
786+ Right _ -> fail "expected InvalidStateError"
736− Left err -> message err `shouldEqual` "InvalidStateError"
787+ Left err -> name err `shouldEqual` "InvalidStateError"
737− }
788+ }
738− case res of
789+ case res of
739− Right _ -> fail "expected InvalidStateError"
790+ Right _ -> fail "expected InvalidStateError"
740− _ -> pure unit
791+ _ -> pure unit
741−
792+
742− it "openCursor() - throw TransactionInactiveError on aborted transaction" do
793+ it "openCursor() - throw TransactionInactiveError on aborted transaction" do
743− { db } <- setup
794+ { db } <- setup
744− { storeParams : { keyPath: ["key"], autoIncrement: false }
795+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
745− , indexParams : IDBIndex.defaultParameters
796+ , indexParams: IDBObjectStore.defaultParameters
746− , keyPath : ["indexedProperty"]
797+ , keyPath: [ "indexedProperty" ]
798+ , values:
747− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
799+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
748− ]
800+ ]
749− , onUpgradeNeeded : Nothing
801+ , onUpgradeNeeded: Nothing
750− }
802+ }
751− let cb =
803+ let
804+ cb =
752− { onSuccess : const $ pure unit
805+ { onSuccess: const $ pure unit
753− , onError : show >>> fail >>> launchAff'
806+ , onError: show >>> fail >>> launchAff'
754 , onComplete: pure unit
807 , onComplete: pure unit
755 }
808 }
756− tx <- IDBDatabase.transaction db ["store"] ReadOnly
809+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
757− store <- IDBTransaction.objectStore tx "store"
810+ store <- IDBTransaction.objectStore tx "store"
758− index <- IDBObjectStore.index store "index"
811+ index <- IDBObjectStore.index store "index"
759− IDBTransaction.onAbort tx (pure unit)
812+ IDBTransaction.onAbort tx (pure unit)
760− IDBTransaction.abort tx
813+ IDBTransaction.abort tx
761− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
814+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
762− case cursor of
815+ case cursor of
763− Right _ -> fail "expected TransactionInactiveError"
816+ Right _ -> fail "expected TransactionInactiveError"
764− Left err -> message err `shouldEqual` "TransactionInactiveError"
817+ Left err -> name err `shouldEqual` "TransactionInactiveError"
765−
818+
766− tearDown db
819+ tearDown db
767−
820+
768− it "openCursor() - throw InvalidStateError when the index is deleted" do
821+ it "openCursor() - throw InvalidStateError when the index is deleted" do
769− { db } <- setup
822+ { db } <- setup
770− { storeParams : { keyPath: ["key"], autoIncrement: false }
823+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
771− , indexParams : IDBIndex.defaultParameters
824+ , indexParams: IDBObjectStore.defaultParameters
772− , keyPath : ["indexedProperty"]
825+ , keyPath: [ "indexedProperty" ]
826+ , values:
773− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
827+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
774− ]
828+ ]
775− , onUpgradeNeeded : Just $ \db tx index -> launchAff' do
829+ , onUpgradeNeeded: Just $ \db tx index -> launchAff' do
776− let cb =
830+ let
831+ cb =
777− { onSuccess : const $ pure unit
832+ { onSuccess: const $ pure unit
778− , onError : show >>> fail >>> launchAff'
833+ , onError: show >>> fail >>> launchAff'
779 , onComplete: pure unit
834 , onComplete: pure unit
780 }
835 }
781− store <- IDBTransaction.objectStore tx "store"
836+ store <- IDBTransaction.objectStore tx "store"
782− IDBObjectStore.deleteIndex store "index"
837+ IDBObjectStore.deleteIndex store "index"
783− cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
838+ cursor <- attempt $ IDBIndex.openCursor index Nothing Next cb
784− case cursor of
839+ case cursor of
785− Right _ -> fail "expected InvalidStateError"
840+ Right _ -> fail "expected InvalidStateError"
786− Left err -> message err `shouldEqual` "InvalidStateError"
841+ Left err -> name err `shouldEqual` "InvalidStateError"
787− }
842+ }
788−
843+
789− tearDown db
844+ tearDown db
790−
845+
791− it "getKey() - multiEntry - adding keys" do
846+ it "getKey() - multiEntry - adding keys" do
792− { db } <- setup
847+ { db } <- setup
793− { storeParams : IDBObjectStore.defaultParameters
848+ { storeParams: IDBDatabase.defaultParameters
794− , indexParams : { unique: false, multiEntry: true }
849+ , indexParams: { unique: false, multiEntry: true }
795− , keyPath : ["name"]
850+ , keyPath: [ "name" ]
851+ , values:
796− , values : [ { name: ["patate", "autruche"] } :+: (Just $ toKey 1)
852+ [ { name: [ "patate", "autruche" ] } :+: (Just $ toKey 1)
797− , { name: ["bob"] } :+: (Just $ toKey 2)
853+ , { name: [ "bob" ] } :+: (Just $ toKey 2)
798− ]
854+ ]
799− , onUpgradeNeeded : Just $ \_ _ index -> launchAff' do
855+ , onUpgradeNeeded: Just $ \_ _ index -> launchAff' do
800− key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
856+ key <- IDBIndex.getKey index (IDBKeyRange.only "patate")
801− key `shouldEqual` (Just $ toKey 1)
857+ key `shouldEqual` (Just $ toKey 1)
802−
858+
803− key <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
859+ key' <- IDBIndex.getKey index (IDBKeyRange.only "autruche")
804− key `shouldEqual` (Just $ toKey 1)
860+ key' `shouldEqual` (Just $ toKey 1)
805−
861+
806− key <- IDBIndex.getKey index (IDBKeyRange.only "bob")
862+ key'' <- IDBIndex.getKey index (IDBKeyRange.only "bob")
807− key `shouldEqual` (Just $ toKey 2)
863+ key'' `shouldEqual` (Just $ toKey 2)
808− }
864+ }
809− tearDown db
865+ tearDown db
810−
866+
811−
812− it "get() - returns the record with the first key in the range" do
867+ it "get() - returns the record with the first key in the range" do
813− { db } <- setup
868+ { db } <- setup
814− { storeParams : { keyPath: ["key"], autoIncrement: false }
869+ { storeParams: { keyPath: [ "key" ], autoIncrement: false }
815− , indexParams : IDBIndex.defaultParameters
870+ , indexParams: IDBObjectStore.defaultParameters
816− , keyPath : ["indexedProperty"]
871+ , keyPath: [ "indexedProperty" ]
872+ , values:
817− , values : [ { key: 14, indexedProperty: "patate" } :+: Nothing
873+ [ { key: 14, indexedProperty: "patate" } :+: Nothing
818− , { key: 42, indexedProperty: "autruche" } :+: Nothing
874+ , { key: 42, indexedProperty: "autruche" } :+: Nothing
819− , { key: 1337, indexedProperty: "baguette" } :+: Nothing
875+ , { key: 1337, indexedProperty: "baguette" } :+: Nothing
820− ]
876+ ]
821− , onUpgradeNeeded : Nothing
877+ , onUpgradeNeeded: Nothing
822− }
878+ }
823−
879+
824− tx <- IDBDatabase.transaction db ["store"] ReadOnly
880+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
825− store <- IDBTransaction.objectStore tx "store"
881+ store <- IDBTransaction.objectStore tx "store"
826− index <- IDBObjectStore.index store "index"
882+ index <- IDBObjectStore.index store "index"
827− val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
883+ val <- IDBIndex.get index (IDBKeyRange.lowerBound "autruche" false)
828− ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
884+ ((\r -> r.key) <$> val) `shouldEqual` (Just 42)
829−
885+
830− tearDown db
886+ tearDown db
831−
887+
832− describe "IDBCursor" do
888+ describe "IDBCursor" do
833− let
889+ let
834 tearDown db = do
890 tearDown db = do
835 IDBDatabase.close db
891 IDBDatabase.close db
836 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
892 _ <- IDBFactory.deleteDatabase (IDBDatabase.name db)
837 pure unit
893 pure unit
838
894
895+ setup
839− setup :: forall value e e'.
896+ :: forall value
840− { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
897+ . { storeParams :: { keyPath :: Array String, autoIncrement :: Boolean }
841− , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
898+ , indexParams :: { unique :: Boolean, multiEntry :: Boolean }
842− , values :: Array (Tuple value (Maybe Key))
899+ , values :: Array (Tuple value (Maybe Key))
843− , keyPath :: Array String
900+ , keyPath :: Array String
844− , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Eff (idb :: IDB, avar :: AVAR, exception :: EXCEPTION | e') Unit)
901+ , onUpgradeNeeded :: Maybe (Database -> Transaction -> Index -> Effect Unit)
902+ }
845− } -> Aff (idb :: IDB, avar :: AVAR | e) { db :: Database, index :: Index, store :: ObjectStore }
903+ -> Aff { db :: Database, index :: Index, store :: ObjectStore }
846 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
904 setup { storeParams, indexParams, values, keyPath, onUpgradeNeeded } = do
905+ let
847− let onUpgradeNeeded' var db tx = launchAff' do
906+ onUpgradeNeeded' var db tx _ = launchAff' do
848− store <- IDBDatabase.createObjectStore db "store" storeParams
907+ store <- IDBDatabase.createObjectStore db "store" storeParams
849− _ <- traverse (uncurry (IDBObjectStore.add store)) values
908+ _ <- traverse (uncurry (IDBObjectStore.add store)) values
850− index <- IDBObjectStore.createIndex store "index" keyPath indexParams
909+ index <- IDBObjectStore.createIndex store "index" keyPath indexParams
851− liftEff $ maybe (pure unit) id (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
910+ liftEffect $ maybe (pure unit) identity (onUpgradeNeeded <*> pure db <*> pure tx <*> pure index)
852− putVar var { db, index, store }
911+ AVar.put { db, index, store } var
853−
912+
854− var <- makeVar
913+ var <- AVar.empty
855− db <- IDBFactory.open "db" Nothing
914+ db <- IDBFactory.open "db" Nothing
856− { onUpgradeNeeded : Just (onUpgradeNeeded' var)
915+ { onUpgradeNeeded: Just (onUpgradeNeeded' var)
857− , onBlocked : Nothing
916+ , onBlocked: Nothing
858 }
917 }
859− takeVar var
918+ AVar.take var
860−
919+
861− it "continue() - iterate to the next record" do
920+ it "continue() - iterate to the next record" do
862− { db } <- setup
921+ { db } <- setup
863− { storeParams : IDBObjectStore.defaultParameters
922+ { storeParams: IDBDatabase.defaultParameters
864− , indexParams : IDBIndex.defaultParameters
923+ , indexParams: IDBObjectStore.defaultParameters
865− , keyPath : []
924+ , keyPath: []
925+ , values:
866− , values : [ "cupcake" :+: (Just $ toKey 4)
926+ [ "cupcake" :+: (Just $ toKey 4)
867− , "pancake" :+: (Just $ toKey 2)
927+ , "pancake" :+: (Just $ toKey 2)
868− , "pie" :+: (Just $ toKey 1)
928+ , "pie" :+: (Just $ toKey 1)
869− , "pie" :+: (Just $ toKey 3)
929+ , "pie" :+: (Just $ toKey 3)
870− ]
930+ ]
871− , onUpgradeNeeded: Nothing
931+ , onUpgradeNeeded: Nothing
872− }
932+ }
933+ let
873− let cb vdone vvals =
934+ cb vdone vvals =
874 { onComplete: launchAff' do
935 { onComplete: launchAff' do
875− putVar vdone unit
936+ AVar.put unit vdone
876
937
877− , onError: \error -> launchAff' do
938+ , onError: \error -> launchAff' do
878 fail $ "unexpected error: " <> show error
939 fail $ "unexpected error: " <> show error
879
940
880 , onSuccess: \cursor -> launchAff' do
941 , onSuccess: \cursor -> launchAff' do
881− vals <- takeVar vvals
942+ vals <- AVar.take vvals
882 pure (IDBCursor.value cursor) >>= shouldEqual (maybe "" _.v $ head vals)
943 pure (IDBCursor.value cursor) >>= shouldEqual (maybe "" _.v $ head vals)
883− IDBCursor.primaryKey cursor >>= shouldEqual (maybe (toKey 0) _.k $ head vals)
944+ IDBCursor.primaryKey cursor >>= shouldEqual (maybe (toKey 0) _.k $ head vals)
884− putVar vvals (drop 1 vals)
945+ AVar.put (drop 1 vals) vvals
885 IDBCursor.continue cursor none
946 IDBCursor.continue cursor none
886 }
947 }
887− vdone <- makeVar
948+ vdone <- AVar.empty
888− vvals <- makeVar'
949+ vvals <- AVar.new
889− [ { v: "pie" , k: toKey 1 }
950+ [ { v: "pie", k: toKey 1 }
890− , { v: "pancake", k: toKey 2 }
951+ , { v: "pancake", k: toKey 2 }
891− , { v: "pie" , k: toKey 3 }
952+ , { v: "pie", k: toKey 3 }
892− , { v: "cupcake", k: toKey 4 }
953+ , { v: "cupcake", k: toKey 4 }
893− ]
954+ ]
894− tx <- IDBDatabase.transaction db ["store"] ReadOnly
955+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
895− store <- IDBTransaction.objectStore tx "store"
956+ store <- IDBTransaction.objectStore tx "store"
896− IDBObjectStore.openCursor store Nothing Next (cb vdone vvals)
957+ IDBObjectStore.openCursor store Nothing Next (cb vdone vvals)
897− takeVar vdone
958+ AVar.take vdone
898− tearDown db
959+ tearDown db
899−
960+
900− it "continue() - attempt to iterate in the wrong direction" do
961+ it "continue() - attempt to iterate in the wrong direction" do
901− { db } <- setup
962+ { db } <- setup
902− { storeParams : IDBObjectStore.defaultParameters
963+ { storeParams: IDBDatabase.defaultParameters
903− , indexParams : IDBIndex.defaultParameters
964+ , indexParams: IDBObjectStore.defaultParameters
904− , keyPath : []
965+ , keyPath: []
966+ , values:
905− , values : [ "cupcake" :+: (Just $ toKey 4)
967+ [ "cupcake" :+: (Just $ toKey 4)
906− , "pancake" :+: (Just $ toKey 2)
968+ , "pancake" :+: (Just $ toKey 2)
907− , "pie" :+: (Just $ toKey 1)
969+ , "pie" :+: (Just $ toKey 1)
908− , "pie" :+: (Just $ toKey 3)
970+ , "pie" :+: (Just $ toKey 3)
909− ]
971+ ]
910− , onUpgradeNeeded: Nothing
972+ , onUpgradeNeeded: Nothing
911− }
973+ }
974+ let
912− let cb vdone =
975+ cb vdone =
913 { onComplete: launchAff' do
976 { onComplete: launchAff' do
914 fail $ "shouldn't complete"
977 fail $ "shouldn't complete"
915
978
916− , onError: \error -> launchAff' do
979+ , onError: \error -> launchAff' do
917 fail $ "unexpected error: " <> show error
980 fail $ "unexpected error: " <> show error
918
981
919 , onSuccess: \cursor -> launchAff' do
982 , onSuccess: \cursor -> launchAff' do
920 res <- attempt $ IDBCursor.continue cursor (Just 1)
983 res <- attempt $ IDBCursor.continue cursor (Just 1)
921 case res of
984 case res of
922− Left err -> do
985+ Left err -> do
923− message err `shouldEqual` "DataError"
986+ name err `shouldEqual` "DataError"
924− putVar vdone unit
987+ AVar.put unit vdone
925 Right _ -> do
988 Right _ -> do
926 fail "expected continue to fail"
989 fail "expected continue to fail"
927 }
990 }
928− vdone <- makeVar
991+ vdone <- AVar.empty
929− tx <- IDBDatabase.transaction db ["store"] ReadOnly
992+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
930− store <- IDBTransaction.objectStore tx "store"
993+ store <- IDBTransaction.objectStore tx "store"
931− IDBObjectStore.openCursor store Nothing Next (cb vdone)
994+ IDBObjectStore.openCursor store Nothing Next (cb vdone)
932− takeVar vdone
995+ AVar.take vdone
933− tearDown db
996+ tearDown db
934−
997+
935−
936− it "advance() - iterate cursor number of times specified by count" do
998+ it "advance() - iterate cursor number of times specified by count" do
937− { db } <- setup
999+ { db } <- setup
938− { storeParams : { keyPath: ["pKey"], autoIncrement: false }
1000+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
939− , indexParams : IDBIndex.defaultParameters
1001+ , indexParams: IDBObjectStore.defaultParameters
940− , keyPath : []
1002+ , keyPath: []
1003+ , values:
941− , values : [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1004+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
942− , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
1005+ , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
943− , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
1006+ , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
944− , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
1007+ , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
945− ]
1008+ ]
946− , onUpgradeNeeded: Nothing
1009+ , onUpgradeNeeded: Nothing
947− }
1010+ }
1011+ let
948− let cb vdone vjump =
1012+ cb vdone vjump =
949 { onComplete: launchAff' do
1013 { onComplete: launchAff' do
950− putVar vdone unit
1014+ AVar.put unit vdone
951
1015
952− , onError: \error -> launchAff' do
1016+ , onError: \error -> launchAff' do
953 fail $ "unexpected error: " <> show error
1017 fail $ "unexpected error: " <> show error
954
1018
955 , onSuccess: \cursor -> launchAff' do
1019 , onSuccess: \cursor -> launchAff' do
956− jump <- takeVar vjump
1020+ jump <- AVar.take vjump
957− if jump
1021+ if jump then do
958− then do
959− IDBCursor.advance cursor 3
1022+ IDBCursor.advance cursor 3
960− else do
1023+ else do
961− let value = IDBCursor.value cursor
1024+ let value = IDBCursor.value cursor
962− value.pKey `shouldEqual` "pkey_3"
1025+ value.pKey `shouldEqual` "pkey_3"
963− value.iKey `shouldEqual` "ikey_3"
1026+ value.iKey `shouldEqual` "ikey_3"
964− IDBCursor.continue cursor none
1027+ IDBCursor.continue cursor none
965− putVar vjump false
1028+ AVar.put false vjump
966 }
1029 }
967− vdone <- makeVar
1030+ vdone <- AVar.empty
968− vjump <- makeVar' true
1031+ vjump <- AVar.new true
969− tx <- IDBDatabase.transaction db ["store"] ReadOnly
1032+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
970− store <- IDBTransaction.objectStore tx "store"
1033+ store <- IDBTransaction.objectStore tx "store"
971− IDBObjectStore.openCursor store Nothing Next (cb vdone vjump)
1034+ IDBObjectStore.openCursor store Nothing Next (cb vdone vjump)
972− takeVar vdone
1035+ AVar.take vdone
973− tearDown db
1036+ tearDown db
974−
1037+
975− it "delete() - remove a record from the object store" do
1038+ it "delete() - remove a record from the object store" do
976− { db } <- setup
1039+ { db } <- setup
977− { storeParams : { keyPath: ["pKey"], autoIncrement: false }
1040+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
978− , indexParams : IDBIndex.defaultParameters
1041+ , indexParams: IDBObjectStore.defaultParameters
979− , keyPath : []
1042+ , keyPath: []
1043+ , values:
980− , values : [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1044+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
981− , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
1045+ , { pKey: "pkey_1", iKey: "ikey_1" } :+: Nothing
982− , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
1046+ , { pKey: "pkey_2", iKey: "ikey_2" } :+: Nothing
983− , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
1047+ , { pKey: "pkey_3", iKey: "ikey_3" } :+: Nothing
984− ]
1048+ ]
985− , onUpgradeNeeded: Nothing
1049+ , onUpgradeNeeded: Nothing
986− }
1050+ }
1051+ let
987− let cb vdone store =
1052+ cb vdone store =
988 { onComplete: launchAff' do
1053 { onComplete: launchAff' do
989 mval <- map _.pKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
1054 mval <- map _.pKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
990 mval `shouldEqual` (Nothing :: Maybe String)
1055 mval `shouldEqual` (Nothing :: Maybe String)
991− putVar vdone unit
1056+ AVar.put unit vdone
992
1057
993− , onError: \error -> launchAff' do
1058+ , onError: \error -> launchAff' do
994 fail $ "unexpected error: " <> show error
1059 fail $ "unexpected error: " <> show error
995
1060
996 , onSuccess: \cursor -> launchAff' do
1061 , onSuccess: \cursor -> launchAff' do
@@ -999,29 +1064,31 @@ main = runMocha do
999 IDBCursor.delete cursor
1064 IDBCursor.delete cursor
1000 IDBCursor.advance cursor 4
1065 IDBCursor.advance cursor 4
1001 }
1066 }
1002− vdone <- makeVar
1067+ vdone <- AVar.empty
1003− tx <- IDBDatabase.transaction db ["store"] ReadWrite
1068+ tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
1004− store <- IDBTransaction.objectStore tx "store"
1069+ store <- IDBTransaction.objectStore tx "store"
1005− IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1070+ IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1006− takeVar vdone
1071+ AVar.take vdone
1007− tearDown db
1072+ tearDown db
1008−
1073+
1009− it "update() - modify a record in the object store" do
1074+ it "update() - modify a record in the object store" do
1010− { db } <- setup
1075+ { db } <- setup
1011− { storeParams : { keyPath: ["pKey"], autoIncrement: false }
1076+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1012− , indexParams : IDBIndex.defaultParameters
1077+ , indexParams: IDBObjectStore.defaultParameters
1013− , keyPath : []
1078+ , keyPath: []
1079+ , values:
1014− , values : [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1080+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1015− ]
1081+ ]
1016− , onUpgradeNeeded: Nothing
1082+ , onUpgradeNeeded: Nothing
1017− }
1083+ }
1084+ let
1018− let cb vdone store =
1085+ cb vdone store =
1019 { onComplete: launchAff' do
1086 { onComplete: launchAff' do
1020 mval <- map _.iKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
1087 mval <- map _.iKey <$> IDBIndex.get store (IDBKeyRange.only "pkey_0")
1021 mval `shouldEqual` (Just "patate")
1088 mval `shouldEqual` (Just "patate")
1022− putVar vdone unit
1089+ AVar.put unit vdone
1023
1090
1024− , onError: \error -> launchAff' do
1091+ , onError: \error -> launchAff' do
1025 fail $ "unexpected error: " <> show error
1092 fail $ "unexpected error: " <> show error
1026
1093
1027 , onSuccess: \cursor -> launchAff' do
1094 , onSuccess: \cursor -> launchAff' do
@@ -1031,41 +1098,44 @@ main = runMocha do
1031 key `shouldEqual` toKey "pkey_0"
1098 key `shouldEqual` toKey "pkey_0"
1032 IDBCursor.advance cursor 4
1099 IDBCursor.advance cursor 4
1033 }
1100 }
1034− vdone <- makeVar
1101+ vdone <- AVar.empty
1035− tx <- IDBDatabase.transaction db ["store"] ReadWrite
1102+ tx <- IDBDatabase.transaction db [ "store" ] ReadWrite
1036− store <- IDBTransaction.objectStore tx "store"
1103+ store <- IDBTransaction.objectStore tx "store"
1037− IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1104+ IDBObjectStore.openCursor store Nothing Next (cb vdone store)
1038− takeVar vdone
1105+ AVar.take vdone
1039− tearDown db
1106+ tearDown db
1040−
1107+
1041− it "update() - throw ReadOnlyError after update on ReadOnly transaction" do
1108+ it "update() - throw ReadOnlyError after update on ReadOnly transaction" do
1042− { db } <- setup
1109+ { db } <- setup
1043− { storeParams : { keyPath: ["pKey"], autoIncrement: false }
1110+ { storeParams: { keyPath: [ "pKey" ], autoIncrement: false }
1044− , indexParams : IDBIndex.defaultParameters
1111+ , indexParams: IDBObjectStore.defaultParameters
1045− , keyPath : []
1112+ , keyPath: []
1113+ , values:
1046− , values : [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1114+ [ { pKey: "pkey_0", iKey: "ikey_0" } :+: Nothing
1047− ]
1115+ ]
1048− , onUpgradeNeeded: Nothing
1116+ , onUpgradeNeeded: Nothing
1049− }
1117+ }
1118+ let
1050− let cb vdone =
1119+ cb vdone =
1051 { onComplete: launchAff' do
1120 { onComplete: launchAff' do
1052 fail $ "shouldn't complete"
1121 fail $ "shouldn't complete"
1053
1122
1054− , onError: \error -> launchAff' do
1123+ , onError: \error -> launchAff' do
1055 fail $ "unexpected error: " <> show error
1124 fail $ "unexpected error: " <> show error
1056
1125
1057 , onSuccess: \cursor -> launchAff' do
1126 , onSuccess: \cursor -> launchAff' do
1058 res <- attempt $ IDBCursor.update cursor "patate"
1127 res <- attempt $ IDBCursor.update cursor "patate"
1059 case res of
1128 case res of
1060 Left err -> do
1129 Left err -> do
1061− message err `shouldEqual` "ReadOnlyError"
1130+ name err `shouldEqual` "ReadOnlyError"
1062− putVar vdone unit
1131+ AVar.put unit vdone
1063 Right _ ->
1132 Right _ ->
1064 fail $ "expected ReadOnlyError"
1133 fail $ "expected ReadOnlyError"
1065 }
1134 }
1066− vdone <- makeVar
1135+ vdone <- AVar.empty
1067− tx <- IDBDatabase.transaction db ["store"] ReadOnly
1136+ tx <- IDBDatabase.transaction db [ "store" ] ReadOnly
1068− store <- IDBTransaction.objectStore tx "store"
1137+ store <- IDBTransaction.objectStore tx "store"
1069− IDBObjectStore.openCursor store Nothing Next (cb vdone)
1138+ IDBObjectStore.openCursor store Nothing Next (cb vdone)
1070− takeVar vdone
1139+ AVar.take vdone
1071− tearDown db
1140+ tearDown db
1141+
yarn.locknew file+81
@@ -0,0 +1,81 @@
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"