From 57aca4a95cf3942264f0660a210b54edf54b1518 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 18 Oct 2020 16:44:30 -0400 Subject: [PATCH] auto set creation via arrays --- services/gunDB/rpc/index.js | 81 +++++++++++++++++++++++++++++-------- services/gunDB/rpc/types.ts | 8 ++++ 2 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 services/gunDB/rpc/types.ts diff --git a/services/gunDB/rpc/index.js b/services/gunDB/rpc/index.js index 67d15ca0..38d04aa1 100644 --- a/services/gunDB/rpc/index.js +++ b/services/gunDB/rpc/index.js @@ -1,10 +1,12 @@ /** * @format */ +/* eslint-disable no-use-before-define */ // @ts-check const { makePromise, Constants, Schema } = require('shock-common') const mapValues = require('lodash/mapValues') const Bluebird = require('bluebird') +const Gun = require('gun') const { pubToEpub } = require('../contact-api/utils') const { @@ -16,6 +18,8 @@ const { } = require('../Mediator') /** * @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 - * @returns {Promise} + * @param {ValidRPCDataValue} value + * @returns {Promise} */ -const deepEncryptIfNeeded = async value => { +// eslint-disable-next-line func-style +async function deepEncryptIfNeeded(value) { const u = getUser() if (!u.is) { @@ -69,6 +74,10 @@ const deepEncryptIfNeeded = async value => { return value } + if (Array.isArray(value)) { + return Promise.all(value.map(v => deepEncryptIfNeeded(v))) + } + const pk = /** @type {string|undefined} */ (value.$$__ENCRYPT__FOR) if (!pk) { @@ -92,7 +101,7 @@ const deepEncryptIfNeeded = async value => { /** * @param {string} rawPath - * @param {ValidDataValue} value + * @param {ValidRPCDataValue} value * @returns {Promise} */ const put = async (rawPath, value) => { @@ -125,25 +134,34 @@ const put = async (rawPath, value) => { return _node })() - const encryptedIfNeededValue = await deepEncryptIfNeeded(value) + const theValue = await deepEncryptIfNeeded(value) - await makePromise((res, rej) => { - node.put(encryptedIfNeededValue, ack => { - if (ack.err && typeof ack.err !== 'number') { - rej(new Error(ack.err)) - } else { - res() - } + 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) => { + node.put(/** @type {ValidDataValue} */ (theValue), ack => { + if (ack.err && typeof ack.err !== 'number') { + rej(new Error(ack.err)) + } else { + res() + } + }) }) - }) + } } /** * @param {string} rawPath - * @param {ValidDataValue} value + * @param {ValidRPCDataValue} value * @returns {Promise} */ -const set = async (rawPath, value) => { +// eslint-disable-next-line func-style +async function set(rawPath, value) { const [root, ...path] = rawPath.split('.') const node = (() => { @@ -173,10 +191,39 @@ const set = async (rawPath, value) => { 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 subNode = node.set(encryptedIfNeededValue, ack => { + const subNode = node.set(theValue, ack => { if (ack.err && typeof ack.err !== 'number') { rej(new Error(ack.err)) } else { diff --git a/services/gunDB/rpc/types.ts b/services/gunDB/rpc/types.ts new file mode 100644 index 00000000..e30bb4b8 --- /dev/null +++ b/services/gunDB/rpc/types.ts @@ -0,0 +1,8 @@ +import {Primitive} from '../contact-api/SimpleGUN' + + +export interface RPCData { + [K: string]: ValidRPCDataValue +} + +export type ValidRPCDataValue = Primitive | null | RPCData | Array \ No newline at end of file