Skip to content

datasource.client ^v2.7.203 ​

Creates a configurable client for working with a datasource.

Why use datasource.client?

This newer client API is the preferred way to run datasource queries.

Compared to the older datasource.select(), datasource.query() and datasource.insert() methods, it provides:

  • Streaming rows instead of loading everything into memory
    (ideal for large datasets)
  • Fine-grained configuration
    (error handling, return types, fetch size, query timeouts)
  • Supports BigQuery and other future non JDBC Datasources
  • Uses a connection pool doesn't create a new connection per query like old methods, that would of potentially exhausted database connections.
  • Termination of a process will also terminate any ongoing queries.

If you are writing new scripts, you should prefer datasource.client() over legacy datasource methods.

Creating a client ​

js
const client = datasource.client("Internal Datastore");

Parameters ​

  • datasource – The name of a datasource.

The returned client exposes configuration methods (chainable) and query methods.

Configuration methods ​

All configuration methods are chainable and optional.
If you don't call them, sensible defaults are used.

Quick overview ​

MethodTypeDefaultApplies toDescription
alwaysReturnStringsbooleanfalseJDBC + BigQueryReturn everything as strings (legacy mode).
suppressErrorsbooleantrueJDBC + BigQueryLog errors instead of throwing.
setFetchSizenumber0JDBC onlyHint to driver for row prefetch window.
setQueryTimeoutSecondsnumber0JDBC onlyQuery timeout in seconds.
  • client.alwaysReturnStrings(flag) ​

    Controls how column values are returned to your script.

    js
    client.alwaysReturnStrings(true | false);
    • Default: false

    • When false (recommended):

      • Numeric columns are returned as JavaScript numbers where possible.
      • Binary/byte columns may be exposed as base64-compatible data for scripts.
    • When true:

      • All values are returned as strings, matching the behaviour of the older datasource APIs.

    Use true if you want to preserve compatibility with older MODLR scripts that assume everything is a string.

  • client.suppressErrors(flag) ​

    Controls whether SQL/driver errors are thrown or just logged.

    js
    client.suppressErrors(true | false);
    • Default: true
    • When true:
      • Errors are logged and the client attempts to continue, similar to the older datasource helpers.
    • When false:
      • Errors will be thrown into your script so you can handle them explicitly with try / catch.

    This is useful when you need strict error handling in complex scripts.

  • client.setFetchSize(size) ​

    Configures the JDBC fetch/streaming window, if supported by the driver.

    js
    client.setFetchSize(500);
    • Default: 0 (use driver default)
    • Applies to: JDBC datasources only (ignored for BigQuery).

    This controls how many rows are prefetched from the database at a time when streaming via select. Larger values may reduce round trips but increase memory usage per stream.

  • client.setQueryTimeoutSeconds(seconds) ​

    Sets a query timeout (in seconds), if supported by the driver.

    js
    client.setQueryTimeoutSeconds(30);
    • Default: 0 (no timeout)
    • Applies to: JDBC datasources only (ignored for BigQuery).

    Use this to prevent long-running queries from blocking forever.

Generic Methods ​

select(sql, [params]) ​

Executes a SELECT and returns a row iterator. Rows are streamed as you iterate; they are not all loaded into memory.

js
const rows = client.select(
    "SELECT id, email, created_at FROM users WHERE active = ?",
    [true],
);

for (const row of rows) {
    console.log(row.id, row.email, row.created_at);
}

Notes ​

  • params is optional. When supplied, ? placeholders in sql are bound positionally.
  • The result is iterable (e.g. usable in for…of).
  • Once iteration completes, the underlying cursor is closed and the rows are no longer available.
  • On JDBC datasources, this supports streaming to avoid pulling the entire result set into memory.
  • Nested queries are supported in a limited way (e.g. running another query inside the loop), but should be avoided in normal code.

If the script is cancelled, the iterator will stop yielding rows.


first(sql, [params]) ​

Executes a SELECT and returns the first row as a plain object, or null/undefined when there are no results.

js
const user = client.first("SELECT id, email FROM users WHERE id = ?", [42]);

if (user) {
    console.log(`User email: ${user.email}`);
} else {
    console.log("User not found.");
}

