Skip to content

Implement CTEInjector with fixture support for SQL testing #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ A suite of utilities for transforming and analyzing SQL ASTs.
Collects all CTEs from WITH clauses, subqueries, and UNION queries.
- **UpstreamSelectQueryFinder**
Finds upstream SELECT queries that provide specific columns by traversing CTEs, subqueries, and UNION branches.
- **CTEInjector**
Inserts Common Table Expressions into queries.
- `inject(query, commonTables)`: Injects CTEs into AST query objects.
- `withFixtures(sql, deps, fixtures, options)`: Injects test fixtures as CTEs with explicit VALUES rows.
- `withNullScaffolding(sql, deps, options)`: Injects NULL-based scaffolding CTEs.
This is useful for testing a query's calculation logic without relying on a live database.

- **CTENormalizer**
Consolidates all CTEs into a single root-level WITH clause. Throws an error if duplicate CTE names with different definitions are found.
- **QueryNormalizer**
Expand Down Expand Up @@ -567,6 +574,67 @@ console.log(formattedSql);

---

## Testing SQL with CTEInjector and Fixtures

The `CTEInjector` class can be used to inject test data into a SQL query for testing purposes. This allows you to validate your SQL query's logic without needing a live database.

```typescript
import { SelectQueryParser } from 'rawsql-ts';
import { SchemaCollector } from 'rawsql-ts';
import { CTEInjector, Fixtures } from 'rawsql-ts';

// SQL query under test
const sql = `
SELECT u.name, SUM(o.total) AS sum_total
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.name
`;

// Parse the query and collect schema dependencies
const query = SelectQueryParser.parse(sql);
const schemaCollector = new SchemaCollector();
const deps = schemaCollector.collect(query);

// Provide test fixtures
const fixtures: Fixtures = {
users: [
{ id: 1, name: 'mike' },
{ id: 2, name: 'ken' },
],
orders: [
{ user_id: 1, total: 100 },
{ user_id: 1, total: 500 },
{ user_id: 2, total: 300 },
],
};

// Create the test SQL with injected fixtures
const injector = new CTEInjector();
const testSQL = injector.withFixtures(sql, deps, fixtures);

console.log(testSQL);
// Output:
// WITH
// users(id, name) AS (
// VALUES
// (1, 'mike'),
// (2, 'ken')
// ),
// orders(total, user_id) AS (
// VALUES
// (100, 1),
// (500, 1),
// (300, 2)
// )
// SELECT u.name, SUM(o.total) AS sum_total
// FROM users u
// JOIN orders o ON o.user_id = u.id
// GROUP BY u.name
```

You can then run this SQL against any database engine (SQLite, DuckDB, PostgreSQL, etc.) for deterministic unit tests.

## Benchmarks

This project includes a comprehensive benchmark suite to evaluate the performance of `rawsql-ts` in comparison with other popular libraries such as `node-sql-parser` and `sql-formatter`.
Expand Down
Loading