Git Product home page Git Product logo

qlik-sse's Introduction

qlik-sse

qlik-sse is an npm package that simplifies the creation of Qlik Server Side Extensions in nodejs.

Check out Server Side Extension for more info and how to get started from the Qlik side.



Getting started

Prerequisites

Before continuing, make sure you:

  • have Node.js >= v8.0.0 installed
  • can configure your Qlik installation (or dockerized Qlik Engine)

Usage

Start by installing qlik-sse:

npm install qlik-sse

Next, create a file foo.js:

const q = require('qlik-sse');

// create an instance of the server
const s = q.server({
  identifier: 'xxx',
  version: '0.1.0',
});

// register functions
s.addFunction(/* */);

// start the server
s.start({
  port: 50051,
  allowScript: true
});

and then run it to start the SSE plugin server:

node foo.js

Configure the SSE in your Qlik installation by following these instructions

If you're running Qlik Sense Desktop (or Qlik Engine) locally, restart it after starting the SSE server to allow Qlik Engine to get the SSE plugin's capabilities.

Assuming you have named the plugin sse, you should now be able to use it's script functions in expressions:

sse.ScriptEval('return Math.random()*args[0]', sum(Sales));

You have now successfully created a Server Side Extension that can be used from within Qlik Sense or Qlik Core.

Take a look at some of the examples on how to add functionality to the SSE.

TODO

  • Documentation
    • API
    • Explain function types SCALAR, AGGREGATION and TENSOR
    • Table load
  • Examples
    • How to use tensorflow with qix data
    • Real use cases
      • linear regression
      • k-means
      • ...
    • Full Qlik example
      • configuring Qlik Engine to use SSEPlugin
      • dockerized environment
      • loading data
      • expression calls
  • Features
    • Script evaluation
    • Error handling

qlik-sse's People

Contributors

miralemd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

qlik-sse's Issues

Not able to write to request.write

For some reason I am unable to write information back within one of my functions. If I log the request before writing the data back I see the following which I suspect is my reason writable: false

Here is the function:

function GetAppMasterItems(request) {
  request.on('data', async function (bundle) {
    console.log(1);
    let tmpItems = []
    let finalItems = []
    async function getData(row) {
      return new Promise(async function (resolve, reject) {
        let masterItems = [];
        let appId = row.duals[0].strData;
        let onlyQwikMaster = row.duals[1].strData;
        let app = await global.openDoc(appId);
        let allInfos = await app.getAllInfos();
        for (var i = 0; i < allInfos.length; i++) {
          if (allInfos[i].qType == 'measure') {
            let measure = await app.getMeasure(allInfos[i].qId);
            let measureLayout = await measure.getProperties();
            if (onlyQwikMaster == 'true') {
              if (typeof measureLayout.qMetaDef.masterId != 'undefined') {
                masterItems.push(
                  [
                    measureLayout.qMetaDef.masterId,
                    "measure",
                    measureLayout.qMeasure.qDef,
                    measureLayout.qMeasure.qLabel,
                    measureLayout.qMetaDef.title,
                    measureLayout.qMetaDef.description,
                    measureLayout.qMeasure.coloring.baseColor.color,
                    appId
                  ]
                )
              }
            }
            else {
              masterItems.push(
                [
                  measureLayout.qMetaDef.masterId,
                  "measure",
                  measureLayout.qMeasure.qDef,
                  measureLayout.qMeasure.qLabel,
                  measureLayout.qMetaDef.title,
                  measureLayout.qMetaDef.description,
                  measureLayout.qMeasure.coloring.baseColor.color,
                  appId
                ]
              )
            }
          }
          if (allInfos[i].qType == 'dimension') {
            let dimension = await app.getDimension(allInfos[i].qId);
            let dimensionLayout = await dimension.getProperties();

            if (onlyQwikMaster == 'true') {
              if (typeof dimensionLayout.qMetaDef.masterId != 'undefined') {
                masterItems.push(
                  [
                    dimensionLayout.qMetaDef.masterId,
                    "dimension",
                    dimensionLayout.qDim.qFieldDefs[0],
                    dimensionLayout.qDim.qLabelExpression,
                    dimensionLayout.qDim.title,
                    dimensionLayout.qDim.descriptionExpression.qStringExpression.qExpr,
                    dimensionLayout.qDim.coloring.baseColor.color,
                    appId
                  ]
                )
              }
            }
            else {
              masterItems.push(
                [
                  dimensionLayout.qMetaDef.masterId,
                  "dimension",
                  dimensionLayout.qDim.qFieldDefs[0],
                  dimensionLayout.qDim.qLabelExpression,
                  dimensionLayout.qDim.title,
                  dimensionLayout.qDim.descriptionExpression.qStringExpression.qExpr,
                  dimensionLayout.qDim.coloring.baseColor.color,
                  appId
                ]
              )
            }
          }
        }
        resolve(masterItems)
      })
    }

    for(var r = 0; r<bundle.rows.length;r++) {
      let data = await getData(bundle.rows[r]);
      tmpItems.push(data);
      console.log(2);
    }
    var test = [];
    for(var one = 0; one< tmpItems.length; one++) {
      for(var two = 0; two < tmpItems[one].length;two++) {
        for(var three = 0; three < tmpItems[one][two].length; three++) {
          test.push({strDate: tmpItems[one][two][three]})
        }
      }
    }
    console.log(3, test);
    console.log(4);
    console.log(request);
    request.write({ "rows": [{ "duals": [{ "strData": "Sucess!" }] }] });
  })
}

AGGREGATION examples return 1 row per bundle versus per request.

Description

In https://github.com/miralemd/qlik-sse/blob/master/examples/functions.md the aggregation example returns a result per bundle. If you have a large enough payload the SSE will return more than one row.

*Note I am using the qcb-qlik-sse which is built using your library and contains your example script.

Example

Qlik Example

qscript

Result

bundle-result

Expected

request-result

Expectation

I'm don't have much experience in Node.js so I'm sure there is a much better way to fix this. However, this is what I used to sum up the bundles before returning the result to Qlik.

  const functionDefinition = function ProcessAllRows(request) {
    let bundleNum = 0;
    const bundleResult = [];
    const rows = [];

    request.on('data', (bundle) => {
      
      console.log('ProcessAllRows: Bundle number ', ++bundleNum) 

      try {

        let v = 0;
        bundle.rows.forEach((row, index) => {
        //   console.log('ProcessAllRows: Row number ', index, row)
          row.duals.forEach((dual) => {
            if (!Number.isNaN(dual.numData)) {
              v += dual.numData;
            }
          });
        });

        bundleResult.push(v)

      }
      catch (error) {
        console.log(error)
      }
      
    });
    
    request.on('end',() => {

        let i = 0;

        bundleResult.forEach((x, index) => {

            i += x;

        })

        rows.push({
            duals: [{ numData: i }],
          });

        console.log('ProcessAllRows: Bundles: ', bundleNum);
        console.log('ProcessAllRows: Write rows: ', JSON.stringify(rows))
        request.write({
            bundleResult
          });
    });

  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.