This is a convenience wrapper over select when you only care about a single row.


selectAll(sql, [params]) ​

Executes a SELECT and returns all rows as an array (not streamed).

Use this when you do not want an itterator and get a list of rows returned, but be aware, all rows will be in memory.

js
const rows = client.selectAll(
    "SELECT id, email, status FROM users WHERE active = ?",
    [true],
);

console.log("Total active users:", rows.length);

for (const row of rows) {
    console.log(row.id, row.email, row.status);
}

execute(sql, [params]) ​

Executes a write statement (INSERT/UPDATE/DELETE/DDL) and returns the number of affected rows and the generated key (if applicable and the datasource supports it).

js
const result = client.execute(
    "UPDATE users SET last_login_at = CURRENT_TIMESTAMP WHERE id = ?",
    [42],
);

if (result.affected === 1) {
    console.log("User login timestamp updated.");
}
js
const result = client.execute(`INSERT INTO users ("John", "Doe", ?)`, [50]);

console.log(result.generatedKey); // Returns ID of John in this example.

Parameters ​

  • sql – An INSERT, UPDATE, DELETE or CREATE/ALTER/DROP statement.
  • params – Optional list of parameterized values to bind to ? placeholders.

BigQuery Client Specifics ​

When the datasource is a BigQuery connection, datasource.client exposes read-oriented helpers and metadata listing.

js
// List datasets within a project
const datasets = bq.listDatasets("my_project_id");

// List tables within a dataset
const tables = bq.listTables("my_project_id.reporting");

Query Parameters ​

BigQuery supports named parameters, not positional ? placeholders like JDBC.
Parameters must be named p1, p2, p3, … and supplied as shown below:

js
const row = bq.first(
    `
    SELECT
        *
    FROM
        \`my_project.reporting.orders\`
    WHERE
        order_id = @p1
        AND country  = @p2
    LIMIT 1
    `,
    {
        p1: "AUS-103939",
        p2: "AU",
    },
);

console.log(row);

BigQuery updates ​

At this time, write operations via client.update are not supported for BigQuery.

Closing Resources ​

For normal usage you do not need to manually close anything; cursors and connections will be returned to their connection pools automatically when:

  • A select iterator finishes reading all rows, or
  • The script completes or cancels.

Manual closing is exposed only for advanced scenarios:

js
const client = datasource.client("Reporting Database");

// Close all open iterators created by this client and return connections to the pool
client.close();

// If you kept a specific iterator:
const iterator = client.select("SELECT * FROM users");
for (const row of iterator) {
    // ...
}
// You may explicitly close just this one:
iterator.close();

Use this only when you are managing complex, long-lived scripts that hold on to multiple iterators.

Full Example ​

js
// Create a client for your datasource
const client = datasource.client("Internal Datastore")
    .suppressErrors(false); // throw errors instead of silently logging

try {
    // Fetch a single row
    const user = client.first("SELECT id, email FROM users WHERE id = ?", [42]);

    if (user) {
        console.log("User found:", user.email);
    } else {
        console.log("User not found");
    }

    // Stream multiple rows (preferred for large datasets)
    const rows = client.select("SELECT id, email FROM users WHERE active = ?", [
        true,
    ]);

    for (const row of rows) {
        console.log(`User ${row.id}: ${row.email}`);
    }

    // Load all rows into memory
    const allUsers = client.selectAll(
        "SELECT id, status FROM users WHERE active = ?",
        [true],
    );

    console.log("Total active users:", allUsers.length);

    // Execute a write operation
    const result = client.execute(
        "UPDATE users SET last_login_at = CURRENT_TIMESTAMP WHERE id = ?",
        [42],
    );

    console.log("Rows affected:", result.affected);

    // Insert example with generated key
    const insert = client.execute(
        "INSERT INTO users (name, age) VALUES (?, ?)",
        ["John Doe", 30],
    );

    console.log("New user ID:", insert.generatedKey);
} catch (err) {
    console.error("Datasource error:", err.message);
} finally {
    // Optional: only needed for advanced/manual control.
    // Clients and open iterators are automatically cleaned up when the script completes or is terminated.
    client.close();
}