C, and other native languages

Nexyron exposes a C interface. Beyond C and C++ itself, this is the route for any language with a foreign-function interface: Go, C#, Java, Swift, Kotlin, Ruby, PHP and others can all call it.

Opening a database

#include <nexyron.h>

int main(void) {
    nexyron_db *db = NULL;
    if (nexyron_open("./business.nexyron", &db) != NEXYRON_OK) {
        return 1;
    }

    nexyron_result *result = NULL;
    if (nexyron_query(db, "MATCH (c:Customer) RETURN count(c) AS customers",
                      &result) == NEXYRON_OK) {
        int64_t customers = 0;
        nexyron_row_get_int(result, 0, "customers", &customers);
        printf("%lld\n", (long long) customers);
        nexyron_result_free(result);
    }

    nexyron_close(db);
    return 0;
}

The rules that matter

Every call returns a status. Check it. A failed query returns a message explaining what was wrong and what to use instead; retrieve it rather than discarding it.

if (status != NEXYRON_OK) {
    const char *message = nexyron_last_error(db);
    fprintf(stderr, "nexyron: %s\n", message);
}

You free what you receive. Results are owned by the caller. Free each one when finished, and free the database last. In a long-running process a result that is never freed is a leak that grows with traffic.

Strings are UTF-8 and borrowed. A string returned from a result is valid until that result is freed. Copy it if it must outlive the result.

One database handle, shared. Open once, use from multiple threads, close on shutdown.

Binding from another language

Two things are worth doing in the wrapper rather than leaving to callers.

Tie freeing to your language's lifetime rules. Whatever your language calls it: a destructor, a finalizer, defer, using, a context manager. Manual freeing at every call site will eventually be forgotten.

Turn status codes into your language's errors. Carry the message through. The guidance in it is specific to the query that failed and is the main reason debugging is quick.

Beyond that, keep the wrapper thin. Parameters and typed rows are handled by the engine; a wrapper that re-implements them adds bugs rather than convenience.

Identifiers

Return identifiers as strings with element_id() when they will reach a runtime without exact 64-bit integers, which includes JavaScript and some scripting languages. In C itself they are exact, but a wrapper that returns strings keeps one habit across every language you target.