forked from cerc-io/laconic-sdk
Refactors the `Record.Attributes` from Any into a byte string. Companion to cerc-io/laconicd#132. Resolves https://github.com/cerc-io/laconicd/issues/107 Co-authored-by: Roy Crihfield <roy@manteia.ltd> Co-authored-by: Prathamesh Musale <prathamesh.musale0@gmail.com> Reviewed-on: cerc-io/laconic-sdk#52 Reviewed-by: Thomas E Lackey <telackey@noreply.git.vdb.to> Co-authored-by: Nabarun <nabarun@deepstacksoft.com> Co-committed-by: Nabarun <nabarun@deepstacksoft.com>
121 lines
2.8 KiB
TypeScript
121 lines
2.8 KiB
TypeScript
import * as Block from 'multiformats/block'
|
|
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
|
import * as dagCBOR from '@ipld/dag-cbor'
|
|
import * as dagJSON from '@ipld/dag-json'
|
|
|
|
/**
|
|
* Utils
|
|
*/
|
|
export class Util {
|
|
/**
|
|
* Sorts JSON object.
|
|
*/
|
|
static sortJSON(obj: any) {
|
|
if (obj instanceof Array) {
|
|
for (let i = 0; i < obj.length; i++) {
|
|
obj[i] = Util.sortJSON(obj[i]);
|
|
}
|
|
return obj;
|
|
}
|
|
if (typeof obj !== 'object' || obj === null) return obj;
|
|
|
|
let keys = Object.keys(obj);
|
|
keys = keys.sort();
|
|
const newObject: {[key: string]: any} = {};
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
newObject[keys[i]] = Util.sortJSON(obj[keys[i]]);
|
|
}
|
|
return newObject;
|
|
}
|
|
|
|
/**
|
|
* Marshal object into gql 'attributes' variable.
|
|
*/
|
|
static toGQLAttributes(obj: any) {
|
|
const vars: any[] = [];
|
|
Object.keys(obj).forEach(key => {
|
|
const value = this.toGQLValue(obj[key]);
|
|
|
|
if (value !== undefined) {
|
|
vars.push({ key, value });
|
|
}
|
|
});
|
|
return vars;
|
|
}
|
|
|
|
static toGQLValue(obj: any) {
|
|
if (obj === null) {
|
|
return null;
|
|
}
|
|
let type: string = typeof obj;
|
|
switch (type) {
|
|
case 'number':
|
|
type = (obj % 1 === 0) ? 'int' : 'float';
|
|
return { [type]: obj };
|
|
case 'string':
|
|
return { 'string': obj };
|
|
case 'boolean':
|
|
return { 'boolean': obj };
|
|
case 'object':
|
|
if (obj['/'] !== undefined) {
|
|
return { 'link': obj['/'] };
|
|
}
|
|
if (obj instanceof Array) {
|
|
return { 'array': obj };
|
|
}
|
|
return { 'map': obj };
|
|
case 'undefined':
|
|
return undefined;
|
|
default:
|
|
throw new Error(`Unknown object type '${type}': ${obj}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unmarshal attributes array to object.
|
|
*/
|
|
static fromGQLAttributes(attributes: any[] = []) {
|
|
const res: {[key: string]: any} = {};
|
|
|
|
attributes.forEach(attr => {
|
|
res[attr.key] = this.fromGQLValue(attr.value);
|
|
});
|
|
|
|
return res;
|
|
}
|
|
|
|
static fromGQLValue(obj: any) {
|
|
// Get first non-null key
|
|
const present = Object.keys(obj).find(k => obj[k] !== null);
|
|
if (present === undefined) {
|
|
throw new Error('Object has no non-null values');
|
|
}
|
|
|
|
// Create an array if array type attribute
|
|
if (present === 'array') {
|
|
return obj[present].map((e: any) => {
|
|
return this.fromGQLValue(e);
|
|
});
|
|
}
|
|
|
|
return obj[present];
|
|
}
|
|
|
|
/**
|
|
* Get record content ID.
|
|
*/
|
|
static async getContentId(record: any) {
|
|
const serialized = dagJSON.encode(record)
|
|
const recordData = dagJSON.decode(serialized)
|
|
|
|
const block = await Block.encode({
|
|
value: recordData,
|
|
codec: dagCBOR,
|
|
hasher
|
|
})
|
|
|
|
return block.cid.toString();
|
|
}
|
|
}
|