Skip to content

Latest commit

 

History

History
358 lines (283 loc) · 10.1 KB

install-and-run-app.md

File metadata and controls

358 lines (283 loc) · 10.1 KB
sidebar_position
1

Install and Run an App

In this page, you will learn how to install SpringQL in your environment and how to run a demo application written in your favorite language.

SpringQL runs on UNIX-like operating systems, such as Linux and macOS. You might use Cygwin in Windows but it is currently not supported.

Choose a language you use from the table of contents.

Rust

Using SpringQL from Rust is the simplest way since SpringQL itself is developed as a Rust crate.

Prerequisites

Create a bin crate to write a demo

cargo new --bin springql-demo
cd springql-demo

And then, add springql to your Cargo.toml:

# ...
[dependencies]
springql = "*"

Finally, fix main.rs as below:

use springql::{SpringPipeline, SpringConfig};

fn main() {
    // Create a pipeline (dataflow definition in SpringQL).
    let pipeline = SpringPipeline::new(&SpringConfig::default()).unwrap();

    // Create a source stream. A stream is similar to a table in relational database.
    // A source stream is a stream to fetch stream data from a foreign source.
    //
    // `ROWTIME` is a keyword to declare that the column represents the event time of a row.
    pipeline
        .command(
            "
            CREATE SOURCE STREAM source_temperature_celsius (
                ts TIMESTAMP NOT NULL ROWTIME,    
                temperature FLOAT NOT NULL
            );
            ",
        )
        .unwrap();

    // Create a sink stream.
    // A sink stream is a final stream in a pipeline. A foreign sink fetches stream rows from it.
    pipeline
        .command(
            "
            CREATE SINK STREAM sink_temperature_fahrenheit (
                ts TIMESTAMP NOT NULL ROWTIME,    
                temperature FLOAT NOT NULL
            );
            ",
        )
        .unwrap();

    // Create a pump to convert Celsius to Fahrenheit.
    // A pump fetches stream rows from a stream, make some conversions to the rows, and emits them to another stream.
    pipeline
        .command(
            "
            CREATE PUMP c_to_f AS
                INSERT INTO sink_temperature_fahrenheit (ts, temperature)
                SELECT STREAM
                    source_temperature_celsius.ts,
                    32.0 + source_temperature_celsius.temperature * 1.8
                FROM source_temperature_celsius;
            ",
        )
        .unwrap();

    // Create a sink writer as an in-memory queue.
    // A sink writer fetches stream rows from a sink stream, and writes them to various foreign sinks.
    // Here we use an in-memory queue as the foreign sinks to easily get rows from our program written here.
    pipeline
        .command(
            "
            CREATE SINK WRITER queue_temperature_fahrenheit FOR sink_temperature_fahrenheit
            TYPE IN_MEMORY_QUEUE OPTIONS (
                NAME 'q'
            );
            ",
        )
        .unwrap();

    // Create a source reader as a TCP server (listening to tcp/9876).
    // A source reader fetches stream rows from a foreign source, and emits them to a source stream.
    //
    // Dataflow starts soon after this command creates the source reader instance.
    pipeline
        .command(
            "
            CREATE SOURCE READER tcp_trade FOR source_temperature_celsius
            TYPE NET_SERVER OPTIONS (
                PROTOCOL 'TCP',
                PORT '9876'
            );
            ",
        )
        .unwrap();

    // Get a row,
    while let Ok(row) = pipeline.pop("q") {
        // fetch columns,
        let ts: String = row.get_not_null_by_index(0).unwrap();
        let temperature_fahrenheit: f32 = row.get_not_null_by_index(1).unwrap();
        // and print them.
        eprintln!("{}\t{}", ts, temperature_fahrenheit);
    }
}

Run the demo

In your terminal, start the demo app:

cargo run

In another terminal, launch TCP clients with nc connecting to port 9876:

echo '{"ts": "2022-01-01 13:00:00.000000000", "temperature": 5.3}' | nc localhost 9876
echo '{"ts": "2022-01-01 14:00:00.000000000", "temperature": 6.2}' | nc localhost 9876

Then you'll get the following outputs:

2022-01-01 13:00:00.000000000   41.54
2022-01-01 14:00:00.000000000   43.16

Finished! You get the temperatures in Celsius translated into Fahrenheit by SpringQL.

C

Prerequisites

  • gcc command
  • nc (netcat) command

Place the header file and dynamic library

mkdir springql-demo
cd springql-demo

Then go to releases page of SpringQL-client-c. Download the latest version of springql_client-<your arch & OS>-debug.zip 1 and unzip it.

Then copy the header file and dynamic library to the springql-demo directory.

