Last active
December 17, 2022 20:00
-
-
Save ans-4175/d9b8055c40ff9dcafd86e463a9aba84a to your computer and use it in GitHub Desktop.
Implementation PouchyStore Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PouchStore from 'PouchStore'; | |
import config from 'config'; | |
class ImplementStore extends PouchStore { | |
get name() { | |
return this._name; | |
} | |
setName(userId) { | |
this._name = `db_${userId}`; | |
} | |
get urlRemote() { | |
return config.couchDBUrl; | |
} | |
get optionsRemote() { | |
return { | |
auth: config.couchDBAuth, | |
}; | |
} | |
} | |
export default ImplementStore; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import IPouchDB from 'pouchdb'; | |
export class PouchDB extends IPouchDB { | |
async getFailSafe(id) { | |
try { | |
const doc = await this.get(id); | |
return doc; | |
} catch (err) { | |
if (err.status === 404) { | |
return null; | |
} | |
throw err; | |
} | |
} | |
async update(id, obj) { | |
const doc = await this.getFailSafe(id) || { _id: id }; | |
Object.assign(doc, obj); | |
const info = await this.put(doc); | |
return info; | |
} | |
createId() { | |
let id = (new Date()).getTime().toString(16); | |
while (id.length < 32) { | |
id += Math.random().toString(16).split('.').pop(); | |
} | |
id = id.substr(0, 32); | |
id = id.replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, '$1-$2-$3-$4-$5'); | |
return id; | |
} | |
async getDocs() { | |
const result = await this.allDocs({ | |
include_docs: true, | |
}); | |
const docs = result.rows.map(row => row.doc); | |
return docs; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import PouchDB from 'PouchDB'; | |
export default class PouchStore { | |
constructor() { | |
// set default options | |
if (!('isUseData' in this)) { | |
this.isUseData = true; | |
} | |
if (!('isUseRemote' in this)) { | |
this.isUseRemote = true; | |
} | |
if (!('optionsRemote' in this)) { | |
this.optionsRemote = {}; | |
} | |
this.initializeProperties(); | |
} | |
initializeProperties() { | |
// initialize in-memory data | |
} | |
async initialize() { | |
// initalize the databases | |
this.dbLocal = new PouchDB(this.name, { auto_compaction: true }); | |
this.dbMeta = new PouchDB(`${PREFIX_META_DB}${this.name}`, { auto_compaction: true }); | |
if (this.isUseRemote) { | |
if (!this.urlRemote) { | |
throw new Error(`store's urlRemote should not be ${this.urlRemote}`); | |
} | |
this.dbRemote = new PouchDB(`${this.urlRemote}${this.name}`, this.optionsRemote); | |
} | |
// init metadata | |
this.dataMeta = await this.dbMeta.getFailSafe(ID_META_DOC) || this.dataMeta; | |
if (this.isUseRemote) { | |
// sync data local-remote | |
try { | |
await checkInternet(this.urlRemote); | |
await this.dbLocal.replicate.from(this.dbRemote); | |
await this.upload(); | |
} catch (err) { | |
console.log(err); | |
} | |
} | |
// init data from PouchDB to memory | |
const docs = await this.dbLocal.getDocs(); | |
if (this.single) { | |
this.data = docs.find(doc => doc._id === this.single) || this.data; | |
} else if (this.isUseData) { | |
this.data = docs.filter(doc => !('deletedAt' in doc) || doc.deletedAt === null); | |
this.sortData(this.data); | |
} | |
this.isInitialized = true; | |
if (this.single || this.isUseData) { | |
this.notifySubscribers(this.data); | |
} else { | |
this.notifySubscribers(docs); | |
} | |
this.watchRemote(); | |
this.watchLocal(); | |
} | |
async deinitialize() { | |
this.unwatchLocal(); | |
this.unwatchRemote(); | |
await this.dbLocal.close(); | |
await this.dbMeta.close(); | |
if (this.dbRemote) { | |
await this.dbRemote.close(); | |
} | |
this.initializeProperties(); | |
this.isInitialized = false; | |
} | |
updateMemory(doc) { | |
// update in memory data | |
} | |
sortData(data) { | |
// do no sorting, override this method to sort | |
} | |
async updateMeta(payload) { | |
// well explained | |
} | |
/* watch manager for local DB and remote DB */ | |
watchRemote() { | |
if (!this.isUseRemote) return; | |
this.handlerRemoteChange = this.dbLocal.replicate.from(this.dbRemote, { | |
live: true, | |
retry: true, | |
}).on('change', change => { | |
for (let doc of change.docs) { | |
this.changeFromRemote[doc._id] = true; | |
this.updateMemory(doc); | |
} | |
this.notifySubscribers(change.docs); | |
}).on('error', err => { | |
console.log(`${this.name}.from`, 'error', err); | |
}) | |
} | |
unwatchRemote() { | |
if (this.handlerRemoteChange) { | |
this.handlerRemoteChange.cancel(); | |
} | |
} | |
watchLocal() { | |
this.handlerLocalChange = this.dbLocal.changes({ | |
since: 'now', | |
live: true, | |
include_docs: true, | |
}).on('change', change => { | |
const doc = change.doc; | |
if (this.changeFromRemote[doc._id]) { | |
delete this.changeFromRemote[doc._id]; | |
} else { | |
this.updateMemory(doc); | |
this.notifySubscribers([ doc ]); | |
} | |
}).on('error', err => { | |
console.log(`${this.name}.changes`, 'error', err); | |
}); | |
} | |
unwatchLocal() { | |
if (this.handlerLocalChange) { | |
this.handlerLocalChange.cancel(); | |
} | |
} | |
/* data upload (from local DB to remote DB) */ | |
checkIsUploaded(doc) { | |
// well explained | |
} | |
async setUnuploaded(id, isUnuploaded=true) { | |
// well explained | |
} | |
countUnuploadeds() { | |
// well explained | |
} | |
async upload() { | |
if (!this.isUseRemote) return; | |
await checkInternet(this.urlRemote); | |
const unuploadeds = Object.keys(this.dataMeta.unuploadeds).map(_id => { | |
return { _id }; | |
}); | |
await this.dbLocal.replicate.to(this.dbRemote); | |
await this.updateMeta({ | |
tsUpload: new Date().toJSON(), | |
unuploadeds: {}, | |
}); | |
this.notifySubscribers(unuploadeds); | |
} | |
/* manipulation of array data (non-single) */ | |
async addItem(payload, user=null) { | |
// well explained | |
} | |
async addItemWithId(id, payload, user=null) { | |
// well explained | |
} | |
async editItem(id, payload, user=null) { | |
// well explained | |
} | |
async deleteItem(id, user=null) { | |
// well explained | |
} | |
/* manipulation of single data (non-array) */ | |
async editSingle(payload) { | |
// well explained | |
} | |
async deleteSingle() { | |
// well explained | |
} | |
/* subscription manager */ | |
subscribe(subscriber) { | |
// well explained | |
} | |
unsubscribe(subscriber) { | |
// well explained | |
} | |
notifySubscribers(docs) { | |
// well explained | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ImplementStore from 'ImplementStore'; | |
const store = new ImplementStore(); | |
// inisialisasi data | |
store.setName('user-id'); | |
store.initialize(); | |
// add data | |
store.addItem({ | |
data: null, | |
}) | |
// check unuploaded data | |
const countUnploaded = store.countUnuploadeds() | |
// upload data | |
store.upload(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment