What & Why
- All javascript functions exist within OrientDB as OFunction rows or objects
- My current approach is to export schema into a single gz & ODB server-side functions in json file.
- The problem with this approach is ODB function changes are not tracked with git system, see https://github.com/jymcheong/OpenEDR/commit/a2f0ffb8c6d457c6bca8cdb731091c23490e9c9a
What you will learn
- be proficient with git; fork OpenEDR, make changes, Pull-Request...
- nodeJS scripting related to OrientDB data-structures
- be proficient with Visual Studio Code execution breakpoint stepping through
How
Extend existing export.sh
- Line 15 of exportFunctions_ORole.js was written because the official export method was VERY SLOW.
- First thing first, understand the data-structure of OFunction such that we can represent ALL the server side javascript functions appropriately as individual files
YJ's Documentation
Overview of exportFunctions.js
Purpose of exportFunctions.js
exportFunctions.js is a script to export out all ODB server-side functions into functionsONLY.json.
Output of exportFunctions.js
As mentioned in the previous section, exportFunctions.js will generate a JSON file called functionsONLY.json containing all ODB functions. Let's take a look into functionsONLY.json to find out how the functions are being stored:
As shown in the screenshot above, each function is stored as an object in the array records. For each object i.e. function, it contains 8 name-value pairs:
- @type
- @version
- @class
- idempotent - Specifies whether the function performs idempotent queries or executes non-idempotent commands
- code - Contains code of the function
- name - Specifies the name of the function
- language - Specifies the scripting language used by the function
- parameters - Specifies the parameters of the function
Codes Explanation
Next, we will take a look into exportFunctions.js codes to understand how the script is able to export out the ODB functions into a JSON file.
Line 8:
const fs = require("fs")
Explanation: Include the File System module using the require() method. The Node.js file system module allows you to work with the file system on your computer e.g. read files, create files, write files etc.
Â
Line 9:
const connectODB = require('../../common/orientdb').connectODB;
Explanation: To connect to ODB
Â
Lines 11-30 i.e. exportFunctions()
This is a flow of how exportFunctions() work:
- Connect to ODB
- Create a variable called output of value '{"records":['
- Retrieve ALL data from OFunction and convert it into JSON format. This is then stored into variable results.
- The JavaScript ODB server-side functions are stored in the special OFunction class.
- Structure of OFunction class:
- Output of the query in Line 14:
As shown in the red box above, OFunction class has 8 properties.
From the results of the query, we can see that it is returning all data for every entry in OFunction.
- For each element in array results, it gets parsed into variable line. I added console.log(line) after line 16 to see the value of variable line. This is a snippet of the output:
From the screenshot above, we can see that it is parsing one function at a time to variable line.
For every function, the script will delete the field @rid as seen in line 17 of exportFunctions.js i.e.
delete line["@rid"]
. Lastly, it will convert variable line into JSON string and append it to variable output. Each JSON string that gets appended will be separated by a comma.- After all JSON strings have been appended, "]}" is appended at the end of variable output.
- Write variable output to functionsONLY.json
Â
Line 32:
exportFunctions();
Explanation: Call exportFunctions()
Extend existing exportFunctions.js
Current version of exportFunctions.js will export out all ODB server-side JavaScript functions into a single JSON file. What we need to do is to modify the codes such that the functions are exported out as individual files.
I have a total of 52 ODB server-side JavaScript functions, meaning that there should be 52 JavaScript files after running the modified exportFunctions.js.
To-do list
- Export into JavaScript file per ODB function instead of JSON files (file name should match the ODB function name)
- Move parameter fields to the top as comments
- Replace \n in code field with actual newlines for IDE viewing
Modified exportFunction.js codes
/*** * This script exports every ODB server-side function into individual JavaScript file ***/ const fs = require("fs") const connectODB = require('../../common/orientdb').connectODB; const fields = ["@version","@class","idempotent","code","name","language","parameters"] async function exportFunctions(){ _session = await connectODB() var output = '{"records":['; let results = await _session.query("select @this.toJSON() from OFunction").all(); for(var i = 0; i < results.length; i++) { var line = JSON.parse(results[i]['@this.toJSON()']); delete line["@rid"] var output = '//@type\n' output += line["@type"]+'\n\n' for(var k = 0; k < fields.length; k++) { output += '//'+fields[k]+'\n' output += line[fields[k]]+'\n\n' } //console.log(output) fs.writeFile(line['name']+'.js', output, function(err) { if(err) { return console.log(err); } console.log("The file was saved!"); process.exit(); }); } } exportFunctions();
Codes Explanation
Line 7:
const fields = ["@version","@class","idempotent","code","name","language","parameters"]
Explanation: Create an array fields containing all parameters of class OFunction excluding @type.Â
Lines 16-17:
var output = '//@type\n'
output += line["@type"]+'\n\n'
Explanation: Declare variable output and append //@type (so that parameter becomes a comment) before appending value of @type for the particular function.
Â
Lines 18-21:
for(var k = 0; k < fields.length; k++) {
output += '//'+fields[k]+'\n'
output += line[fields[k]]+'\n\n'
}
Explanation: For each parameter in array fields, append the parameter name as a comment before appending its value into variable output. Repeat until all parameters have been appended.
Â
Line 23:
fs.writeFile(line['name']+'.js', output, function(err) {
Explanation: Write content of variable output into JavaScript file. Name of the JavaScript file is the function name.
Output of modified exportFunctions.js
Before running the script, I had 13 files in the directory.
After running the script, I now have 65 files in the directory.
65 - 13 = 52 newly added files. As shown in the screenshot, the script was able to export out every ODB server-side functions into separate JavaScript files.
Let's compare the way data is structured inside the exported files before and after modification.
This is an example of how function sizeofdb was structured in functionsONLY.json BEFORE modification:
AFTER modification, function sizeofdb is now stored in its own file called sizeofdb.js. This is how it looks like inside sizeofdb.js:
Parameter name is listed as a comment and the parameter value is listed right below the parameter name. \n inside parameter code has been replaced with actual newlines. The way it is structured makes it easy for developers to read or edit the values before making the changes in ODB web UI.
Jym's Review, Test & Integration
Slight refactoring
As explained to , I still need the original / existing exportFunctions.js that creates output files that are directly consumed during installation by Orientdb container's entrypoint script.
common/orientdb.js is an older version of common/odb.js, which I removed & refactored all scripts within exportScripts/.
Really satisfying to work with because our ideas can turn into good implementation. It worked nicely as shown above after slight refactoring. Switching to Github Desktop, we see:
So from a developer perspective, the improvement is we now can track changes in ODB functions that were once opaque to git.
The workflow does not change much, every time ODB functions or schema are updated, we still run export.sh, but the enhanced version will dump changes into a new folder odbFunctions. These scripts are not meant to be imported into ODB, but for git to help track changes.
Why? there are a few cases in the past that changes made started to break ODB (eg. unclose records & whatever exception). We need a way to track & understand how things break!
Other enhancement(s) to this enhancement
- To delete all odbFunctions/*.js before export because we don't want "orphans" (eg. we decide to rename a function..)
- I re-ordered to `const fields = ["@version","@class","idempotent","parameters","name","language","code"]` because from a readability standpoint, we want to know the parameters we use with this function upfront or earlier, rather at the end.
To-do
Implement & test thedelete-before-exportchanges
Update GH master & dev exportScripts & common, still based on old way.
Merge these changes to GH master & dev (including the new script outputs for tracking)
Â