cp /path/to/download/springql_client-<your arch & OS>-debug/* .

Write a demo

Create main.c and write the demo code as below:

#include <assert.h>
#include <string.h>
#include <stdio.h>

#include "springql.h"

void abort_with_report()
{
    SpringErrno errno_;
    char errmsg[1024];
    spring_last_err(&errno_, errmsg, 1024);
    fprintf(stderr, "Error occurred (%d): %s", errno_, errmsg);
    abort();
}

void assert_ok(SpringErrno ret)
{
    if (ret != Ok)
    {
        abort_with_report();
    }
}

void assert_not_null(void *p)
{
    if (p == NULL)
    {
        abort_with_report();
    }
}

int main()
{
    SpringErrno ret;

    SpringConfig *config = spring_config_default();
    assert_not_null(config);

    // Create a pipeline (dataflow definition in SpringQL).
    SpringPipeline *pipeline = spring_open(config);
    assert_not_null(pipeline);

    // Create a source stream. A stream is similar to a table in relational database.
    // A source stream is a stream to fetch stream data from a foreign source.
    //
    // `ROWTIME` is a keyword to declare that the column represents the event time of a row.
    ret = spring_command(
        pipeline,
        "CREATE SOURCE STREAM source_temperature_celsius ("
        "    ts TIMESTAMP NOT NULL ROWTIME,"
        "    temperature FLOAT NOT NULL"
        ");");
    assert_ok(ret);

    // Create a sink stream.
    // A sink stream is a final stream in a pipeline. A foreign sink fetches stream rows from it.
    ret = spring_command(
        pipeline,
        "CREATE SINK STREAM sink_temperature_fahrenheit ("
        "    ts TIMESTAMP NOT NULL ROWTIME,"
        "    temperature FLOAT NOT NULL"
        ");");
    assert_ok(ret);

    // Create a pump to convert Celsius to Fahrenheit.
    // A pump fetches stream rows from a stream, make some conversions to the rows, and emits them to another stream.
    ret = spring_command(
        pipeline,
        "CREATE PUMP c_to_f AS"
        "    INSERT INTO sink_temperature_fahrenheit (ts, temperature)"
        "    SELECT STREAM"
        "       source_temperature_celsius.ts,"
        "       32.0 + source_temperature_celsius.temperature * 1.8"
        "    FROM source_temperature_celsius;");
    assert_ok(ret);

    // Create a sink writer as an in-memory queue.
    // A sink writer fetches stream rows from a sink stream, and writes them to various foreign sinks.
    // Here we use an in-memory queue as the foreign sinks to easily get rows from our program written here.
    ret = spring_command(
        pipeline,
        "CREATE SINK WRITER queue_temperature_fahrenheit FOR sink_temperature_fahrenheit"
        "    TYPE IN_MEMORY_QUEUE OPTIONS ("
        "        NAME 'q'"
        "    );");
    assert_ok(ret);

    // Create a source reader as a TCP server (listening to tcp/9876).
    // A source reader fetches stream rows from a foreign source, and emits them to a source stream.
    //
    // Dataflow starts soon after this command creates the source reader instance.
    ret = spring_command(
        pipeline,
        "CREATE SOURCE READER tcp_trade FOR source_temperature_celsius"
        "    TYPE NET_SERVER OPTIONS ("
        "        PROTOCOL 'TCP',"
        "        PORT '9876'"
        "    );");
    assert_ok(ret);

    SpringSinkRow *row;
    while (1)
    {
        // Get a row,
        row = spring_pop(pipeline, "q");
        assert_not_null(row);

        // fetch columns,
        const int ts_len = 128;
        const char ts[ts_len];

        int r = spring_column_text(row, 0, (char *)ts, ts_len);
        assert(r == strlen(ts));

        float temperature_fahrenheit;
        ret = spring_column_float(row, 1, &temperature_fahrenheit);
        assert_ok(ret);

        // and print them.
        fprintf(stderr, "%s\t%f\n", ts, temperature_fahrenheit);

        // Free the row
        spring_sink_row_close(row);
    }

    // Free the remaining resources
    ret = spring_close(pipeline);
    assert_ok(ret);

    ret = spring_config_close(config);
    assert_ok(ret);

    return 0;
}

Build the demo

You need to link to the libspringql_client in build-time.

gcc main.c -lspringql_client -L.

Then, you'll get a.out as a runnable binary.

Run the demo

In your terminal, start the demo app. You also need to link to the libspringql_client in run-time.

LD_LIBRARY_PATH=. ./a.out
DYLD_LIBRARY_PATH=. ./a.out

In another terminal, launch TCP clients with nc connecting to port 9876:

echo '{"ts": "2022-01-01 13:00:00.000000000", "temperature": 5.3}' | nc localhost 9876
echo '{"ts": "2022-01-01 14:00:00.000000000", "temperature": 6.2}' | nc localhost 9876

Then you'll get the following outputs:

2022-01-01 13:00:00.000000000   41.54
2022-01-01 14:00:00.000000000   43.16

Finished! You get the temperatures in Celsius translated into Fahrenheit by SpringQL.

Footnotes

  1. See https://doc.rust-lang.org/nightly/rustc/platform-support.html to correctly select <your arch & OS>.