@jakub.knejzlik/ts-query
Version:
TypeScript implementation of SQL builder
112 lines (80 loc) • 3.12 kB
text/mdx
import { Meta } from "@storybook/addon-docs";
import { CodePreview } from "./CodePreview";
<Meta title="6. Transformations" />
Transformations let you intercept and modify query structures at SQL generation time. This is useful for enforcing ACL rules, dynamic table routing, default filters, or modifying mutations without altering each query manually.
When calling `toSQL`, provide transformation functions:
- `transformTable`: Alters table references.
- `transformSelectQuery`: Modifies `SELECT` queries.
- `transformInsertMutation`: Adjusts `INSERT` statements.
- `transformUpdateMutation`: Modifies `UPDATE` operations.
- `transformDeleteMutation`: Restricts `DELETE` queries.
This example replaces a table reference with a subquery:
<CodePreview
code={`const baseQuery = Q.select().from("foo", "f1");
const joinQuery = baseQuery.leftJoin(Q.table("foo2", "f2"), Cond.columnEqual("f1.id", "f2.id"));
return joinQuery.toSQL(Q.flavors.mysql, {
transformTable: (table) => {
if (table === "foo") {
return Q.select()
.from(table, "f")
.join(Q.table("bar", "b"), Cond.columnEqual("f.id", "b.id"));
}
return table;
},
});
`}/>
You can modify fields in `SELECT` queries dynamically:
<CodePreview
code={`const baseQuery = Q.select().from("foo");
const unionQuery = baseQuery.union(Q.select().from("blah"));
return unionQuery.toSQL(Q.flavors.mysql, {
transformSelectQuery: (select) => {
return select.addField("f1.name", "f1name");
},
});
`}/>
Automatically add fields like `createdAt`:
<CodePreview
code={`const insertQuery = Q.insert("foo").values([{ id: 1, name: "foo" }]);
return insertQuery.toSQL(Q.flavors.mysql, {
transformInsertMutation: (q) => {
const values = q.allValues().map((v) => ({ ...v, createdAt: "YYYY-MM-DD" }));
return q.removeAllValues().values(values);
},
});
`}/>
Ensure updates meet specific conditions:
<CodePreview
code={`const updateQuery = Q.update("foo").set({ firstName: "john" });
return updateQuery.toSQL(Q.flavors.mysql, {
transformUpdateMutation: (q) => {
return q.set({ firstName: "jane" }).where(Cond.equal("lastName", "doe"));
},
});
`}/>
Add automatic conditions to `DELETE` queries:
<CodePreview
code={`const deleteQuery = Q.delete("foo");
return deleteQuery.toSQL(Q.flavors.mysql, {
transformDeleteMutation: (q) => {
return q.where(Cond.equal("owner", "12345"));
},
});
`}/>
1. **ACL Enforcement**
Automatically append conditions for access control.
2. **Sharding**
Dynamically redirect queries to the appropriate database partition.
3. **Data Auditing**
Add fields like `createdAt` to `INSERT` statements automatically.
4. **Soft Deletes**
Transform `DELETE` into an `UPDATE` setting a `deletedAt` timestamp.
By applying these transformations, query logic remains centralized and adaptable without needing individual query modifications.