const glob = require("glob"); const path = require("path"); const fs = require("fs-extra"); const dayjs = require("dayjs"); const conf = require(`${process.env.dirtown}/conf.json`); const Checkjson = require(`./Checkjson.js`); /* This manage Objects for indexing and check and act to CRUD objectpath/objects/schema/objectName.json /objectNames/searchindes/objectName_valueofkey_uuildlist.json /objectNames/uuid.json */ const Odmdb = {}; /* Input: metaobject => data mapper of Key: Value objname + an object {} + action Checkjson => get a valid or not answer objname + an object {} + action search => apply matching algo to find probalistic object id objname + action index => update /searcindex of objects concern */ Odmdb.setObject = (schemaPath, objectPath, objectName, schema, lgjson, lg) => { /** * * @schemapath {string} path to create or replace a schema ${schemaPath}/schema/ * @objectPath {string} path where object are store * @objectName {string} name of the object * @schema {object} the json schema for this object * @lgjson {object} the json file for a specific language * @lg {string} the 2 letters language * * a shema : * schemaPath/schema/objectName.json * /lg/objectName_{lg}.json * an object : * objectPath/objectName/idx/confjson ={"schema":"relativpathfile or http"} * /uniqueid.json defining schema * */ if (!fs.existsSync(schemaPath)) { return { status: 404, ref: "Odmdb", info: "pathnamedoesnotexist", moreinfo: { fullpath: schemaPath }, }; } if (!fs.existsSync(objectPath)) { return { status: 404, ref: "Odmdb", info: "pathnamedoesnotexist", moreinfo: { fullpath: objectPath }, }; } // store schema file if not empty undefined or {} if ( schema && !(Object.keys(schema).length === 0 && schema.constructor === Object) ) { fs.outputJSONSync(`${schemaPath}/schema/${objectName}.json`, schema, { spaces: 2, }); } if ( lgjson && lg && !(Object.keys(lgjson).length === 0 && lgjson.constructor === Object) ) { fs.outputJSONSync(`${schemaPath}/lg/${objectName}_${lg}.json`, lgjson, { spaces: 2, }); } //create environnement object with the new schema config if (!fs.existsSync(`${objectPath}/${objectName}`)) { fs.outputJsonSync( `${objectPath}/${objectName}/idx/confjson`, { schema: `${schemaPath}/schema/${objectName}.json` }, { spaces: 2 } ); } return { status: 200 }; }; Odmdb.schema = (schemaPath, objectName, withschemacheck) => { // Return schema if exist and objectpath contain objectName { status:200;data:schema} if (!fs.existsSync(`${schemaPath}/${objectName}`)) return { status: 404, info: "|odmdb|schemapathnamedoesnotexist", moreinfo: `${schemaPath}/${objectName}`, }; if (!fs.existsSync(`${objectPath}/schema/${objectName}.json`)) { return { status: 404, info: `|odmdb|schemanotfound`, moreinfo: `file not found ${schemaPath}/schema/${objectName}.json`, }; } const schema = fs.readJsonSync(`${schemaPath}/schema/${objectName}.json`); // check schema apx validity specificities primary unique ans searchindex if (withschemacheck) { if (!schema.apxprimarykey) { // code 422: unprocessable Content return { status: 422, info: "|Odmdb|apxprimarykeynotfound", moreinfo: `${schemaPath}/schema/${objectName}.json`, }; } else { if ( !( schema.apxsearchindex[schema.apxprimarykey] && schema.apxsearchindex[schema.apxprimarykey].list ) ) { return { status: 422, info: "|Odmdb|apxprimaryketnotinsearchindexlist", moreinfo: `${schemaPath}/schema/${objectName}.json`, }; } if (schema.apxuniquekey) { schema.apxuniquekey.forEach((k) => { if ( !( schema.apxsearchindex[k] && schema.apxsearchindex[k][schema.apxprimarykey] ) ) { return { status: 422, info: "|Odmdb|apxuniquekeynotinsearchindex", moreinfo: `${schemaPath}/schema/${objectName}.json`, }; } }); } } const validschema = Checkjson.schema.validation(schema); if (validschema.status != 200) return validschema; } return { status: 200, data: schema, }; }; Odmdb.Checkjson = (objectPath, objectName, data, withschemacheck) => { /* @objectPath path to the folder that contain /objects/objectName/ /lg/objectName_{lg}.json /schema/objectName.json @objectName name of object @data data to check based on schema objectName definition @return status:200 Data is consistent with schema and primarykey does not exist status:201 Data is consistent with schema and primarykey does already exist status:other means unconsistent schema: 404: schema does not exist or unconsitent data and schema from Checkjson.js Checkjson.schema.data */ const res = { status: 200 }; //get schema link of object const schemaPath = fs.readJsonSync( `${objectPath}/${objectName}/idx/confjson` )["schema"]; if (schemaPath.substring(0, 4) == "http") { // lance requete http pour recuperer le schema } else { schema == "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; } // check schema validity const schema = Odmdb.schema(objectPath, objectName, withschemacheck); if (schema.status != 200) return schema; console.log("SCHEMA for checking:"); console.log(schema.data); console.log("DATA to check:"); console.log(data); // withschemacheck at false, if check then it is done at Odmdb.schema const validate = Checkjson.schema.data(schema.data, data, false); if (validate.status != 200) { return validate; } if ( schema.data.apxprimarykey && data[k] && fs.existsSync(`${objectPath}/${objectName}/${data[k]}.json}`) ) { res.status = 201; // means created => exist an object with this primary key } if (schema.data.apxuniquekey) { schema.data.apxuniquekey.forEach((k) => { if ( data[k] && fs.existsSync( `${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}` ) && fs.readJsonSync( `${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}` )[k] ) { res.status = 201; // means created => exist as primary key } }); } return res; }; Odmdb.search = (objectPath, objectName, search) => { /* @search= { txt: string, algo: match | pattern | fuzzy fieldstring:[list of field], indexfilter:{index1:[val1,val2 | ] } } Return data:[uuids] example: search exact match hill in townId heavy search={txt:"hill",algo:"match",fieldstring:"toxnId"} light search={txt:"hill", algo:"match", indexfilter:{"key":"townId","value":[]}} light search={txt:"hill", algo:"match", indexfilter:{"key":"nationId","value":"ants"}} */ const schema = Odmdb.schema(objectPath, objectName); if (schema.status != 200) return schema; }; Odmdb.get = (objectPath, objectName, uuidprimarykeyList, fieldList) => { /* @uuidprimarykeyList list of uuid requested @fieldList key to return for each object Return objectName {status:200; data:{found:[{primarykey,field}],notfound:[uuid]} if all primarykey exist then data.notfound does not exist if all primarykey does not exist data.found does not exist */ const res = { status: 200, data: {} }; uuidprimarykeyList.forEach((id) => { if (fs.existsSync(`${objectPath}/${objectName}/${id}.json`)) { if (!res.data.found) res.data.found = []; const objectdata = fs.readJsonSync( `${objectPath}/${objectName}/${id}.json` ); if (!fieldList) { res.data.found.push(objectdata); } else { const objinfo = {}; fieldlList.forEach((k) => { if (objectdata[k]) objinfo[k] = objectdata[k]; }); res.data.found.push(objinfo); } } else { if (!res.data.notfound) res.data.notfound = []; } }); return res; }; Odmdb.create = (objectPath, objectName, data) => { /* Create an objects data into objectName @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json @objectName name of object @data data to check based on objectsMeta definition */ }; Odmdb.update = (objectPath, objectName, data) => { /* Create an objects data into objectName @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json @objectName name of object @data data to check based on objectsMeta definition */ }; Odmdb.delete = (objectPath, objectName, data) => { /* Create an objects data into objectName @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json @objectName name of object @data data to check based on objectsMeta definition */ }; /*console.log("test Odmdb"); console.log( Odmdb.check( "/media/phil/usbfarm/apxtrib/nationchains/socialworld/objects", "nations", { nationId: "123", status: "unchain" } ) );*/ Odmdb.updatefromidxall = (objectname, idxname, data, lastupdate) => { /** * Update all itm of objectname from index idx/idxname with data * if itm exist in local and not in data then /ojectname/conf.json.lastupdate = now * not then /ojectname/conf.json.lastupdate = lastupdate * this way mean next time server A want to refresh from B its lastupdate < than on A */ let conflastupdate = 0; let localidx = {}; if ( fs.existsSync(`${conf.dirapi}/nationchains/${objectname}/idx/${idxname}`) ) { localidx = fs.readJsonSync( `${conf.dirapi}/nationchains/${objectname}/idx/${idxname}` ); } Object.keys(data).forEach((id) => { if (localidx[id]) { if ( localidx[id].dt_update && data[id].dt_update && localidx[id].dt_update > data[id].dt_update ) { // means local information is fresher than the one in data for replacement conflastupdate = dayjs(); } else { // replace itm with data localidx[id] = data[id]; fs.outputJsonSync( `${conf.dirapi}/nationchains/${objectname}/itm/${id}.json`, data[id] ); } } else { // add itm localidx[id] = data[id]; fs.outputJsonSync( `${conf.dirapi}/nationchains/${objectname}/itm/${id}.json`, data[id] ); } }); //check if it miss id in fresher update means conf.lastupdate will be now to indicate Object.keys(localidx).forEach((id) => { if (!data[id]) { conflastupdate = dayjs(); } }); // update the object files if (conflastupdate == 0) conflastupdate = lastupdate; fs.outputJSONSync( `${conf.dirapi}/nationchains/${objectname}/idx/${idxname}`, localidx ); const objconf = fs.readJsonSync( `${conf.dirapi}/nationchains/${objectname}/conf.json` ); objconf.lastupdate = conflastupdate; fs.outputJsonSync( `${conf.dirapi}/nationchains/${objectname}/conf.json`, objconf ); return { status: 200, ref: "Odmdb.js", info: "Successfullupdate", data: { objectname, idxname, lastupdate }, }; }; module.exports = Odmdb;