@flexvertex/flexvertex-driver
Version:
The official FlexVertex Node.js driver
567 lines (439 loc) • 17.4 kB
JavaScript
import fs from 'node:fs';
import { JSONParse, JSONStringify } from 'json-with-bigint';
import { FlexCommons } from '../commons/FlexCommons.js';
import { FlexCargo } from '../journey/FlexCargo.js';
import { FlexObject } from '../objects/FlexObject.js';
import { FlexConnection } from '../connections/FlexConnection.js';
import { FlexResultSet } from './FlexResultSet.js';
/**
* Represents a FlexVertex Schema.
*/
export class FlexSchema
{
// Holds the list of FlexObjects to save.
#objectsToSave = new Map();
#objectsToDelete = new Array();
// Holds the list of FlexConnections to save.
#cxsToSave = new Map();
#cxsToDelete = new Array();
#dnsPath;
#flexSession;
/**
*
* @param {!FlexSession} flexSession - The FlexSession this FlexSchema belongs
* @param {?string} dnsPath - The /Domain/Nexus/Schema path
*/
constructor(flexSession, dnsPath) // dnsPath may be null
{
this.#flexSession = flexSession;
this.#dnsPath = dnsPath;
}
/**
* Should be called when this FlexSchema is no longer needed.
*/
close()
{
// console.log("--FlexSchema.close()");
}
createConnection(sourceKey, destinationKey, options)
{
let cx = new FlexConnection(this, sourceKey, destinationKey, options);
cx.save();
return cx;
}
async createObject(flexObject)
{
// console.log("FlexSchema.createObject()");
if(flexObject === undefined) throw "FlexSchema.createObject() FlexObject is undefined!";
if(flexObject.className === undefined) throw "FlexSchema.createObject() FlexObject.className is undefined!";
if(flexObject.properties === undefined) throw "FlexSchema.createObject() FlexObject.properties is undefined!";
// console.log("FlexSchema.createObject() about to call post, props = " + JSONStringify(flexObject.properties));
const response = await this.#flexSession.axInstance.post('schema/createObject',
{
Class: flexObject.className,
Attributes: flexObject.attributes,
Properties: flexObject.properties
});
// console.log("FlexSchema.createObject() post complete response = " + response);
if(response.data === undefined) throw "FlexSchema.createObject() Returned Response is undefined!";
if(response.data.ObjectKey === undefined) throw "FlexSchema.createObject() Returned ObjectKey is undefined!";
// console.log("response.data.objectKey = " + response.data.objectKey);
flexObject.objectKey = response.data.ObjectKey;
return response.data;
}
/**
* Deletes the specified {@link FlexConnection}. FlexSchema.save() must be called to complete the deletion.
* @param {!FlexConnection} flexConnection
*/
deleteConnection(flexConnection)
{
if(flexConnection === undefined) throw "FlexSchema.deleteConnection() FlexConnection is undefined!";
//console.log("--deleteConnection() objectKey = " + flexConnection.objectKey);
if(FlexCommons.isDefined(flexConnection.objectKey))
this.#cxsToDelete.push(flexConnection.objectKey);
}
/**
* Deletes a {@link FlexConnection} by specifying its ObjectKey. FlexSchema.save() must be called to complete the deletion.
* @param {!string} objectKey
*/
deleteConnectionByKey(objectKey)
{
if(objectKey === undefined) throw "FlexSchema.deleteConnectionByKey() ObjectKey is undefined!";
// console.log("--deleteConnectionByKey() objectKey = " + objectKey);
if(FlexCommons.isDefined(objectKey))
this.#cxsToDelete.push(objectKey);
}
/**
* Deletes the specified {@link FlexObject}. FlexSchema.save() must be called to complete the deletion.
* @param {!FlexObject} flexObject
*/
deleteObject(flexObject)
{
if(flexObject === undefined) throw "FlexSchema.deleteObject() FlexObject is undefined!";
//console.log("--deleteObject() objectKey = " + flexObject.objectKey);
if(FlexCommons.isDefined(flexObject.objectKey))
this.#objectsToDelete.push(flexObject.objectKey);
}
/**
* Deletes a {@link FlexObject} by specifying its ObjectKey. FlexSchema.save() must be called to complete the deletion.
* @param {!string} objectKey
*/
deleteObjectByKey(objectKey)
{
if(objectKey === undefined) throw "FlexSchema.deleteObjectByKey() ObjectKey is undefined!";
// console.log("--deleteObjectByKey() objectKey = " + objectKey);
if(FlexCommons.isDefined(objectKey))
this.#objectsToDelete.push(objectKey);
/*
const response = await this.#flexSession.axInstance.delete('schema/deleteObject',
{
params: { objectKey: objectKey }
});*/
// return response.data;
}
/**
* Executes a Voyage from a local file
* @param {!string} voyagerFilePath - The path to the Voyager file
* @param {Object} [namedParams] - Each property in the object is passed to Voyager as a namedParams property
* @returns {FlexCargo}
*/
async executeVoyagerFile(voyagerFilePath, namedParams)
{
try
{
const voyage = fs.readFileSync(voyagerFilePath, 'utf8');
return this.executeVoyage(voyage, namedParams);
}
catch(err)
{
console.error("FlexSchema.executeVoyagerFile() error: " + err);
}
}
/**
* Executes a Voyage from the passed-in string
* @param {!string} voyage - The Voyager contents
* @param {Object} [namedParams] - Each property in the object is passed to Voyager as a namedParams property
* @returns {FlexCargo}
*/
async executeVoyage(voyage, namedParams)
{
// console.log("-- FlexSchema.executeVoyage() voyage = " + voyage);
if(namedParams == null) namedParams = { };
const response = await this.#flexSession.axInstance.post('schema/executeVoyage',
{
Voyage: voyage,
NamedParams: namedParams,
DNS: this.#dnsPath
});
if(response === undefined) throw "FlexSchema.executeVoyage() response is undefined!";
if(response.data === undefined) throw "FlexSchema.executeVoyage() response.data is undefined!";
if(response.data.Cargo === undefined) throw "FlexSchema.executeVoyage() response.data Cargo is undefined!";
// console.log("-- FlexSchema.executeVoyage() response.data.Cargo = " + JSONStringify(response.data.Cargo));
let cargo = new FlexCargo(this, response.data.Cargo);
// console.log("-- FlexSchema.executeVoyage() cargo = " + cargo);
return cargo;
}
/**
* Executes a Voyage from a remote asset
* @param {!string} assetPath - The asset path to the Voyager file
* @param {Object} [namedParams] - Each property in the object is passed to Voyager as a namedParams property
* @returns {FlexCargo}
*/
async executeVoyagerAsset(assetPath, namedParams)
{
if(namedParams == null) namedParams = { };
const response = await this.#flexSession.axInstance.post('schema/executeVoyagerAsset',
{
AssetPath: assetPath,
NamedParams: namedParams,
DNS: this.#dnsPath
});
if(response === undefined) throw "FlexSchema.executeVoyagerAsset() response is undefined!";
if(response.data === undefined) throw "FlexSchema.executeVoyagerAsset() response.data is undefined!";
if(response.data.Cargo === undefined) throw "FlexSchema.executeVoyagerAsset() response.data Cargo is undefined!";
let cargo = new FlexCargo(this, response.data.Cargo);
return cargo;
}
/**
* Loads and returns a {@link FlexConnection} from the specified ObjectKey
* @param {!string} objectKey
* @returns FlexConnection
*/
async loadConnection(objectKey)
{
if(objectKey === undefined) throw "FlexSchema.loadConnection() objectKey is undefined!";
const response = await this.#flexSession.axInstance.get('schema/loadConnection',
{
params: { ObjectKey: objectKey },
DNS: this.#dnsPath
});
if(response.data === undefined) throw "FlexSchema.loadConnection() Returned Response is undefined!";
if(response.data.Connection === undefined) throw "FlexSchema.loadConnection() Returned Response Connection is undefined!";
let cx = FlexConnection.createFromObject(this, response.data.Connection);
// console.log("-- loadConnection() data = " + JSONStringify(response.data));
// if(response.data.Connection.Class === undefined) throw "FlexSchema.loadConnection() Returned Class is undefined!";
// if(response.data.connection.objectKey === undefined) throw "FlexSchema.loadConnection() Returned objectKey is undefined!";
// if(response.data.connection.properties === undefined) throw "FlexSchema.loadConnection() Returned properties is undefined!";
// let cx = new FlexConnection(this, response.data.Connection);
// cx.objectKey = response.data.connection.objectKey;
// cx.attributes = response.data.connection.attributes;
// cx.properties = response.data.connection.properties;
return cx;
}
/**
* Loads and returns a {@link FlexObject} from the specified ObjectKey
* @param {!string} objectKey
* @returns FlexObject
*/
async loadObject(objectKey)
{
if(objectKey === undefined) throw "FlexSchema.loadObject() objectKey is undefined!";
const response = await this.#flexSession.axInstance.get('schema/loadObject',
{
params: { ObjectKey: objectKey },
DNS: this.#dnsPath
});
if(response.data === undefined) throw "FlexSchema.loadObject() Returned Response is undefined!";
if(response.data.Object === undefined) throw "FlexSchema.loadObject() Returned Object is undefined!";
// console.log("-- loadObject() data = " + JSONStringify(response.data));
let obj = FlexObject.createFromObject(this, response.data.Object);
/*
if(response.data.object.class === undefined) throw "FlexSchema.loadObject() Returned class is undefined!";
if(response.data.object.objectKey === undefined) throw "FlexSchema.loadObject() Returned objectKey is undefined!";
if(response.data.object.properties === undefined) throw "FlexSchema.loadObject() Returned properties is undefined!";
let obj = new FlexObject(this, response.data.object.class);
obj.objectKey = response.data.object.objectKey;
obj.attributes = response.data.object.attributes;
obj.properties = response.data.object.properties;
*/
return obj;
}
/**
*
* @param {!string} sql
* @param {Object} [namedParams] - Each property in the object is passed to the SQL executor as a named parameter
* @returns {FlexResultSet}
*/
async query(sql, namedParams)
{
// let keys = Object.keys(namedParams)
// console.log("query(sql, namedParams)");
if(namedParams == null) namedParams = { };
const response = await this.#flexSession.axInstance.post('schema/sql',
{
Query: sql,
NamedParams: namedParams,
DNS: this.#dnsPath
});
if(response === undefined) throw "FlexSchema.query() response is undefined!";
const objectArray = new Array();
if(response.data === undefined) throw "FlexSchema.query() response.data is undefined!";
if(!(response.data.ResultSet === undefined))
{
let rs = new FlexResultSet(this, response.data.ResultSet);
return rs;
}
return null;
}
async saveObject(flexObject)
{
if(flexObject === undefined) throw "FlexSchema.saveObject() FlexObject is undefined!";
/*
if(flexObject.objectKey === undefined)
{
if(flexObject.className === undefined) throw "FlexSchema.saveObject() FlexObject.className is undefined!";
return this.createObject(flexObject);
}
else
{
return this.updateObject(flexObject);
}
*/
// this.#objectsToSave.push(flexObject);
// Object.defineProperty(this.#objectsToSave, flexObject.uniqueID, { value: flexObject, enumerable: true, writable: true });
this.#objectsToSave.set(flexObject.uniqueID, flexObject);
/*
if(flexObject.isNew())
{
this.#objectsToSave.push({ class: flexObject.className, properties: flexObject.properties });
}
else
{
this.#objectsToSave.push({ objectKey: flexObject.objectKey, properties: flexObject.properties });
}*/
}
addSavingConnection(flexConnection)
{
if(flexConnection === undefined) throw "FlexSchema.addSavingConnection() FlexConnection is undefined!";
// this.#cxsToSave.push(flexConnection);
// console.log("FlexSchema.addSavingCx() cx uniqueID = " + flexConnection.uniqueID);
// Object.defineProperty(this.#cxsToSave, flexConnection.uniqueID, { value: flexConnection, enumerable: true, writable: true });
this.#cxsToSave.set(flexConnection.uniqueID, flexConnection);
}
/**
* Must be called anytime a FlexObject or FlexConnection needs to be saved or deleted.
*
*/
async save()
{
// The order of operations must be:
// - SaveObjects
// - SaveConnections
// - DeleteConnections
// - DeleteObjects
// This is important because deleting objects with connections will delete the connections too.
// To avoid an error by calling DeleteConnections, last, we make sure the connections are deleted first, just in case.
// console.log("-- save() objectArray = " + JSONStringify(this.#objectsToSave));
//objects: Object.fromEntries(this.#objectsToSave)
let saveObjArray = new Array();
let saveCxArray = new Array();
let deleteCxArray = new Array();
let deleteObjArray = new Array();
this.#objectsToSave.forEach((value, key) =>
{
saveObjArray.push(value.getObject());
});
this.#cxsToSave.forEach((value, key) =>
{
saveCxArray.push(value.getObject());
});
for(const objectKey of this.#cxsToDelete)
{
deleteCxArray.push(objectKey);
}
for(const objectKey of this.#objectsToDelete)
{
deleteObjArray.push(objectKey);
}
// Save the Objects
if(saveObjArray.length > 0)
{
const response = await this.#flexSession.axInstance.post('schema/saveObjects',
{
SaveObjects: saveObjArray,
DNS: this.#dnsPath
})
.catch(function(error)
{
console.log("-- save() error = " + error);
});
if(response === undefined) throw "FlexSchema.save() saveObjects response is undefined!";
if(response.data === undefined) throw "FlexSchema.save() saveObjects response.data is undefined!";
if(FlexCommons.isDefined(response.data.SavedObjects))
{
for(const so of response.data.SavedObjects)
{
if(FlexCommons.isDefined(so.UniqueID))
{
let obj = this.#objectsToSave.get(so.UniqueID);
if(FlexCommons.isDefined(obj))
{
obj.objectKey = so.ObjectKey;
}
}
}
}
// Empty the arrays.
saveObjArray = [ ];
this.#objectsToSave.clear();
}
// Save the Connections
if(saveCxArray.length > 0)
{
const cxResponse = await this.#flexSession.axInstance.post('schema/saveConnections',
{
SaveConnections: saveCxArray,
DNS: this.#dnsPath
})
.catch(function(error)
{
console.log("-- save() cx error = " + error);
});
if(cxResponse === undefined) throw "FlexSchema.save() saveConnections response is undefined!";
if(cxResponse.data === undefined) throw "FlexSchema.save() saveConnections response.data is undefined!";
if(FlexCommons.isDefined(cxResponse.data.SavedConnections))
{
for(const so of cxResponse.data.SavedConnections)
{
if(FlexCommons.isDefined(so.UniqueID))
{
let obj = this.#cxsToSave.get(so.UniqueID);
if(FlexCommons.isDefined(obj)) obj.objectKey = so.ObjectKey;
}
}
}
// Empty the arrays.
saveCxArray = [ ];
this.#cxsToSave.clear();
}
// Delete the Connections
if(deleteCxArray.length > 0)
{
const cxResponse = await this.#flexSession.axInstance.delete('schema/deleteConnections',
{
data: { ObjectKeys: deleteCxArray }
})
.catch(function(error)
{
console.log("-- save() cx error = " + error);
});
if(cxResponse === undefined) throw "FlexSchema.save() deleteConnections response is undefined!";
if(cxResponse.data === undefined) throw "FlexSchema.save() deleteConnections response.data is undefined!";
// console.log("-- save() deleteConnections response = " + JSONStringify(cxResponse.data));
deleteCxArray = [ ];
this.#cxsToDelete = [ ];
}
// Delete the Objects (do this last)
if(deleteObjArray.length > 0)
{
const response = await this.#flexSession.axInstance.delete('schema/deleteObjects',
{
data: { ObjectKeys: deleteObjArray }
})
.catch(function(error)
{
console.log("-- save() error = " + error);
});
if(response === undefined) throw "FlexSchema.save() deleteObjects response is undefined!";
if(response.data === undefined) throw "FlexSchema.save() deleteObjects response.data is undefined!";
// console.log("-- save() deleteObjects response = " + JSONStringify(response.data));
// Empty the arrays.
deleteObjArray = [ ];
this.#objectsToDelete = [ ];
}
// console.log("-- save() response = " + JSONStringify(response.data));
// return response.data;
}
async updateObject(flexObject)
{
if(flexObject === undefined) throw "FlexSchema.updateObject() FlexObject is undefined!";
if(flexObject.objectKey === undefined) throw "FlexSchema.updateObject() FlexObject.objectKey is undefined!";
const response = await this.#flexSession.axInstance.post('schema/updateObject',
{
ObjectKey: flexObject.objectKey,
Properties: flexObject.properties,
DNS: this.#dnsPath
});
return response.data;
}
}