npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@saptools/cf-hana

v0.1.1

Published

Run SQL against SAP HANA Cloud databases bound to a Cloud Foundry app by region/org/space/app selector

Readme

@saptools/cf-hana

Run SQL directly against SAP HANA Cloud databases bound to a Cloud Foundry app — addressed by a region/org/space/app selector.

@saptools/cf-hana closes the last gap in the saptools chain: @saptools/cf-sync already discovers Cloud Foundry topology and HANA service bindings, but nothing actually executes SQL. This package does. Pass a selector, get a connected, pooled client, and run SELECT / INSERT / UPDATE / DELETE / DDL.

It is fast because credentials come from cf-sync's on-disk cache (no 5–15s CF login on the hot path) and connections are pooled and reused within a process.

Features

  • Selector-based connectregion/org/space/app or a bare app name.
  • Credentials, handled for you — cache-first via @saptools/cf-sync, with an on-demand live Cloud Foundry fetch as a fallback.
  • Parameterized queries — values always travel as bound ? parameters, never string-concatenated.
  • Connection pooling — pooled, reused connections; opt out with pool: false.
  • Transactionstransaction(work) commits on success, rolls back on throw.
  • Query-builder shorthandsselectFrom, count, insertInto, update, deleteFrom — query a table by name without writing SQL.
  • Schema introspection — list schemas, tables, and columns.
  • Safety guard — opt-in read-only mode and a destructive-statement guard (blocks DROP/TRUNCATE/ALTER and unscoped UPDATE/DELETE).
  • Typed resultsquery<TRow>() returns typed rows.
  • CLI + API — a cf-hana CLI and an ergonomic TypeScript API.

Installation

npm install @saptools/cf-hana
# or, for the CLI
npm install -g @saptools/cf-hana

Requires Node.js >= 20. The pure-JavaScript hdb driver is bundled as a dependency — there is no native build step.

Quick start

import { connect, query } from "@saptools/cf-hana";

// Open a reusable, pooled client for one CF app's HANA database.
const db = await connect("eu10/acme/dev/orders-srv");

const open = await db.query("SELECT ID, STATUS FROM ORDERS WHERE STATUS = ?", ["OPEN"]);
console.log(open.rows);

const total = await db.count({ schema: "ORDERS_APP", table: "ORDERS", where: { STATUS: "OPEN" } });

await db.transaction(async (tx) => {
  await tx.execute("UPDATE ORDERS SET STATUS = ? WHERE ID = ?", ["SHIPPED", 42]);
});

await db.close();

// One-shot: connect, run one query, close.
const rows = await query("orders-srv", "SELECT COUNT(*) AS N FROM ORDERS");

The selector

Every entry point takes a selector as its first argument:

  • Explicitregion/org/space/app (e.g. eu10/acme/dev/orders-srv). Works without any cached topology.
  • Bare app nameorders-srv. Resolved against the topology cached by cf-sync sync; throws if the name is ambiguous across spaces.

CLI

cf-hana query   <selector> <sql>            Run a single SQL statement
cf-hana tables  <selector> [schema]         List tables in a schema
cf-hana columns <selector> <schema.table>   List the columns of a table
cf-hana count   <selector> <schema.table>   Count rows in a table
cf-hana ping    <selector>                  Connect and measure round-trip latency
cf-hana info    <selector>                  Print the resolved connection metadata

Common options: --format <table|json|csv>, --refresh, --role <runtime|hdi>, --binding <name> / --binding-index <n>, --timeout <ms>, --read-only, --allow-destructive, --limit <n>, --no-auto-limit. The query command also accepts --param <value> (repeatable) to bind ? placeholders.

cf-hana query eu10/acme/dev/orders-srv "SELECT ID, STATUS FROM ORDERS WHERE STATUS = ?" \
  --param OPEN --format json
cf-hana tables orders-srv
cf-hana columns orders-srv ORDERS_APP.ORDERS
cf-hana ping eu10/acme/dev/orders-srv

Programmatic API

| Export | Purpose | | --- | --- | | connect(selector, options?) | Open a reusable, pooled HanaClient. | | query(selector, sql, params?, options?) | One-shot: connect, query, close. | | withConnection(selector, work, options?) | Run work with a client that auto-closes. | | HanaClient | query, execute, selectFrom, count, insertInto, update, deleteFrom, transaction, listSchemas, listTables, listColumns, explain, close. | | createDriver, formatResult, build* | Lower-level building blocks. |

ConnectOptions highlights: role (runtime | hdi), bindingName / bindingIndex, readOnly, allowDestructive, autoLimit, queryTimeoutMs, connectTimeoutMs, refresh, pool.

Credentials

Credentials are resolved cache-first:

  1. Read what cf-sync db-sync cached in ~/.saptools/cf-db-bindings.json.
  2. On a cache miss (or when refresh: true / --refresh is passed), fetch them live from Cloud Foundry. The live fetch needs SAP_EMAIL and SAP_PASSWORD (or the email / password options) and never persists anything to disk.

cf-hana itself writes nothing under ~/.saptools/ — it only reads what cf-sync cached. The connection pool is in-process and in-memory only, so it is safe to run many cf-hana processes in parallel and alongside any cf-sync command.

Safety

  • Read-only mode (readOnly / --read-only) rejects every DML and DDL statement.
  • Destructive guard blocks DROP / TRUNCATE / ALTER and UPDATE / DELETE without a WHERE clause unless allowDestructive / --allow-destructive is set.
  • Auto-limit appends a LIMIT to bare SELECT statements (default 1000); QueryResult.truncated reports when it clipped the result. Disable with autoLimit: false / --no-auto-limit.

The guard is a convenience, not a security control: always pass values as bound parameters.

Requirements

  • Node.js >= 20.
  • A HANA binding reachable from your network. Resolving a bare app name, or a live credential fetch, additionally needs the Cloud Foundry CLI and SAP_EMAIL / SAP_PASSWORD.

Development

pnpm --filter @saptools/cf-hana build
pnpm --filter @saptools/cf-hana lint
pnpm --filter @saptools/cf-hana typecheck
pnpm --filter @saptools/cf-hana test:unit
pnpm --filter @saptools/cf-hana test:e2e:fake

The live e2e suite (test:e2e:live) needs real SAP_EMAIL / SAP_PASSWORD and a CF_HANA_E2E_TARGET selector pointing at a HANA-bound app.

License

MIT