Waddler

3 min read Original article ↗

Waddler is a database client wrapper that unifies database communication and enables all* supported database clients to use an SQL template tag with consistent syntax, value escaping, helping prevent SQL injection and supporting common query-building scenarios.


* supported clients by waddler

You don't need to learn each driver's API, hunt for the features you need to build queries, or constantly write your own small utilities for parameterization, escaping, and so on. All of that is handled by the sql`` template tag from Waddler

SQL template

sql.identifier

sql.values

sql.raw

Types

Stream

Chunked

// Import from any driver subpackage to wrap it with waddler
import { waddler } from 'waddler/...';

const sql = waddler({ dbUrl: "" })

await sql`select * from "users" where "id" = ${10}`;
// Example wrapping "duckdb-neo" driver with waddler
import { waddler } from 'waddler/duckdb-neo';

const sql = waddler({ dbUrl: ":memory:" })

await sql`select * from "users" where "id" = ${10}`;
select * from "users" where "id" = $1;
-- 10 will be passed as a param [10]
await sql`select * from ${sql.identifier('users')}`;
await sql`select ${sql.identifier('id')} from ${sql.identifier('users')}`;
await sql`select ${sql.identifier(['id', 'name', 'email'])} from ${sql.identifier('users')}`;
select * from "users";
select "id" from "users";
select "id", "name", "email" from "users";
// Just add an array of arrays for insert values
await sql`insert into "users" ("name") values ${sql.values([["Dan"]])}`;

const values = sql.values([["Dan", "[email protected]", 25]]);
await sql`insert into "users" ("name", "email", "age") values ${values}`;
insert into "users" ("name") values ('Dan');
insert into "users" ("name", "email", "age") values ('Dan', '[email protected]', 25);
const listUsers = async (filter: string | undefined) => {
  const whereClause = filter ? sql.raw(` where ${filter}`) : sql.raw("");
  return sql`select * from "users"${whereClause}`;
}

await listUsers(`"id" = 10`);
await listUsers(`"name" = 'Dan'`);
await listUsers();
select * from "users" where "id" = 10;
select * from "users" where "name" = 'Dan';
select * from "users";
const result = await sql<{ id: number, name: string }>`select * from "users"`;

// or
type User = { id: number, name: string };
const result: User[] = await sql<User>`select * from "users"`;

result[0].id; // ✓ works
result[0].name; // ✓ works

result[0].unknown;
// ^ TS error
const result = sql`select * from users`.stream();

for await (const row of result) {
  console.log(row);
}
{
  id: 1,
	name: "Alex",
}
{
  id: 2,
	name: "Oleksii",
}
const result = sql`select * from users`.chunked(2);

for await (const chunk of result) {
  console.log(chunk);
}
[
	{
  	id: 1,
		name: "Alex",
	},
	{
	  id: 2,
		name: "Oleksii",
	}
]