Search code examples
javascriptdatabaseorientdborientjs

How to store SVGs in OrientDB using OrientJS


My webapp needs to include the feature to save SVG files to the database so that they can be fetched and rendered in the browser with the ability to make use of CSS to style parts of the image based on parsing the XML. Storing as base64 does not do the job, because then it is rendered to the DOM without making the XML available for parsing and manipulation.

The docs on working with binary files in orientjs are extremely thin, and I cannot find any suitable examples out there, so I'm pretty much stuck.

Any help would be appreciated.


Solution

  • An svg is nothing else but a string of XML syntax.

    E.g. consider the following svg:

    var svg = `<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
      <circle cx="100" cy="100" r="50" stroke="black" stroke-width="5" fill="red" /></svg>`
    

    You pretty much have two options:

    1. Store the svg as a simple String
    2. Store the svg as a base64 encoded String

    If your svg only contains ASCII characters, method 1 should be fine. Otherwise you need to use method 2. Note: method 2 can be used to store any type of file!!!

    An example of both methods in OrientJS:

    // First npm install the following packages
    npm install orientjs
    npm install await-to-js
    

    Then create a file app.js and run it:

    const OrientDBClient = require("orientjs").OrientDBClient;
    const to = require('await-to-js').default;
    
    // SVG EXAMPLE IMAGE
    var svg = `<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
    <circle cx="100" cy="100" r="50" stroke="black" stroke-width="5" fill="red" /></svg>`
    
    connect().then(async function(db) {
    
        // Add class to database
        [err, result] = await to(
            db.session.class.create('Example', 'V')
        );
        if (err) { console.error(err); };
    
        // Add property image to class
        [err, result] = await to(
            db.session.command('CREATE PROPERTY Example.image STRING').all()
        );
        if (err) { console.error(err); };
    
        // Add property name to class
        [err, result] = await to(
            db.session.command('CREATE PROPERTY Example.type STRING').all()
        );
        if (err) { console.error(err); };
    
        // *****************************************************************
        // ********************** USING PLAIN STRING ***********************
        // *****************************************************************
    
        // Add node to class with image stored as plain string (just use var [svg])
        [err, result] = await to(
            db.session.insert().into('Example').set({image: svg, type: 'string'}).one()
        );
        if (err) { console.error(err); };
    
        // Retrieve simple string from database
        [err, result] = await to(
            db.session.select('image').from('Example').where({type: 'string'}).one()
        );
        if (err) { console.error(err); };
        // Output svg XML to the console
        console.log(result.image);
    
        // *****************************************************************
        // ********************* USING BASE64 ENCODING *********************
        // *****************************************************************
    
        // Convert to base64
        var buf = Buffer.from(svg, 'utf-8').toString("base64");
    
        // Add node to class with image encoded as base64
        [err, result] = await to(
            db.session.insert().into('Example').set({image: buf, type: 'base64'}).one()
        );
        if (err) { console.error(err); };
    
        // Retrieve base64 encoded svg from database
        [err, result] = await to(
            db.session.select('image').from('Example').where({type: 'base64'}).one()
        );
        if (err) { console.error(err); };
    
        // Output svg XML to the console
        var output = Buffer.from(result.image, 'base64');
        console.log(output.toString('ascii'));
    })
    
    async function connect() {
        // Connect to Server
        [err,client] = await to(OrientDBClient.connect({
            host:   'localhost',    // Specify your host here
            port:   '2424'          // Make sure you call the HTTP port
        }));
        if (err) {
            console.log("Cannot reach OrientDB. Server is offline");
            return false;
        }
    
        // Connect to Database.
        [err,session] = await to(client.session({ 
            name:       'demodb',   // Name of your database
            username:   'admin',    // Username of your database
            password:   'admin'     // Password of your database
        }));
        if (err) {
            console.log("Database doesn't exist.");
            return false;
        }
    
        // Add handler
        session.on('beginQuery', (obj) => {
            console.log(obj);
        });
    
        // Check if session opens
        console.log("Successfully connected to database.");
        var graph = {client, session};
        return graph;
    }
    

    This code will create a class Example that has properties image and type and will then create two vertices: one where the svg is saved as a string and one where the svg is saved as a base64 encoded string. It also shows how to retrieve both images again into javascript.

    After you've retrieved the files, you can then pass them to your front-end and render them on the DOM, at which point any CSS styles that are defined on the DOM will also be applied.

    I hope that answers your question.