/dancing_sql

This is an incoming SQLite clone compiled to WebAssembly.

Primary LanguageCGNU Affero General Public License v3.0AGPL-3.0

DanCing SQL 💃📂 (DCS)

This is an incoming SQLite clone compiled to WebAssembly — heavily inspired by this.

Getting Started

Dancing SQL is now distributed with the Tarantella Package Manager — a tool I've made to simplify setup of projects like these!

To install the Tarantella Package Manager, you need the Rust toolchain — for instructions on how to install it, see this. Once you're done with that, you can install Tarantella by running: cargo install tarantella.

To start-off, setup a new main module WASM project with: tapm new my-first-project --server. This will start a new C WASM project with:

  • a build folder,
  • a dependencies folder,
  • an index.js,
  • a Makefile,
  • a releases folder,
  • a src folder with some starting code in main.c, and a
  • Tarantella.toml file.

Next, add the latest version of Dancing SQL as a dependency with: tapm add "danbugs/dancing_sql". This will automatically download DCS to your dependencies folder, add it to your Tarantella.toml list of dependencies, and append dependencies/dcs/dcs.o to the DEPENDENCIES variable of your Makefile to facilitate compilation.

Now, replace the content of src/main.cwith:

#include <stdio.h>
#include <emscripten.h>
#include "../dependencies/dcs/dcs.h"
// ^^^ adds necessary structs and definitions from DCS

extern Statement execute_sql(sql_t raw_sql, Table *table);
extern Table *open_table(char *table_name);
extern void close_table(Table *table);
// ^^^ group of functions coming from ../dependencies/dcs/dcs.o

int main()
{
    Table *table = open_table("mytable");
    // ^^^ creating a new default table.
    // Default Structure:
    // - INTEGER id, and
    // - VARCHAR(255) content ~ meant to contain all necessary info in sort of a JSON.stringify-ed way.
    // Notes:
    // - content will be trucated at 255 characters.
    // - just like VARCHAR, you content does not
    // need to have 255 bytes but; regardless,
    // 255 will still be allocated for that field.

    sql_t insert_s = SQL(INSERT 0 '{"name":"dan"}');
    // ^^^ un-executed insert statement.
    // Notes:
    // - 'INSERT' must be upper-case, the VM
    // is case-sensitive.
    // - There are currently no checks to ensure
    // the ID is unique.

    sql_t select_s = SQL(SELECT);
    // ^^^ un-executed select statement.
    // Note: 'SELECT' must be upper-case, the VM
    // is case-sensitive.

    Statement insert_r = execute_sql(insert_s, table);
    Statement select_r = execute_sql(select_s, table);
    printf("select: %s\n", select_r.select_result);
    // ^^^ executes SQL statements and
    // prints results to console.

    close_table(table);
    // ^^^ frees malloc-ed table and its'
    // attributes and saves data to database file.
}

Next, in your Makefile, change the EMCC_CFLAGS to:

EMCC_CFLAGS=-s MAIN_MODULE=1 -lnodefs.js -s EXIT_RUNTIME=1

Now, to finish off, run tapm build to compile our code and tapm run to test it out. You should see the following in your console: getting-started-result

Your information will be persisted to a file at db/mytable.db.

You can view the mytable.db file directly w/ a hex editor. In VSCode, you can install this extension, right click the mytable.db file and select "Show hexdump". You should see:

getting-started-hexdump-of-db-file

Notes to Self

Use: emcc .\src\main.c ..\src\dcs.c -l"nodefs.js" -s EXIT_RUNTIME=1 -fsanitize=address -s ALLOW_MEMORY_GROWTH -gsource-map --source-map-base http://localhost:3000/test -o test/example.js to check for mem-leaks and whatnot.