squealy-ts
v0.0.10
Published
## Usage
Downloads
12
Readme
Squealy TS
Usage
import {
createSchema,
setup,
query,
select,
join,
where,
all,
} from "squealy-ts";
import { create } from "squealy-ts-adapter-bun-sqlite";
import { Database } from "bun:sqlite";
const schema = createSchema(
// define your data
{
users: {
id: ["text", "PRIMARY KEY"], // string
name: ["text", "NOT NULL"], // string
age: "integer", // number | null
},
account: {
id: ["text", "PRIMARY KEY"],
},
transaction: {
id: ["text", "PRIMARY KEY"],
amount: ["real", "NOT NULL"],
},
},
// define the relations
{
users: {
account: ["maybe one", "account", "id"], // type safe strings
},
account: {
transactions: ["many", "transaction", "id"],
},
transaction: {
source: ["one", "account", "id"],
target: ["one", "account", "id"],
},
},
);
const adapter = create(new Database());
await pipe(adapter, setup(schema)); // create tables
const getTransactions = (sourceAccount: string) =>
pipe(
query(schema),
select("transaction"), // again, a typesafe string
join({
source: true,
target: true,
}),
where((row) => `${row.source.id} = "${sourceAccount}"`), // typesafe column access based on current context
all,
);
const transactions = await pipe(adapter, getTransactions("foo")); // Array<{id: string, amount: number, source: {id: string}, target: {id: string}}>
Keep it simple, keep it functional
As you can see from the snippet above squealy-ts
almost reads like regular SQL
while avoiding the pitfalls of a fluent API. It also integrates nicely with
other concepts such as reader monads and partial application, enabling you to
simply define your operations as a series of smaller steps. I'd recommend using
fp-ts
for that, but of course you can use any functionally oriented library as
well, such as lodash-fp
or ramda
.
A Typescript "ORM" that won't block you.
squealy-ts
is built around a few core tenets that are supposed to provide a
balance between seamless SQL integration and sensible use cases.
no ORM can abstract all of SQL without becoming a worse version of SQL itself
In the end SQL has been designed to arbitrarily query your data in an efficient manner. ORMs on the other hand have been designed for some common programmatic use cases. Trying to abstract everything SQL has to offer would just result in another version of SQL that is most likely worse. That means: if you need advanced stuff like window functions, recursive SQL, and even CTEs you should write those in SQL. After all there's not much gained if you have to spend the same effort googling "how to do CTEs in ORM X" compared to just "how to do CTEs in SQL".
easy, code-first schema definition
Schemas should be flexible without breaking your brain. Just say what your Data
looks like and how it's connected and squealy-ts
will take care of setting up
the database.
precise typings that are still fast enough to use
"Typesafety" has many levels - from simply being explicit about nullability to inferring structure from a string. Many other ORMs seem to think modelling "entities" as classes is already enough while completely forgetting about things like object-relational impedance mismatch while others try to fully type any SQL query which makes things like autocomplete reeeeally slow.
easy integration with raw SQL
squealy-ts
isn't even an "ORM" in the classical sense - it's more of a SQL
wrapper geared towards common programmatic interactions.
"don't migrate, rebuild instead"
Anybody who tells you SQL migrations can be automated or supported so that they
become painless is either lying or hasn't had to deal with larger migrations.
IMHO migrating databases is always problematic - luckily employing architectures
like event sourcing nicely circumvent these problems. So squealy-ts
doesn't
even try to solve a problem that can more completely and easily be solved
outside of SQL.
A note on autoincrementing keys and such
While fine in theory you often want to control your ids from a programmatic perspective anyway. If you want to sort your primary keys in chronological order you should probably look at ULIDs or UUID-v7.
Comparison with other ORMs
Drizzle
Drizzle has been a great inspiration but its typings are too slow and some aspects break the "SQL abstraction" tenet.
Prisma
Why learn a new schema language when you already have typescript?
Sequelize
No typesafety in current version, classes in the next... to quote from object-relational impedance mismatch: Object orientation is a poor basis for schemas.
TypeORM
Class based and even flaunts that it goes nicely with the Active Record Pattern... as referenced above: object-relational impedance mismatch!