auto set creation via arrays

This commit is contained in:
Daniel Lugo 2020-10-18 16:44:30 -04:00
parent b960a17855
commit 57aca4a95c
2 changed files with 72 additions and 17 deletions

View file

@ -1,10 +1,12 @@
/** /**
* @format * @format
*/ */
/* eslint-disable no-use-before-define */
// @ts-check // @ts-check
const { makePromise, Constants, Schema } = require('shock-common') const { makePromise, Constants, Schema } = require('shock-common')
const mapValues = require('lodash/mapValues') const mapValues = require('lodash/mapValues')
const Bluebird = require('bluebird') const Bluebird = require('bluebird')
const Gun = require('gun')
const { pubToEpub } = require('../contact-api/utils') const { pubToEpub } = require('../contact-api/utils')
const { const {
@ -16,6 +18,8 @@ const {
} = require('../Mediator') } = require('../Mediator')
/** /**
* @typedef {import('../contact-api/SimpleGUN').ValidDataValue} ValidDataValue * @typedef {import('../contact-api/SimpleGUN').ValidDataValue} ValidDataValue
* @typedef {import('./types').ValidRPCDataValue} ValidRPCDataValue
* @typedef {import('./types').RPCData} RPCData
*/ */
/** /**
@ -55,10 +59,11 @@ const deepDecryptIfNeeded = async (value, publicKey) => {
} }
/** /**
* @param {ValidDataValue} value * @param {ValidRPCDataValue} value
* @returns {Promise<ValidDataValue>} * @returns {Promise<ValidRPCDataValue>}
*/ */
const deepEncryptIfNeeded = async value => { // eslint-disable-next-line func-style
async function deepEncryptIfNeeded(value) {
const u = getUser() const u = getUser()
if (!u.is) { if (!u.is) {
@ -69,6 +74,10 @@ const deepEncryptIfNeeded = async value => {
return value return value
} }
if (Array.isArray(value)) {
return Promise.all(value.map(v => deepEncryptIfNeeded(v)))
}
const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR) const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR)
if (!pk) { if (!pk) {
@ -92,7 +101,7 @@ const deepEncryptIfNeeded = async value => {
/** /**
* @param {string} rawPath * @param {string} rawPath
* @param {ValidDataValue} value * @param {ValidRPCDataValue} value
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
const put = async (rawPath, value) => { const put = async (rawPath, value) => {
@ -125,10 +134,17 @@ const put = async (rawPath, value) => {
return _node return _node
})() })()
const encryptedIfNeededValue = await deepEncryptIfNeeded(value) const theValue = await deepEncryptIfNeeded(value)
if (Array.isArray(theValue)) {
await Promise.all(theValue.map(v => set(rawPath, v)))
} else if (Schema.isObj(theValue)) {
const writes = mapValues(theValue, (v, k) => put(`${rawPath}.${k}`, v))
await Bluebird.props(writes)
} /* is primitive */ else {
await makePromise((res, rej) => { await makePromise((res, rej) => {
node.put(encryptedIfNeededValue, ack => { node.put(/** @type {ValidDataValue} */ (theValue), ack => {
if (ack.err && typeof ack.err !== 'number') { if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err)) rej(new Error(ack.err))
} else { } else {
@ -136,14 +152,16 @@ const put = async (rawPath, value) => {
} }
}) })
}) })
}
} }
/** /**
* @param {string} rawPath * @param {string} rawPath
* @param {ValidDataValue} value * @param {ValidRPCDataValue} value
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
const set = async (rawPath, value) => { // eslint-disable-next-line func-style
async function set(rawPath, value) {
const [root, ...path] = rawPath.split('.') const [root, ...path] = rawPath.split('.')
const node = (() => { const node = (() => {
@ -173,10 +191,39 @@ const set = async (rawPath, value) => {
return _node return _node
})() })()
const encryptedIfNeededValue = await deepEncryptIfNeeded(value) const theValue = await deepEncryptIfNeeded(value)
if (Array.isArray(theValue)) {
// we'll create a set of sets
// @ts-expect-error
const uuid = Gun.text.random()
// here we are simulating the top-most set()
const subPath = rawPath + '.' + uuid
const writes = theValue.map(v => set(subPath, v))
await Promise.all(writes)
return uuid
} else if (Schema.isObj(theValue)) {
// @ts-expect-error
const uuid = Gun.text.random() // we'll handle UUID ourselves
// so we can use our own put()
const subPath = rawPath + '.' + uuid
await put(subPath, theValue)
return uuid
}
/* else is primitive */
const id = await makePromise((res, rej) => { const id = await makePromise((res, rej) => {
const subNode = node.set(encryptedIfNeededValue, ack => { const subNode = node.set(theValue, ack => {
if (ack.err && typeof ack.err !== 'number') { if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err)) rej(new Error(ack.err))
} else { } else {

View file

@ -0,0 +1,8 @@
import {Primitive} from '../contact-api/SimpleGUN'
export interface RPCData {
[K: string]: ValidRPCDataValue
}
export type ValidRPCDataValue = Primitive | null | RPCData | Array<ValidRPCDataValue>