// $Id$
// @ts-check
'use strict';
import { RestServices } from '../tools/RestServices.js';
import { ApiResponse } from '../tools/ApiResponse.js';
import { Context } from './Context.js';
import { Func } from '../tools/Func.js';
import { CatalogueServices } from './Catalogue.js'
import { cnObjectServices } from '../gom/cnObject.js'
import { NodeServices } from '../infohub/Node.js'
/**
*
* @category COLNEO infohub
*
* @classdesc
* An object of class PropertySchema' consists of metadata, an info block and the property schema itself.
*
* ps = {
* 'info' :
* 'meta' :
* 'schema' :
* }
*/
export class PropertySchema {
#_jsondata = null
#_saved_schema = null
constructor() {
}
getId() {
return this.#_jsondata?.info?.object_id
}
/**
* get name
*/
getName() {
return this.#_jsondata?.info?.object_name
}
getShortId() {
return this.#_jsondata?.info?.shortid
}
getInfo() {
return this.#_jsondata?.info
}
getMeta() {
return this.#_jsondata?.meta
}
getSchema() {
return this.#_jsondata?.schema
}
/**
*
*/
clear() {
console.log(`PropertySchema.clear() `)
this.#_jsondata = null
}
/**
*
* @param {*} grpid
* @returns {Object|null}
*/
findGroup(grpid) {
let s = this.getSchema()
if (s) {
for (let i in s.groups) {
let g = s.groups[i]
if (g.id == grpid) return g
}
return null
}
}
/**
*
* @param {*} typeid
* @returns {Object|null}
*/
findPropertyType(typeid) {
let pt = null
const s = this.getSchema();
if (s && s.propertytypes) {
for (const i in s.propertytypes) {
if (i.startsWith('$')) continue
let p = s.propertytypes[i]
let t = p.name + '##' + p.datatype
if (t == typeid) {
pt = p
break
}
}
}
return pt
}
/**
*
* Set schema by JSON object
*
* @param {Object} json_object
* @returns {void}
*/
setByJson(json_object) {
// console.log("SET SCHEMA:")
// console.log(JSON.stringify(json_object))
this.#_jsondata = json_object
// if (json_object.hasOwnProperty('schema')) {
// this.schema = json_object.schema
// }
}
/**
*
* @returns {Object|null}
*/
getAsJson() {
return this.#_jsondata
}
/**
* Get property types from key 'propertytypes'
* as list of
* {
* 'property_type' : '~eq~ ...typeid... ',
* 'value' : '~notnull'
* }
* to pass it as a parameter to endpoint which creates a queryid.
*
*/
getPropertytypeListForQuery() {
let proplist = []
const pt = this.#_jsondata?.schema?.propertytypes
if (pt) {
for (let idx in pt) {
if (idx.startsWith("$")) continue
let prop = pt[idx]
proplist.push({
'property_type': " ~eq~ '" + prop.name + "##" + prop.datatype + "' ",
'value': ' ~notnull~ '
})
}
}
return proplist
}
/**
* Save current schema internally.
* The last saved schema can be restored by restoreSchemaState()
*
*/
saveSchemaState() {
this.#_saved_schema = Func.clone( this.getSchema() )
}
restoreSchemaState() {
if ( this.#_jsondata?.schema ) {
this.#_jsondata.schema = this.#_saved_schema
this.#_saved_schema = null
}
}
/**
* Update property members in schema taking dependencies into account. <br>
* The current state is saved and can be restored by restoreSchemaState().
*
* @param {function} cb
* @param {Object} node Optional node with properties. By default the values in property list are used.
* @returns {Object} updated schema as JSON
*/
updateSchemaByDependencies( cb = null , node = null ) {
console.log( `### [${this.getName()}] <updateSchemaByDependencies()> `)
// if( node ) {
// console.log("UpdateSchema / GOT NODE")
// console.log( JSON.stringify(node) )
// }
// console.log( "HANDLE DEPENDENCIES ... ")
// console.log( JSON.stringify(dependencies) )
this.saveSchemaState()
// Object.assign( {} , propertyschema ) // new Object(propertyschema)
// console.log("NODE ++++:::::")
// console.log( node )
let schema = this.getSchema()
if (node != null) {
for (const pid in schema.propertytypes) {
// console.log("NODE :::::")
// console.log( JSON.stringify(node) )
if (pid === '$order') continue
const p = schema.propertytypes[pid]
const t = p.name + '##' + p.datatype
const v = node.properties[t] || './.'
p.displayvalue = v
}
}
const dependencies = schema.dependencies
if (dependencies) {
for (const dep of dependencies) {
this._handle_dep(dep)
}
}
return cb ? cb(schema) : schema
}
_handle_dep(dep) {
let deplist = dep.deplist
const prop = this.getSchema().propertytypes[dep.$ref]
// console.log("REF..........: " + dep.$ref)
// console.log("PROP.........: " + prop.name + "##" + prop.datatype)
// console.log("VALUES........: " + prop.values)
// console.log("DISPLAY VALUE: " + prop.displayvalue)
function find__(deplist, displayvalue, prop) {
for (const k of deplist) {
// console.log("check : = " + displayvalue )
// console.log( JSON.stringify(k) )
// if ( k.value == displayvalue) {
if (Func.isEqual(k.value, displayvalue, prop)) {
return k
}
}
return null
}
// const depval = deplist.find( e => e.value == prop.displayvalue)
const depval = find__(deplist, prop?.displayvalue, prop)
if (!depval) {
// console.log(prop.displayvalue + " not found in deplist:")
// deplist.forEach(dep => console.log(dep.value))
return
}
if (!Array.isArray(depval.dependencies)) { // also checks for existence
return
}
for (const dependency of depval.dependencies) {
// try to get propertytype to dependency refid
let prop = this.getSchema().propertytypes[dependency.$ref]
if (prop != null) {
// handle property overrides
prop = this._overrideMembers(dependency.overrides, prop)
} else {
// try to get group to dependency refid
let group = this.getSchema().groups[dependency.$ref]
// still nothing found
if (group == null) {
console.log("ERROR, property type id or group id not found: " + dependency.$ref)
continue
}
// handle group overrides
group = this._overrideMembers(dependency.overrides, group)
// this.handle_dep(propertyschema_with_dependencies, dependency)
}
this._handle_dep(dependency)
}
}
_overrideMembers(overrides, obj) {
if (!overrides) return
// copy overridden property type key/values
for (const key in overrides) {
let newval = overrides[key]
if (key === 'values') {
// check list / single value / regex / arbitrary
if (!Array.isArray(newval)) {
newval = newval.trim()
if (newval != '' && newval != '*' && !newval.startsWith('/')) {
newval = new Array(newval)
}
}
}
obj[key] = newval
}
if (overrides.hasOwnProperty('values') && !overrides.hasOwnProperty('displayvalues')) {
delete obj['displayvalues']
}
return obj
}
}
/**
* @category COLNEO infohub
*
* @classdesc
* Service class for Property Schemas
*
*/
export class PropertySchemaServices {
/** @type {Context} */
#_ctx = new Context();
/**
* @since 1.0, 12.2025, jh
* @param {Context} ctx - Context instance
*
*/
constructor(ctx) {
this.#_ctx = ctx;
}
/**
*
* Get schema from standard catalogue in scope: ID = 'cn_properties'
*
* @param {*} name Schema name
* @param {*} cb Promise<ApiResponse>
* @returns {Promise<void>}
*/
async getSchemaByName(name, cb) {
console.log(`### PropertySchema.js <getSchemaByName( ${name} )>`)
const catsrv = new CatalogueServices(this.#_ctx)
catsrv.getCatalogue( 'cn_properties', (ret_cat) => {
if (ret_cat.status < 300) {
const catsid = ret_cat.data.getShortId()
// console.log(`CAT SID : ${catsid}`)
const objsrv = new cnObjectServices(this.#_ctx)
const ndsrv = new NodeServices(this.#_ctx)
const query = {
"filter": `$object_type ~eq~ 'doc_json' $AND $object_name ~eq~ '${name}' `
}
objsrv.getObjects(query, (ret_obj) => {
// console.log("SCHEMA LIST:")
// console.log(ret_obj.dump('SCHEMALIST'))
if (ret_obj.data.length == 1) {
let id = ret_obj.data[0].info.object_id
let node_sid = ret_obj.data[0].info.shortid
const pschema = new PropertySchema()
// console.log(`ID = ${id}`)
ndsrv.getNodeData(node_sid, { members: ['info'] }, (ret_nodedata) => {
// console.log("RET NODE")
// console.log(ret_nodedata.dump('RET NODE'))
// console.log(JSON.stringify(ret_nodedata.data))
ndsrv.getDocument(node_sid, { as_blob: false }, (ret) => {
// console.log("SCHEMA JSON:")
// console.log(ret.dump("S"))
// console.log( JSON.stringify(ret) )
let ps = {
'info': ret_nodedata.data.info,
'schema': ret.data.doc.schema,
'meta': ret.data.doc.meta
}
pschema.setByJson(ps)
return cb(new ApiResponse(200, pschema))
})
})
} else {
return cb(new ApiResponse(404, null, 'name not unique'))
}
}, catsid)
} else {
// return cb(new ApiResponse( ret_cat.status, null ))
return cb(ret_cat)
}
})
}
/**
*
* Load schema from infohub
*
* @param {string} shortid Short id of schema
* @param {*} cb
*
*/
async getSchemaByShortId(shortid, cb) {
console.log("### PropertySchema.js <getSchema(" + shortid + ")>")
const nd_srv = new NodeServices(this.#_ctx)
nd_srv.getDocument(shortid, { as_blob: false }, (ret) => {
if (ret.status < 300) {
console.log("SCHEMA JSON:")
console.log(JSON.stringify(ret))
const pschema = new PropertySchema()
pschema.setByJson(ret)
return cb(new ApiResponse(200, pschema))
} else {
return cb(ret)
}
})
// const pschema = new PropertySchema( Func.createId() )
}
}
Source