@oceans/indexdb
Version:
oceans indexdb
350 lines (278 loc) • 7.97 kB
JavaScript
import { merge } from './utils'
export const Router = {
collections: {},
register (prefix, name, indexs) {
if (!this.collections[prefix]) {
this.collections[prefix] = {}
}
this.collections[prefix][name] = { name, indexs }
},
getCollections (prefix) {
return this.collections[prefix]
}
}
export class Connect {
constructor (params) {
const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB
if (!indexedDB) {
throw new Error('Your browser is not support indexDB.')
}
this.settings = Object.assign({
dbName: '',
version: 1,
createObjectStoreOption: {
keyPath: 'id',
autoIncrement: true
},
collections: {}
}, params || {})
if (!this.settings.dbName) {
throw new Error('db name is required')
}
this.indexedDB = indexedDB
this.collections = this.settings.collections
this.db = null
this.events = {}
}
open () {
return new Promise((resolve, reject) => {
const dbInstance = this.indexedDB.open(this.settings.dbName, this.settings.version || 1)
dbInstance.onsuccess = (e) => {
this.db = dbInstance.result
Connect.db[this.settings.dbName] = {
db: this.db,
connectInstance: this
}
resolve(this.db)
}
dbInstance.onerror = (e) => {
const msg = e.currentTarget.error.message
reject(msg)
}
dbInstance.onupgradeneeded = (e) => {
const db = e.target.result
const collections = this.collections
Object.keys(collections).forEach((key) => {
const collection = collections[key]
if (!db.objectStoreNames.contains(collection.name)) {
const store = db.createObjectStore(
collection.name,
this.settings.createObjectStoreOption || {}
)
if (collection.indexs) {
collection.indexs.forEach((item) => {
store.createIndex(item.name, item.keyPath, item.options || {})
})
}
if (this.events.onupgradeneeded) {
this.events.onupgradeneeded(db)
}
console.log('current version : ', this.settings.version)
}
})
}
})
}
bind (name, cb) {
this.events[name] = cb
}
}
Connect.db = {}
export class Base {
constructor (struct, params) {
this.settings = merge({
db: null,
collectionName: '',
connectInstance: null
}, params || {}, true)
if (!this.settings.db) {
throw new Error('db is required')
}
if (!this.settings.collectionName) {
throw new Error('collection name is required')
}
if (!this.settings.connectInstance) {
throw new Error('connectInstance is required')
}
this.struct = struct
this.db = this.settings.db
this.events = {}
this.connectInstance = this.settings.connectInstance
}
bind (name, cb) {
this.events[name] = cb
}
getTransactionAndStore (isWrite) {
const collectionName = this.settings.collectionName
const transaction = this.db.transaction([collectionName], isWrite ? 'readwrite' : 'readonly')
const store = transaction.objectStore(collectionName)
return { transaction, store }
}
insert (docs) {
return new Promise((resolve, reject) => {
const db = this.db
if (!db) {
reject(new Error('db is not ready'))
return false
}
if (!docs || docs.length === 0) {
resolve(docs)
return false
}
let data = []
if (docs.constructor === Array) {
data = docs
} else {
data.push(docs)
}
const rs = this.getTransactionAndStore(true)
rs.transaction.oncomplete = (e) => {
resolve()
}
rs.transaction.onerror = (e) => {
reject(e.target.error.message)
}
const struct = this.struct
data.forEach((item) => {
const doc = merge(struct, item, true)
rs.store.add(doc)
})
})
}
get (key, value) {
return new Promise((resolve, reject) => {
if (!key) {
reject(new Error('key is required'))
return false
}
const rs = this.getTransactionAndStore()
const request = rs.store.index(key).get(value)
request.onsuccess = (e) => {
resolve(e.target.result)
}
request.onerror = (e) => {
reject(new Error(e.target.error.message))
}
})
}
list (key, value, option) {
return new Promise((resolve, reject) => {
const settings = Object.assign({
page: 0,
pageSize: 20,
sort: 'next' // next 正, prev 倒
}, option || {})
const docs = []
const IDBKeyRange = window.IDBKeyRange
let isAdvancing = true
let limit = settings.page === 0 ? -100 : settings.pageSize
let val = null
const rs = this.getTransactionAndStore()
let request = null
if (key) {
if (value instanceof IDBKeyRange) {
val = value
} else {
val = IDBKeyRange.only(value)
}
request = rs.store.index(key).openCursor(val, settings.sort)
} else {
request = rs.store.openCursor(null, settings.sort)
}
request.onsuccess = (e) => {
const cursor = e.target.result
if (cursor) {
const count = settings.page * settings.pageSize
if (isAdvancing && count > 0) {
cursor.advance(count)
isAdvancing = false
} else {
docs.push(cursor.value)
if (limit !== 0) {
limit--
cursor.continue()
}
}
} else {
let rs = docs
if (settings.page > 0) {
rs = Object.assign({
docs
}, settings)
}
resolve(rs)
}
}
request.onerror = (e) => {
reject(e.target.error.message)
}
})
}
delete (key, value) {
return new Promise((resolve, reject) => {
if (!key) {
reject(new Error('key is required'))
return false
}
if (typeof value === 'undefined') {
reject(new Error('value is require'))
return false
}
const rs = this.getTransactionAndStore(true)
const findOneRequest = rs.store.index(key).get(value)
findOneRequest.onsuccess = (e) => {
const info = e.target.result
if (!info) {
resolve('ok')
return false
}
const request = rs.store.delete(info[this.connectInstance.settings.keyPath])
request.onsuccess = () => {
resolve()
}
request.onerror = (e) => {
reject(e.target.error.message)
}
}
findOneRequest.onerror = (e) => {
reject(e.target.error.message)
}
})
}
update (key, value, updateInfo) {
return new Promise((resolve, reject) => {
if (!key) {
reject(new Error('key is required'))
return false
}
if (!value) {
reject(new Error('value is required'))
return false
}
if (!updateInfo) {
reject(new Error('updateInfo is required'))
return false
}
const rs = this.getTransactionAndStore(true)
const request = rs.store.index(key).get(value)
request.onsuccess = (e) => {
const doc = e.target.result
Object.keys(updateInfo).forEach((k) => {
if (typeof doc[k] !== 'undefined') {
doc[k] = updateInfo[k]
}
})
const req = rs.store.put(doc)
req.onsuccess = (e) => {
resolve('ok')
}
req.onerror = (e) => {
reject(e.target.error.message)
}
}
request.onerror = (e) => {
reject(e.target.error.message)
}
})
}
}