CKN/Technology/CKN Data
CKN Data

One data layer for every database and file

CKN Data is the framework's data-access layer: six database types, Excel, Word, CSV files and data pipelines behind one consistent API. Your team learns it once, moves between systems easily, and avoids a pile of third-party libraries to keep patched.

6database types behind one API surface
404unit tests passing in the latest recorded run, zero failures
159checks against real servers (PostgreSQL, MySQL, MongoDB, Oracle, SQL Server, Firestore emulator) all passing
1third-party runtime library (jszip) beyond CKN Core
Capabilities

What CKN Data does

01

Every database, one way of working

MySQL, PostgreSQL, Oracle, SQL Server, MongoDB and Firestore share the same commands. Switching databases means minimal code change, and drivers load only when a connection is actually opened.

  • query, insert, update, delete, count, upsert
  • Check each database's abilities with capabilities
  • Configurable connection pool on every pooled adapter
  • Parameterized queries guard against SQL injection
02

Transactions that are safe by default

Any call made inside a transaction block automatically joins it, even through other functions. If anything fails, everything rolls back.

  • Nested transactions through savepoints
  • Independent transactions, e.g. to log why a request was refused
  • Row locks with SELECT ... FOR UPDATE to prevent write races
  • MongoDB retries transient write conflicts automatically
03

Big data volumes without memory spikes

Read hundreds of thousands of rows as a stream, one batch at a time, and write in bulk with batch sizes tuned for each database.

  • stream() on every adapter except Firestore
  • queryColumnFrame() for aggregating large results
  • Multi-row upsert and bulkUpdate in one statement
  • Per-statement timeouts
04

Excel, Word, PowerPoint, CSV and ZIP

Create, read and edit office documents straight from code: reports, quotations, and imports from files your customers send.

  • ExcelFile, WordFile, PowerPointFile and Excel Online
  • Extract document text for an AI model to read
  • Atomic writes and folder confinement for files
  • Metered ZIP opening to guard against hostile archives
05

Pipelines and connectors to other systems

Build ETL/ELT jobs that move data between databases, files and message brokers, with checkpoints to resume a run that failed midway.

  • HTTP, S3, SFTP, Kafka, Redis Streams, CDC, DuckDB, SOAP
  • Checkpoints and dead-letter storage for records that fail
  • Late records are counted and set aside, never dropped silently
  • Declarative pipeline specs
06

The data housekeeping real systems need

Includes the modules business systems depend on, from guaranteed event delivery to schema upgrades and Thai-aware text search.

  • Outbox: safe retries without duplicates, via idempotency keys
  • Schema migration planning with column-type checks before running
  • Validation, import/export and data sync
  • RAG storage on PostgreSQL with Thai-aware full-text search
Performance

Measured, not promised

Figures come from our own benchmark harness, run on an Apple M1 Pro with Docker (database containers capped at 2 CPUs and 2 GB, 100,000 seeded rows). Absolute values on a laptop differ from production servers; the ratios against the raw driver and before/after comparisons are the useful part.

Point read (PostgreSQL, 32 concurrent workers)
15,366 ops/s
Within 7% of the raw database driver at every concurrency level measured, on all four SQL databases
Bulk insert (PostgreSQL, 100,000 rows x 10 columns)
94,252 rows/s
MySQL reached 102,372 and Oracle 199,929 rows/s in the same run
Upsert of 1,000 rows (PostgreSQL), after moving to multi-row statements
17,612 rows/s
11x faster than the 1,600 rows/s measured before the change (MySQL improved 33x)
bulkUpdate (PostgreSQL, 10,000 rows, 3 columns)
53,117 rows/s
Compared with 2,538 rows/s before batch-size tuning
Reading 100,000 x 1 KB rows: stream() vs a normal query() (PostgreSQL)
+0.7 MB vs +56 MB
Process memory growth. stream() took 698 ms against 558 ms. Other databases saw a 5x to 25x reduction in memory growth
Pipeline with 3 map steps (200,000 rows, source to sink)
1,049,548 rows/s
Excludes database and network time; real runs depend on the source and destination connectors

Figures come from CKN's own test suites and benchmarks. Real results depend on each system's hardware and data volume.

Business value

What your business gets

Lower build and maintenance cost

Your team uses one API for databases, files and pipelines, so new developers get productive faster and code written once is reused across systems. Jobs that normally need extra libraries, such as producing Excel or Word files, are covered in the same package.

Less risk where money and stock are involved

Full rollback, row locking and an Outbox that retries without duplicating events help prevent problems like negative stock or double orders. The test suite also runs against real servers for all six databases, not just mocks.

You own the stack, with no single-vendor lock-in

Word writing, CSV and XML handling are our own code, which cuts exposure to third-party libraries you would have to keep patching. You install only the drivers for the databases you use, and you can move to another database without rewriting the whole data layer.

For developers

Example: load prices, then deduct stock without a race

In use across the CKN stack

  • All 14 CKN business services use it as their main database layer (PostgreSQL)
  • Platform services such as identity, integration, portal, intelligent and engine
  • The CKN Works internal app (projects, tickets, costing, documents, expenses)
  • The ckn command-line tool generates database-layer code for new apps
import { PostgreSQL } from "@ckn-technology/data/database";

const db = new PostgreSQL({
    host: process.env.MAIN_DB_HOST ?? "", port: 5432, user: process.env.MAIN_DB_USER ?? "",
    password: process.env.MAIN_DB_PASSWORD ?? "", database: "app", schema: "sales", enableLog: false,
});

await db.upsert("price", [{ sku: "A-100", company_code: "TH01", price: 890, currency: "THB" }], ["sku", "company_code"]);

await db.transaction(async (tx) => {
    const [s] = (await tx.query("SELECT qty FROM stock WHERE sku = $1 FOR UPDATE", ["A-100"])).rows;
    if (!s || s.qty < 5) throw new Error("not enough A-100");   // rolls everything back
    await tx.update("stock", { qty: s.qty - 5 }, "sku = $1", ["A-100"]);
});
await db.close();
CKN Technology

Explore the other packages

See CKN Data working on your systems

Contact us →