@hpcc-js/comms
Version:
hpcc-js - Communications
237 lines (217 loc) • 10.7 kB
text/typescript
import { Cache, exists, StateObject } from "@hpcc-js/util";
import { IConnection, IOptions } from "../connection.ts";
import { WsDfu } from "../services/wsDFU.ts";
import { isECLResult, WorkunitsService, WsWorkunits } from "../services/wsWorkunits.ts";
import { parseXSD, XSDSchema, XSDXMLNode } from "./xsdParser.ts";
export class GlobalResultCache extends Cache<{ BaseUrl: string, Wuid: string, ResultName: string }, Result> {
constructor() {
super((obj) => {
return `${obj.BaseUrl}-${obj.Wuid}-${obj.ResultName}`;
});
}
}
const _results = new GlobalResultCache();
export type ResultFilter = { [key: string]: string | number };
export interface ECLResultEx extends WsWorkunits.ECLResult {
Wuid: string;
ResultName?: string;
ResultSequence?: number;
LogicalFileName?: string;
NodeGroup?: string;
ResultViews: string[];
}
export interface WUResultResponseEx {
Exceptions: WsWorkunits.Exceptions;
Wuid: string;
Sequence: WsWorkunits.int;
LogicalName: string;
Cluster: string;
Name: string;
Start: WsWorkunits.long;
Requested: WsWorkunits.int;
Count: WsWorkunits.int;
Total: WsWorkunits.long;
Result: { [key: string]: any[] } & {
XmlSchema?: {
xml: string;
};
};
}
export type UResulState = ECLResultEx & WsDfu.DFULogicalFile;
export type IResulState = ECLResultEx | WsDfu.DFULogicalFile;
export class Result extends StateObject<UResulState, IResulState> implements ECLResultEx {
protected connection: WorkunitsService;
get BaseUrl() { return this.connection.baseUrl; }
protected xsdSchema: XSDSchema;
get properties(): WsWorkunits.ECLResult { return this.get(); }
get Wuid(): string { return this.get("Wuid"); }
get ResultName(): string | undefined { return this.get("ResultName"); }
get ResultSequence(): number | undefined { return this.get("ResultSequence"); }
get LogicalFileName(): string | undefined { return this.get("LogicalFileName"); }
get Name(): string { return this.get("Name"); }
get Sequence(): number { return this.get("Sequence"); }
get Value(): string { return this.get("Value"); }
get Link(): string { return this.get("Link"); }
get FileName(): string { return this.get("FileName"); }
get IsSupplied(): boolean { return this.get("IsSupplied"); }
get ShowFileContent() { return this.get("ShowFileContent"); }
get Total(): number { return this.get("Total"); }
get ECLSchemas(): WsWorkunits.ECLSchemas { return this.get("ECLSchemas"); }
get NodeGroup(): string { return this.get("NodeGroup"); }
get ResultViews(): string[] { return this.get("ResultViews"); }
get XmlSchema(): string { return this.get("XmlSchema"); }
static attach(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, name: string);
static attach(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, sequence: number);
static attach(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, eclResult: WsWorkunits.ECLResult, resultViews: string[]);
static attach(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, name_sequence_eclResult?: string | number | WsWorkunits.ECLResult, resultViews?: string[]): Result {
let retVal: Result;
if (Array.isArray(resultViews)) {
retVal = _results.get({ BaseUrl: optsConnection.baseUrl, Wuid: wuid, ResultName: (name_sequence_eclResult as WsWorkunits.ECLResult).Name }, () => {
return new Result(optsConnection, wuid, name_sequence_eclResult as WsWorkunits.ECLResult, resultViews);
});
retVal.set(name_sequence_eclResult as any);
} else if (typeof resultViews === "undefined") {
if (typeof name_sequence_eclResult === "number") {
retVal = _results.get({ BaseUrl: optsConnection.baseUrl, Wuid: wuid, ResultName: "Sequence_" + name_sequence_eclResult }, () => {
return new Result(optsConnection, wuid, name_sequence_eclResult);
});
} else if (typeof name_sequence_eclResult === "string") {
retVal = _results.get({ BaseUrl: optsConnection.baseUrl, Wuid: wuid, ResultName: name_sequence_eclResult }, () => {
return new Result(optsConnection, wuid, name_sequence_eclResult);
});
}
}
return retVal;
}
static attachLogicalFile(optsConnection: IOptions | IConnection | WorkunitsService, nodeGroup: string, logicalFile: string) {
return _results.get({ BaseUrl: optsConnection.baseUrl, Wuid: nodeGroup, ResultName: logicalFile }, () => {
return new Result(optsConnection, nodeGroup, logicalFile, true);
});
}
private constructor(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, name: string);
private constructor(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, sequence: number);
private constructor(optsConnection: IOptions | IConnection | WorkunitsService, wuid: string, eclResult: WsWorkunits.ECLResult, resultViews: string[]);
private constructor(optsConnection: IOptions | IConnection | WorkunitsService, nodeGroup: string, logicalFile: string, isLogicalFiles: boolean);
private constructor(optsConnection: IOptions | IConnection | WorkunitsService, wuid_NodeGroup: string, name_sequence_eclResult_logicalFile?: string | number | WsWorkunits.ECLResult, resultViews_isLogicalFile?: any[] | boolean) {
super();
if (optsConnection instanceof WorkunitsService) {
this.connection = optsConnection;
} else {
this.connection = new WorkunitsService(optsConnection);
}
if (typeof resultViews_isLogicalFile === "boolean" && resultViews_isLogicalFile === true) {
this.set({
NodeGroup: wuid_NodeGroup,
LogicalFileName: name_sequence_eclResult_logicalFile
} as ECLResultEx);
} else if (isECLResult(name_sequence_eclResult_logicalFile) && Array.isArray(resultViews_isLogicalFile)) {
this.set({
...name_sequence_eclResult_logicalFile,
Wuid: wuid_NodeGroup,
ResultName: name_sequence_eclResult_logicalFile.Name,
ResultViews: resultViews_isLogicalFile
} as ECLResultEx);
} else if (typeof resultViews_isLogicalFile === "undefined") {
if (typeof name_sequence_eclResult_logicalFile === "number") {
this.set({
Wuid: wuid_NodeGroup,
ResultSequence: name_sequence_eclResult_logicalFile
} as ECLResultEx);
} else if (typeof name_sequence_eclResult_logicalFile === "string") {
this.set({
Wuid: wuid_NodeGroup,
ResultName: name_sequence_eclResult_logicalFile
} as ECLResultEx);
} else {
console.warn("Unknown Result.attach (1)");
}
} else {
console.warn("Unknown Result.attach (2)");
}
}
isComplete() {
return this.Total !== -1;
}
private _fetchXMLSchemaPromise: Promise<XSDSchema | null>;
fetchXMLSchema(refresh = false): Promise<XSDSchema | null> {
if (!this._fetchXMLSchemaPromise || refresh) {
this._fetchXMLSchemaPromise = this.WUResult().then(response => {
if (response.Result?.XmlSchema?.xml) {
this.xsdSchema = parseXSD(response.Result.XmlSchema.xml);
return this.xsdSchema;
}
return null;
});
}
return this._fetchXMLSchemaPromise;
}
async refresh(): Promise<this> {
await this.fetchRows(0, 1, true);
return this;
}
fetchRows(from: number = 0, count: number = -1, includeSchema: boolean = false, filter: ResultFilter = {}, abortSignal?: AbortSignal): Promise<any[]> {
return this.WUResult(from, count, !includeSchema, filter, abortSignal).then((response) => {
const result: any = response.Result;
delete response.Result; // Do not want it in "set"
this.set({
...response
} as any);
if (exists("XmlSchema.xml", result)) {
this.xsdSchema = parseXSD(result.XmlSchema.xml);
}
if (exists("Row", result)) {
return result.Row;
} else if (this.ResultName && exists(this.ResultName, result)) {
return result[this.ResultName].Row;
}
return [];
});
}
rootField(): XSDXMLNode | null {
if (!this.xsdSchema) return null;
return this.xsdSchema.root;
}
fields(): XSDXMLNode[] {
if (!this.xsdSchema) return [];
return this.xsdSchema.root.children();
}
protected WUResult(start: number = 0, count: number = 1, suppressXmlSchema: boolean = false, filter: { [key: string]: string | number } = {}, abortSignal?: AbortSignal): Promise<WUResultResponseEx> {
const FilterBy = {
NamedValue: {
itemcount: 0
}
};
for (const key in filter) {
FilterBy.NamedValue[FilterBy.NamedValue.itemcount++] = {
Name: key,
Value: filter[key]
};
}
const request: Partial<WsWorkunits.WUResult> = { FilterBy } as any;
if (this.Wuid && this.ResultName !== undefined) {
request.Wuid = this.Wuid;
request.ResultName = this.ResultName;
} else if (this.Wuid && this.ResultSequence !== undefined) {
request.Wuid = this.Wuid;
request.Sequence = this.ResultSequence;
} else if (this.LogicalFileName && this.NodeGroup) {
request.LogicalName = this.LogicalFileName;
request.Cluster = this.NodeGroup;
} else if (this.LogicalFileName) {
request.LogicalName = this.LogicalFileName;
}
request.Start = start;
request.Count = count;
request.SuppressXmlSchema = suppressXmlSchema;
return this.connection.WUResult(request, abortSignal).then((response: unknown) => {
return response as WUResultResponseEx;
});
}
}
export class ResultCache extends Cache<WsWorkunits.ECLResult, Result> {
constructor() {
super((obj) => {
return Cache.hash([obj.Sequence, obj.Name, obj.Value, obj.FileName]);
});
}
}