Skip to content

Commit

Permalink
refactor: extract cache from api
Browse files Browse the repository at this point in the history
  • Loading branch information
mediremi committed Feb 24, 2021
1 parent 10a5c69 commit 34d31e6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 212 deletions.
8 changes: 4 additions & 4 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2021-02-24T12:58:28.207Z\n"
"PO-Revision-Date: 2021-02-24T12:58:28.207Z\n"
"POT-Creation-Date: 2021-02-24T22:13:18.605Z\n"
"PO-Revision-Date: 2021-02-24T22:13:18.605Z\n"

msgid "Hello {{name}}"
msgid "An error has occurred."
msgstr ""

msgid "Welcome to DHIS2!"
msgid "Invalid JSON. Please fix all remaining issues and try again."
msgstr ""
1 change: 0 additions & 1 deletion src/components/utils/JSONEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export class JSONEditor extends Component {
}

updateValue(value) {
console.log('updateValue', value)
this.editor.set(sortObjectKeys(value))
}

Expand Down
3 changes: 0 additions & 3 deletions src/constants/apiHistoryActions.js

This file was deleted.

279 changes: 75 additions & 204 deletions src/utils/api.js
Original file line number Diff line number Diff line change
@@ -1,237 +1,108 @@
import { getInstance } from 'd2'
import { CREATED, DELETED } from '../constants/apiHistoryActions'
import { API_URL } from '../constants/apiUrls'

