wip
ci/woodpecker/push/woodpecker Pipeline failed Details

refactor/addresses-js
Tomáš Mládek 2023-11-26 12:41:38 +01:00
parent 2c75a76446
commit 52fc8e73e9
4 changed files with 45 additions and 21 deletions

View File

@ -14,6 +14,7 @@ import type {
StoreInfo, StoreInfo,
VaultInfo, VaultInfo,
} from "./types"; } from "./types";
import { asAddress } from "./types";
import type { UpEndWasmExtensions, AddressComponents } from "./wasm"; import type { UpEndWasmExtensions, AddressComponents } from "./wasm";
import debug from "debug"; import debug from "debug";
const dbg = debug("upend:api"); const dbg = debug("upend:api");
@ -43,7 +44,7 @@ export class UpEndApi {
return this.instanceUrl + "/api"; return this.instanceUrl + "/api";
} }
public async fetchEntity(address: string): Promise<UpObject> { public async fetchEntity(address: Address): Promise<UpObject> {
dbg("Fetching Entity %s", address); dbg("Fetching Entity %s", address);
const entityFetch = await fetch(`${this.apiUrl}/obj/${address}`); const entityFetch = await fetch(`${this.apiUrl}/obj/${address}`);
const entityResult = (await entityFetch.json()) as EntityListing; const entityResult = (await entityFetch.json()) as EntityListing;
@ -51,11 +52,11 @@ export class UpEndApi {
return entityListing.getObject(address); return entityListing.getObject(address);
} }
public async fetchEntry(address: string) { public async fetchEntry(address: Address) {
dbg("Fetching entry %s", address); dbg("Fetching entry %s", address);
const response = await fetch(`${this.apiUrl}/raw/${address}`); const response = await fetch(`${this.apiUrl}/raw/${address}`);
const data = await response.json(); const data = await response.json();
const listing = new UpListing({ address: data }); const listing = new UpListing({ [address]: data });
return listing.entries[0]; return listing.entries[0];
} }
@ -103,7 +104,8 @@ export class UpEndApi {
body: JSON.stringify(input), body: JSON.stringify(input),
}); });
return await response.json(); const [entry, entity] = await response.json();
return [entry, entity].map(asAddress) as PutResult;
} }
public async putEntityAttribute( public async putEntityAttribute(
@ -212,12 +214,12 @@ export class UpEndApi {
| { url: string } | { url: string }
| { urlContent: string } | { urlContent: string }
| ADDRESS_TYPE | ADDRESS_TYPE
): Promise<string> { ): Promise<Address> {
let response: Response; let response: Response;
if (typeof input === "string") { if (typeof input === "string") {
if (this.wasmExtensions) { if (this.wasmExtensions) {
await this.wasmExtensions.init(); await this.wasmExtensions.init();
return this.wasmExtensions.AddressTypeConstants[input]; return asAddress(this.wasmExtensions.AddressTypeConstants[input]);
} }
response = await fetch(`${this.apiUrl}/address?type=${input}`); response = await fetch(`${this.apiUrl}/address?type=${input}`);
} else { } else {
@ -237,7 +239,7 @@ export class UpEndApi {
} }
const result = await response.json(); const result = await response.json();
dbg("Address for %o = %s", input, result); dbg("Address for %o = %s", input, result);
return result; return asAddress(result);
} }
public async addressToComponents( public async addressToComponents(

View File

@ -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 { UpEndApi } from "./api";
export { Query } from "./query"; export { Query } from "./query";
@ -8,7 +9,7 @@ export class UpListing {
constructor(listing: ListingResult) { constructor(listing: ListingResult) {
this.entries = Object.entries(listing).map( 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; return result;
} }
public getObject(address: string) { public getObject(address: Address) {
if (!this._objects[address]) { if (!this._objects[address]) {
this._objects[address] = new UpObject(address, this); this._objects[address] = new UpObject(address, this);
} }
return this._objects[address]; return this._objects[address];
} }
public get entities(): string[] { public get entities(): Address[] {
return Array.from(new Set(this.entries.map((e) => `@${e.entity}`))); return Array.from(new Set(this.entries.map((e) => asAddress(e.entity))));
} }
public get attributes(): string[] { public get attributes(): string[] {
@ -42,10 +43,10 @@ export class UpListing {
} }
export class UpObject { export class UpObject {
public readonly address: string; public readonly address: Address;
public listing: UpListing | undefined; public listing: UpListing | undefined;
constructor(address: string, listing?: UpListing) { constructor(address: Address, listing?: UpListing) {
this.address = address; this.address = address;
this.listing = listing; this.listing = listing;
} }
@ -106,13 +107,13 @@ export class UpObject {
} }
export class UpEntry extends UpObject implements IEntry { export class UpEntry extends UpObject implements IEntry {
entity: string; entity: Address;
attribute: string; attribute: string;
value: IValue; value: IValue;
provenance: string; provenance: string;
timestamp: string; timestamp: string;
constructor(address: string, entry: IEntry, listing: UpListing) { constructor(address: Address, entry: IEntry, listing: UpListing) {
super(address, listing); super(address, listing);
this.entity = entry.entity; this.entity = entry.entity;

View File

@ -1,5 +1,16 @@
import test from "ava"; import test from "ava";
import { Any, Query, Variable } from "./query"; 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) => { test("query matches simple", (t) => {
const query = Query.matches("entity", "attribute", "value"); const query = Query.matches("entity", "attribute", "value");

View File

@ -1,9 +1,19 @@
export type Address = string; export type Address = `@${string}`;
export type ADDRESS_TYPE = "Hash" | "Uuid" | "Attribute" | "Url"; export type ADDRESS_TYPE = "Hash" | "Uuid" | "Attribute" | "Url";
export type VALUE_TYPE = "Address" | "String" | "Number" | "Invalid"; export type VALUE_TYPE = "Address" | "String" | "Number" | "Invalid";
export function isAddress(address: string): address is Address { 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 = export type IValue =
| { | {
t: "Address"; t: "Address";
c: string; c: Address;
} }
| { | {
t: "String"; t: "String";
@ -63,11 +73,11 @@ export type PutInput =
| { entity: InAddress }; | { entity: InAddress };
export interface ListingResult { export interface ListingResult {
[key: string]: IEntry; [key: Address]: IEntry;
} }
// entry address, entity address address // entry address, entity address address
export type PutResult = [string | undefined, string]; export type PutResult = [Address | undefined, Address];
// export type OrderedListing = [Address, IEntry][]; // export type OrderedListing = [Address, IEntry][];