From 52fc8e73e99d990478ea7aec548b0302ff518a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ml=C3=A1dek?= Date: Sun, 26 Nov 2023 12:41:38 +0100 Subject: [PATCH] wip --- tools/upend_js/api.ts | 16 +++++++++------- tools/upend_js/index.ts | 19 ++++++++++--------- tools/upend_js/test.ts | 11 +++++++++++ tools/upend_js/types.ts | 20 +++++++++++++++----- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/tools/upend_js/api.ts b/tools/upend_js/api.ts index 58bf9a6..5e9c66c 100644 --- a/tools/upend_js/api.ts +++ b/tools/upend_js/api.ts @@ -14,6 +14,7 @@ import type { StoreInfo, VaultInfo, } from "./types"; +import { asAddress } from "./types"; import type { UpEndWasmExtensions, AddressComponents } from "./wasm"; import debug from "debug"; const dbg = debug("upend:api"); @@ -43,7 +44,7 @@ export class UpEndApi { return this.instanceUrl + "/api"; } - public async fetchEntity(address: string): Promise { + public async fetchEntity(address: Address): Promise { dbg("Fetching Entity %s", address); const entityFetch = await fetch(`${this.apiUrl}/obj/${address}`); const entityResult = (await entityFetch.json()) as EntityListing; @@ -51,11 +52,11 @@ export class UpEndApi { return entityListing.getObject(address); } - public async fetchEntry(address: string) { + public async fetchEntry(address: Address) { dbg("Fetching entry %s", address); const response = await fetch(`${this.apiUrl}/raw/${address}`); const data = await response.json(); - const listing = new UpListing({ address: data }); + const listing = new UpListing({ [address]: data }); return listing.entries[0]; } @@ -103,7 +104,8 @@ export class UpEndApi { body: JSON.stringify(input), }); - return await response.json(); + const [entry, entity] = await response.json(); + return [entry, entity].map(asAddress) as PutResult; } public async putEntityAttribute( @@ -212,12 +214,12 @@ export class UpEndApi { | { url: string } | { urlContent: string } | ADDRESS_TYPE - ): Promise { + ): Promise
{ let response: Response; if (typeof input === "string") { if (this.wasmExtensions) { await this.wasmExtensions.init(); - return this.wasmExtensions.AddressTypeConstants[input]; + return asAddress(this.wasmExtensions.AddressTypeConstants[input]); } response = await fetch(`${this.apiUrl}/address?type=${input}`); } else { @@ -237,7 +239,7 @@ export class UpEndApi { } const result = await response.json(); dbg("Address for %o = %s", input, result); - return result; + return asAddress(result); } public async addressToComponents( diff --git a/tools/upend_js/index.ts b/tools/upend_js/index.ts index de5fc44..3a4f64a 100644 --- a/tools/upend_js/index.ts +++ b/tools/upend_js/index.ts @@ -1,4 +1,5 @@ -import type { IEntry, IValue, ListingResult } from "./types"; +import type { Address, IEntry, IValue, ListingResult } from "./types"; +import { asAddress } from "./types"; export { UpEndApi } from "./api"; export { Query } from "./query"; @@ -8,7 +9,7 @@ export class UpListing { constructor(listing: ListingResult) { this.entries = Object.entries(listing).map( - (lr) => new UpEntry(...lr, this) + ([address, entry]) => new UpEntry(asAddress(address), entry, this) ); } @@ -21,15 +22,15 @@ export class UpListing { return result; } - public getObject(address: string) { + public getObject(address: Address) { if (!this._objects[address]) { this._objects[address] = new UpObject(address, this); } return this._objects[address]; } - public get entities(): string[] { - return Array.from(new Set(this.entries.map((e) => `@${e.entity}`))); + public get entities(): Address[] { + return Array.from(new Set(this.entries.map((e) => asAddress(e.entity)))); } public get attributes(): string[] { @@ -42,10 +43,10 @@ export class UpListing { } export class UpObject { - public readonly address: string; + public readonly address: Address; public listing: UpListing | undefined; - constructor(address: string, listing?: UpListing) { + constructor(address: Address, listing?: UpListing) { this.address = address; this.listing = listing; } @@ -106,13 +107,13 @@ export class UpObject { } export class UpEntry extends UpObject implements IEntry { - entity: string; + entity: Address; attribute: string; value: IValue; provenance: string; timestamp: string; - constructor(address: string, entry: IEntry, listing: UpListing) { + constructor(address: Address, entry: IEntry, listing: UpListing) { super(address, listing); this.entity = entry.entity; diff --git a/tools/upend_js/test.ts b/tools/upend_js/test.ts index d71e247..0556f06 100644 --- a/tools/upend_js/test.ts +++ b/tools/upend_js/test.ts @@ -1,5 +1,16 @@ import test from "ava"; import { Any, Query, Variable } from "./query"; +import { asAddress, isAddress } from "./types"; + +test("address check", (t) => { + const address = "@address"; + t.is(isAddress(address), true); +}); + +test("address conversion", (t) => { + t.is(asAddress("address"), "@address"); + t.is(asAddress("@address"), "@address"); +}); test("query matches simple", (t) => { const query = Query.matches("entity", "attribute", "value"); diff --git a/tools/upend_js/types.ts b/tools/upend_js/types.ts index 66b6873..b72e1c0 100644 --- a/tools/upend_js/types.ts +++ b/tools/upend_js/types.ts @@ -1,9 +1,19 @@ -export type Address = string; +export type Address = `@${string}`; export type ADDRESS_TYPE = "Hash" | "Uuid" | "Attribute" | "Url"; export type VALUE_TYPE = "Address" | "String" | "Number" | "Invalid"; export function isAddress(address: string): address is Address { - return address.startsWith("@"); + return address.match(/^@[0-9a-zA-Z]+$/) !== null; +} + +export function asAddress(address: string): Address { + const result = address.startsWith("@") ? address : `@${address}`; + + if (!isAddress(result)) { + throw new Error(`Invalid address: ${address}`); + } + + return result; } /** @@ -25,7 +35,7 @@ export interface IEntry { export type IValue = | { t: "Address"; - c: string; + c: Address; } | { t: "String"; @@ -63,11 +73,11 @@ export type PutInput = | { entity: InAddress }; export interface ListingResult { - [key: string]: IEntry; + [key: Address]: IEntry; } // entry address, entity address address -export type PutResult = [string | undefined, string]; +export type PutResult = [Address | undefined, Address]; // export type OrderedListing = [Address, IEntry][];