class Api {
/**
* @param url API endpoint url
* @param auth Authentication HTTP header content
*/
class Cache {
constructor() {
this.cache = []
this.ignoredStores = ['']
this.cache = Object.create(null)
}

getNamespaces() {
return getInstance().then(d2 =>
d2.dataStore
.getAll()
.then(response =>
response.filter(
value => this.ignoredStores.indexOf(value) === -1
)
)
)
clearNamespace(namespace) {
this.cache[namespace] = Object.create(null)
}

deleteNamespace(namespace) {
return getInstance().then(d2 =>
d2.dataStore.delete(namespace).then(response => {
this.cache[namespace] = []
return response
})
)
contains(namespace, key) {
return namespace in this.cache && key in this.cache[namespace]
}

getKeys(namespace) {
return getInstance()
.then(d2 => d2.dataStore.get(namespace))
.then(resName => resName.getKeys())
.catch(error => Promise.reject(error))
get(namespace, key) {
if (this.contains(namespace, key)) {
return this.cache[namespace][key]
}
}

/**
* @param namespace
* @param key
*/
getValue(namespace, key) {
const cache = this.cache

// check for cache hit
if (
cache[namespace] === undefined ||
cache[namespace][key] === undefined
) {
return this.getMetaData(namespace, key).then(result => {
const jsonLength = result.value.length
const val = JSON.parse(result.value)

// cache result
if (cache[namespace] === undefined) {
cache[namespace] = []
}
const ret = {
length: jsonLength,
value: val,
}
cache[namespace][key] = ret

return ret
})
set(namespace, key, value) {
if (!(namespace in this.cache)) {
this.cache[namespace] = Object.create(null)
}
this.cache[namespace][key] = value
}

return new Promise(resolve => {
resolve(cache[namespace][key])
})
delete(namespace, key) {
if (this.contains(namespace, key)) {
delete this.cache[namespace][key]
}
}
}

/**
* @param namespace
* @param key
*/
getMetaData(namespace, key) {
return getInstance()
.then(d2 => d2.dataStore.get(namespace, false))
.then(namespace => namespace.getMetaData(key))
class Api {
constructor() {
this.cache = new Cache()
}

/**
* @param namespace
* @param key
* @param value
*/
createValue(namespace, key, value) {
return getInstance()
.then(d2 => d2.dataStore.get(namespace))
.then(resName => resName.set(key, value, true))
.then(response => {
// cache value
if (this.cache[namespace] === undefined) {
this.cache[namespace] = []
}
const ret = {
length: 0,
value: value,
}
this.cache[namespace][key] = ret

return response
})
getNamespaces = async () => {
const d2 = await getInstance()
return d2.dataStore.getAll()
}

/**
* @param namespace
* @param key
* @param value
*/
updateValue(namespace, key, value) {
return getInstance()
.then(d2 => d2.dataStore.get(namespace))
.then(resName => resName.update(key, value))
.then(response => {
// cache value
if (this.cache[namespace] === undefined) {
this.cache[namespace] = []
}
this.cache[namespace][key] = { value }
return response
})
deleteNamespace = async namespace => {
const d2 = await getInstance()
const response = await d2.dataStore.delete(namespace)
this.cache.clearNamespace(namespace)
return response
}

deleteValue(namespace, key) {
return getInstance()
.then(d2 => d2.dataStore.get(namespace))
.then(resName => resName.delete(key))
.then(response => {
// delete cache value
if (
this.cache[namespace] !== undefined &&
this.cache[namespace][key] !== undefined
) {
delete this.cache[namespace][key]
}
return response
})
getKeys = async namespace => {
const d2 = await getInstance()
const resName = await d2.dataStore.get(namespace)
return resName.getKeys()
}

/**
* Updates the history of the namespace
* @param namespace
* @param key
* @param historyRecord
*/
updateNamespaceHistory(namespace, key, historyRecord) {
const namespaceHistoryRecord = {
name: namespace,
action: historyRecord.action,
date: new Date(),
user: historyRecord.user,
value: `Key '${key}' was ${historyRecord.action.toLowerCase()}.`,
getValue = async (namespace, key) => {
if (this.cache.contains(namespace, key)) {
return this.cache.get(namespace, key)
}

return this.getHistory(namespace)
.then(history => {
history.unshift(namespaceHistoryRecord)

if (historyRecord.action === DELETED) {
// special check for delete action
this.getKeys(namespace)
.then(response => {
if (response.length < 1) {
// last key in namespace was deleted, namespace got deleted too
history.unshift({
name: namespace,
action: DELETED,
date: new Date(),
user: historyRecord.user,
value: 'Namespace was deleted.',
})

delete this.cache[namespace]
}

this.updateValue('HISTORYSTORE', namespace, history)
})
.catch(e => {
console.error(e)
})
} else {
// create or update action
this.updateValue('HISTORYSTORE', namespace, history)
}
})
.catch(e => {
if (e.httpStatusCode === 404) {
// this history record is first
const value = [
{
name: namespace,
action: CREATED,
date: namespaceHistoryRecord.date,
user: historyRecord.user,
value: 'Namespace was created.',
},
]
return this.createValue(
'HISTORYSTORE',
namespace,
value,
false
).then(() => {
value.unshift(namespaceHistoryRecord)
this.updateValue('HISTORYSTORE', namespace, value)
})
}
})
const result = await this.getMetaData(namespace, key)
const jsonLength = result.value.length
const value = {
length: jsonLength,
value: JSON.parse(result.value),
}
this.cache.set(namespace, key, value)
return value
}

/**
* Make sure the response status code is 2xx
* @param response
*/
successOnly(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
}
return Promise.reject(response)
getMetaData = async (namespace, key) => {
const d2 = await getInstance()
const response = await d2.dataStore.get(namespace, false)
return response.getMetaData(key)
}

createValue = async (namespace, key, value) => {
const d2 = await getInstance()
const resName = await d2.dataStore.get(namespace)
const response = await resName.set(key, value, true)
this.cache.set(namespace, key, {
length: 0,
value,
})
return response
}

updateValue = async (namespace, key, value) => {
const d2 = await getInstance()
const resName = await d2.dataStore.get(namespace)
const response = await resName.update(key, value)
this.cache.set(namespace, key, { value })
return response
}

/**
* @param namespace
* @param key
*/
buildId(namespace, key) {
return encodeURIComponent(`${namespace}:${key}`)
deleteValue = async (namespace, key) => {
const d2 = await getInstance()
const resName = await d2.dataStore.get(namespace)
const response = await resName.delete(key)
this.cache.delete(namespace, key)
return response
}
}

Expand Down

0 comments on commit 34d31e6

Please sign in to comment.