(Legacy software - not maintained anymore due to many breaking changes in dependencies)
Indexed Database reactive (Rx) wrapper written in scala.js using monix, uPickle and uTest.
resolvers in ThisBuild ++= Seq(
Resolver.bintrayRepo("pragmaxim", "maven")
)
libraryDependencies ++= Seq("com.pragmaxim" %%% "scalajs-rx-idb" % "0.0.9")
Primarily it is trying to be :
In other words, doing complicated stuff with IndexedDb directly is not that easy as one might expect. I came to conclusion that IndexedDb is rather a db engine that is meant to be used by Databases built around it
NOTE
Struggles
There is lot to abstract over in regards to querying IDB, especially key autogeneration, key being on value's keypath, KeyRanges, Indexes, operations on Last and First record etc. I could use scala Marcos to generate the API based on DB Schema, but unfortunately I decided not to, there are just 4 methods that basically do everything based on type of input.
// v - either store Value OR (Key,Value) type v - type class abstracting over the possibility of key being on value keypath, autogenerated or explicitly specified
def add[I, C[X] <: Iterable[X]](values: C[I])(implicit p: StoreKeyPolicy[I], tx: Tx[C]): Observable[(K,V)]
// ^ - type constructor of any type that is iterable ^ - type class for ad-hoc polymorphism regarding transaction handling
// v - type constructor that might be either an Iterable or KeyRange of Keys
def get[C[_]](keys: C[K])(implicit e: Tx[C]): Observable[(K,V)]
// ^ - type class allows you to add a custom logic for the request, there is just an evidence for Iterable and KeyRange
// v - usually an observable of Key Value pairs is returned, delete just completes
def delete[C[_]](keys: C[K])(implicit e: Tx[C]): Observable[Nothing]
// update works similar to add except it supports KeyRange - beware you must supply KeyRange entries
def update[I, C[_]](input: C[I])(implicit p: StoreKeyPolicy[I], e: Tx[C]): Observable[(K,V)]
The best place to look at examples is IndexedDbSuite
Note that the crud operations accept either anything that is Iterable
or any com.pragmaxim.idb.Store.Key
working with iterables
val obj1 = Map("x" -> 0) // store values might be anything that upickle manages to serialize
val obj2 = Map("y" -> 1)
val db = IndexedDb( // you may create new db, open, upgrade or recreate existing one
new NewDb("dbName", db => db.createObjectStore("storeName", lit("autoIncrement" -> true)))
)
val store = db.openStore[Int,Map[String, Int]]("storeName") //declare Store's key and value type information
// db requests should be combined with `onCompleteNewTx` combinator which honors idb transaction boundaries
store.add(List(obj1, obj2)).onCompleteNewTx { appendTuples =>
assert(appendTuples.length == 2)
val (keys, values) = appendTuples.unzip
assert(values.head == Map("x" -> 0))
store.get(keys).onCompleteNewTx { getTuples =>
val (keys2, _) = getTuples.unzip
store.delete(keys2).onCompleteNewTx { empty =>
store.count.onCompleteNewTx { counts =>
assert(counts(0) == 0)
db.close()
}
}
}
}
val store = db.openStore[Int, Int](storeName)
store.add(1 to 10).onCompleteNewTx { tuples =>
store.delete(store.lastKey).onCompleteNewTx { empty =>
store.count.map { count =>
assert(count == 9)
}
store.delete(store.firstKey).onCompleteNewTx { empty =>
store.count.map { count =>
assert(count == 8)
}
store.delete(store.rangedKey(IDBKeyRange.bound(3,5), Direction.Prev)).onCompleteNewTx { empty =>
store.count.map { count =>
assert(count == 5)
}
db.close()
}
}
}
}
val db = IndexedDb(recreateDB(dbName))
val store = db.openStore[Int,AnInstance](dbName)
val index = store.index[String]("testIndex")
store.add(List(obj)).onCompleteNewTx { appendTuples =>
index.get(List("index")).onCompleteNewTx { tuples =>
db.close()
}
}