npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ganister-cypher-reporter

v0.0.76

Published

Report Engine for Graph DB supporting cypher queries

Downloads

4

Readme

Logo

Codeship Status for Ganister/ganister-cypher-reporter

ganister-cypher-reporter

Report nodejs library for graph db supporting cypher

Install

Using npm:

npm i ganister-cypher-reporter

Usage

To produce a report you need the following elements :

  • an array of cypher queries
  • a report template
  • an output option (html/pdf)
  • a neo4j driver authentified instance
const reporter = require('ganister-cypher-reporter');
await reporter.buildReport({
   queries, 
   template, 
   output: 'html', 
   cypherDriver 
});

Cypher Queries

Cypher queries have to be identified with a unique id. Cypher queries can return paths, nodes, relationships or just values

Sample :

const queries = [
  {
    id: 'docs',
    query: `MATCH (d:document) 
    OPTIONAL MATCH (d)-[]->(f:file) 
    OPTIONAL MATCH (d)<-[r]-(p:part) 
    RETURN d as documents, f as files, r as docparts, p as parts ORDER BY documents._createdOn`,
  },
  {
    id: 'partCount',
    query: `MATCH (a:part) WHERE NOT(a)<-[:revises]-() RETURN COUNT(a) as partCount`,
  },
  {
    id: 'userCount',
    query: `MATCH (a:user) RETURN COUNT(a) as userCount`,
  },
  {
    id: 'partBom',
    query: `MATCH p=(a:part{_id:'1'})-[:consumes*]->(items:part) 
            OPTIONAL MATCH (items)-[partDocRel]->(documents:document)
            OPTIONAL MATCH (documents)-[docFileRel]->(file:file)
            RETURN p,partDocRel,documents,docFileRel,file`,
  }
];

Report Template

Report Template Schema :

const optionsSchema = Joi.object({
  queries: Joi.array().required().items(Joi.object({
    id: Joi.string().required(),
    query: Joi.string().required(),
    ordering: Joi.array(),
    structure: Joi.array().items(Joi.object({
      identifier: Joi.string(),
      children: Joi.array().items(Joi.object({
        identifier: Joi.string(),
        pick: Joi.string().allow('last', 'path'),
        children: Joi.array().items(Joi.link('#structureNodeType')),
      })),
    }).id('structureNodeType')),
  })),
  template: Joi.object({
    name: Joi.string().required(),
    locale: Joi.string().required(),
    indentationColumns: Joi.number(),
    author: Joi.string().required(),
    items: Joi.array().items(Joi.object({
      id: Joi.number().required(),
      type: Joi.string().allow('field', 'table', 'graph').required(),
      datatype: Joi.string(),
      mapping: Joi.string(),
      inlineRelationships: Joi.array().items(Joi.string()),
      columns: Joi.array().items(Joi.object({
        graphType: Joi.string(),
        indentation: Joi.boolean(),
        fields: Joi.object(),
        label: Joi.string(),
        category: Joi.string(),
        width: Joi.number(),
        relationships: Joi.array(),
        nodes: Joi.array(),
        columns: Joi.array().items(Joi.link('#column')),
        style: Joi.object(), // cell style
        css: Joi.object(), // header style
      }).id('column')),
      style: Joi.object(), // cell style
      width: Joi.string().allow('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'),
      title: Joi.string(),
    })),
  }).required(),
  output: Joi.string().allow('pdf', 'html'),
  cypherDriver: Joi.object().required(),
  dataConverters: Joi.object(),
});

Template item properties

| Parameters | Explanation |
|---|---|

Column properties

| Parameters | Explanation |
|---|---| | inlineRelationships | In the report template you can define an array of relationships which will be handled as inlineRelationships in a table. If true, whenever such relationship is met, the children of these relationships will appear in a cell to the right of their parent node. If False, then for each child a new row is appended under the parent row.| | graphType (string)| "node" | | indentation (boolean) | defines if this is the indentation column. You can have only one indentation column | | fields (object) | | | label (string) | | | category (string) | | | width (number) | | | relationships (array) | | | nodes (array) | | | columns (array(column)) | | | style (array) | intable cell style | | css (array) | header style|

Field properties

| Parameters | Explanation |
|---|---|

Output

For now we only support 'html' as an output.

Driver

const neo4j = require('neo4j-driver');
const cypherDriver = neo4j.driver('bolt://<neo4jBoltAddress>', neo4j.auth.basic(
  '<username>',
  '<password>',
), { disableLosslessIntegers: true, encrypted: true });

How it works

Running Cypher

An array of cypher queries is provided as an input. Each cypher query object has the following schema:

  Joi.object({
    id: Joi.string().required(),
    query: Joi.string().required(),
    ordering: Joi.array(),
    structure: Joi.array().items(Joi.object({
      identifier: Joi.string(),
      children: Joi.array().items(Joi.object({
        identifier: Joi.string(),
        children: Joi.array().items(Joi.link('#structureNodeType')),
      })),
    }).id('structureNodeType')),
  })

The queries are run by the file cypherQueries.js. They are run asynchronously. Their result is stored in a dataStore variable when all the promise resolve.

The result is obtained from the function parseQueryResult which converts the neo4j default formatting into nodes and relationships. Some cypher may return values instead of nodes/edges. In this case we also return these as key-value pair.

The returned object has the following format:

return {nodes,edges,values};

Converting to table

Once the datastore is built, the publisher scripts convert the datastore into an html table. publisher.tableConverter.js is the script converting the data into lines and columns, while publisher.js is building the table wrapper.

Process

  1. we retrieve the nodes parent-most nodes. Nodes that don't have parents are selected first.
  2. we then iterate the resulting array.
  3. for each item, we manage their inline relationships first and then fetch their non-inline relationships to build a data-tree corresponding to the structure template by running this process recursively.
  4. The data-tree is converted into the table
    1. We first manage the indentation/level columns

Code of Conduct

License

Roadmap

Evolution of features are listed on the project kanban board

Semver

Until ganister-cypher-reporter reaches a 1.0.0 release, breaking changes will be released with a new minor version.