Implement a wrapper around IndexedDB
This commit is contained in:
parent
f745cb22d1
commit
c4c50565b6
143
src/lib/looped_in/indexeddb.cljs
Normal file
143
src/lib/looped_in/indexeddb.cljs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
(ns looped-in.indexeddb
|
||||||
|
(:require [cljs.core.async :refer [go chan >!]]
|
||||||
|
[looped-in.logging :as log]))
|
||||||
|
|
||||||
|
(defn add-data
|
||||||
|
"Adds data to IndexedDB"
|
||||||
|
[db object-store data]
|
||||||
|
(let [channel (chan)
|
||||||
|
transaction (.transaction db (clj->js [object-store]) "readwrite")
|
||||||
|
store (.objectStore transaction object-store)
|
||||||
|
data-coll (if (coll? data) data [data])]
|
||||||
|
(doseq [datum data-coll]
|
||||||
|
(.add store datum))
|
||||||
|
(set! (.-onerror transaction)
|
||||||
|
(fn [event] (log/error "Error adding data to IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-oncomplete transaction)
|
||||||
|
(fn [event] (go (>! channel (.-result (.-target event))))))
|
||||||
|
channel))
|
||||||
|
|
||||||
|
(defn get-data
|
||||||
|
"Gets data from IndexedDB."
|
||||||
|
[db object-store index]
|
||||||
|
(let [channel (chan)
|
||||||
|
request (-> db
|
||||||
|
(.transaction (clj->js [object-store]))
|
||||||
|
(.objectStore objectStore)
|
||||||
|
(.get index))]
|
||||||
|
(set! (.-onerror request)
|
||||||
|
(fn [event] (log/error "Error getting data from IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-onsuccess request)
|
||||||
|
(fn [event] (go (>! channel (.-result (.-target event))))))
|
||||||
|
channel))
|
||||||
|
|
||||||
|
(defn update-data
|
||||||
|
"Updates data in IndexedDB.
|
||||||
|
`updated-values` is map of key-value pairs to update. It does not need to contain
|
||||||
|
every field in the object schema, just those to update."
|
||||||
|
[db object-store index updated-values]
|
||||||
|
(let [channel (chan)
|
||||||
|
store (-> db
|
||||||
|
(.transaction (clj->js [object-store]) "readwrite")
|
||||||
|
(.objectStore object-store))
|
||||||
|
get-request (.get store index)]
|
||||||
|
(set! (.-onerror get-request)
|
||||||
|
(fn [event] (log/error "Error getting data from IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-onsuccess get-request)
|
||||||
|
(fn [event]
|
||||||
|
(let [data (js->clj (.-result (.-target event)) :keywordize-keys true)
|
||||||
|
update-request (.put store (clj->js (merge data updated-values)))]
|
||||||
|
(set! (.-onerror update-request)
|
||||||
|
(fn [event] (log/error "Error updating data in IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-onsuccess update-request)
|
||||||
|
(fn [event] (go (>! channel (.-result (.-target event)))))))))
|
||||||
|
channel))
|
||||||
|
|
||||||
|
(defn delete-data
|
||||||
|
"Deletes data from IndexedDB"
|
||||||
|
[db object-store index]
|
||||||
|
(let [channel (chan)
|
||||||
|
request (-> db
|
||||||
|
(.transaction (clj->js [object-store]) "readwrite")
|
||||||
|
(.objectStore object-store)
|
||||||
|
(.delete index))]
|
||||||
|
(set! (.onerror request)
|
||||||
|
(fn [event] (log/error "Error deleting data from IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.onsuccess request)
|
||||||
|
(fn [event] (go (>! channel (.-result (.-target event))))))
|
||||||
|
channel))
|
||||||
|
|
||||||
|
(defn open-database
|
||||||
|
"Opens an IndexedDB database.
|
||||||
|
The database should have already been created."
|
||||||
|
([name] (open-database name 1))
|
||||||
|
([name version]
|
||||||
|
(let [channel (chan)
|
||||||
|
request (.open js/window.indexedDB name version)]
|
||||||
|
(set! (.-onerror request)
|
||||||
|
(fn [event] (log/error "Error opening IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-onsuccess request)
|
||||||
|
(fn [event] (go (>! channel (.-result (.-target event))))))
|
||||||
|
channel)))
|
||||||
|
|
||||||
|
(defn create-database
|
||||||
|
"Creates an IndexedDB database and returns a channel that resolves with a database instance.
|
||||||
|
If the database has already been created with the specified version,
|
||||||
|
just opens the existing one. `object-stores` is a sequence of object
|
||||||
|
store maps created via `looped-in.indexeddb/create-object-store`."
|
||||||
|
([name object-stores]
|
||||||
|
(create-database name 1 object-stores))
|
||||||
|
([name version object-stores]
|
||||||
|
(let [channel (chan)
|
||||||
|
request (.open js/window.indexedDB name version)]
|
||||||
|
(set! (.-onerror request)
|
||||||
|
(fn [event]
|
||||||
|
(log/error "Error opening IndexedDB: "
|
||||||
|
(.-errorCode (.-target event)))))
|
||||||
|
(set! (.-onupgradeneeded request)
|
||||||
|
(fn [event]
|
||||||
|
(let [db (.-result (.-target event))]
|
||||||
|
(doseq [object-store object-stores]
|
||||||
|
(let [store (.createObjectStore db
|
||||||
|
(:name object-store)
|
||||||
|
(clj->js
|
||||||
|
{:key-path
|
||||||
|
(:key-path object-store)
|
||||||
|
:auto-increment
|
||||||
|
(:auto-increment? object-store)}))]
|
||||||
|
(doseq [index (:indices object-store)]
|
||||||
|
(.createIndex store
|
||||||
|
(:name index)
|
||||||
|
(:key-path index)
|
||||||
|
(clj->js (:opts index)))))))))
|
||||||
|
(set! (.-onsuccess request)
|
||||||
|
(go (>! channel (.-result (.-target event)))))
|
||||||
|
channel)))
|
||||||
|
|
||||||
|
(defn create-object-store
|
||||||
|
"Creates an object store data structure.
|
||||||
|
`indices` is a sequence of index maps
|
||||||
|
created via `looped-in.indexeddb/create-index`."
|
||||||
|
([store-name key-path]
|
||||||
|
(create-object-store store-name key-path []))
|
||||||
|
([store-name key-path indices]
|
||||||
|
(create-object-store store-name key-path indices false))
|
||||||
|
([store-name key-path indices auto-increment?]
|
||||||
|
{:name store-name :key-path key-path :indices indices :auto-increment? auto-increment?}))
|
||||||
|
|
||||||
|
(defn create-index
|
||||||
|
"Creates an index for use with `looped-in.indexeddb/create-object-store`.
|
||||||
|
`opts` is a map of options. Valid keys are :unique and :multi-entry, as
|
||||||
|
documented at https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/createIndex."
|
||||||
|
([name]
|
||||||
|
(create-index name name))
|
||||||
|
([name key-path]
|
||||||
|
(create-index name key-path {}))
|
||||||
|
([name key-path opts]
|
||||||
|
{:name name :key-path key-path :opts opts}))
|
Loading…
Reference in New Issue
Block a user