Skip to content

Commit 57c3b82

Browse files
committed
better error handling
1 parent 00b16f6 commit 57c3b82

5 files changed

Lines changed: 196 additions & 129 deletions

File tree

example/src/sqlc.ts

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,59 +20,50 @@ type QueryClient = {
2020
type Apply<T, K extends keyof T, TOverride> = K extends keyof TOverride ? TOverride[K] : T[K];
2121

2222
type Queries = typeof queries;
23-
type NestedQueries = typeof nested_queries;
2423

2524
const queries = {
2625
["\n SELECT\n customer_id,\n store_id\n FROM customer\n "]: {
2726
exec: async<TOverride extends Partial<{ "customer_id": unknown; "store_id": unknown }> = {}>(client: QueryClient) => {
2827
type Row = { "customer_id": UUID; "store_id": number };
29-
const { rows } = await client.query("\n SELECT\n customer_id,\n store_id\n FROM customer");
28+
const { rows } = await client.query("SELECT\n customer_id,\n store_id\nFROM customer");
3029
return rows as unknown as Array<{ "customer_id": Apply<Row, 'customer_id', TOverride>; "store_id": Apply<Row, 'store_id', TOverride> }>;
31-
}
32-
},
33-
["\n WITH customer_spending AS (\n SELECT \n c.customer_id,\n c.first_name,\n c.last_name,\n COUNT(r.rental_id) as total_rentals,\n SUM(p.amount) as total_spent,\n AVG(p.amount) as avg_payment\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN payment p ON r.rental_id = p.rental_id\n GROUP BY c.customer_id, c.first_name, c.last_name\n ),\n customer_categories AS (\n SELECT DISTINCT\n c.customer_id,\n STRING_AGG(cat.name, ', ') OVER (PARTITION BY c.customer_id) as favorite_categories\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN inventory i ON r.inventory_id = i.inventory_id\n JOIN film_category fc ON i.film_id = fc.film_id\n JOIN category cat ON fc.category_id = cat.category_id\n )\n SELECT \n cs.*,\n cc.favorite_categories,\n RANK() OVER (ORDER BY cs.total_spent DESC) as spending_rank,\n NTILE(4) OVER (ORDER BY cs.total_rentals) as rental_quartile,\n ROUND(cs.total_spent / SUM(cs.total_spent) OVER () * 100, 2) as percentage_of_total_revenue\n FROM customer_spending cs\n JOIN customer_categories cc ON cs.customer_id = cc.customer_id\n WHERE cs.total_rentals > 5\n ORDER BY spending_rank\n "]: {
34-
exec: async<TOverride extends Partial<{ "customer_id": unknown; "first_name": unknown; "last_name": unknown; "total_rentals": unknown; "total_spent": unknown; "avg_payment": unknown; "favorite_categories": unknown; "spending_rank": unknown; "rental_quartile": unknown; "percentage_of_total_revenue": unknown }> = {}>(client: QueryClient) => {
35-
type Row = { "customer_id": number; "first_name": string; "last_name": string; "total_rentals": number; "total_spent": number; "avg_payment": unknown; "favorite_categories": Buffer; "spending_rank": number; "rental_quartile": number; "percentage_of_total_revenue": number };
36-
const { rows } = await client.query("\n WITH customer_spending AS (\n SELECT \n c.customer_id,\n c.first_name,\n c.last_name,\n COUNT(r.rental_id) as total_rentals,\n SUM(p.amount) as total_spent,\n AVG(p.amount) as avg_payment\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN payment p ON r.rental_id = p.rental_id\n GROUP BY c.customer_id, c.first_name, c.last_name\n ),\n customer_categories AS (\n SELECT DISTINCT\n c.customer_id,\n STRING_AGG(cat.name, ', ') OVER (PARTITION BY c.customer_id) as favorite_categories\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN inventory i ON r.inventory_id = i.inventory_id\n JOIN film_category fc ON i.film_id = fc.film_id\n JOIN category cat ON fc.category_id = cat.category_id\n )\n SELECT \n cs.customer_id, cs.first_name, cs.last_name, cs.total_rentals, cs.total_spent, cs.avg_payment,\n cc.favorite_categories,\n RANK() OVER (ORDER BY cs.total_spent DESC) as spending_rank,\n NTILE(4) OVER (ORDER BY cs.total_rentals) as rental_quartile,\n ROUND(cs.total_spent / SUM(cs.total_spent) OVER () * 100, 2) as percentage_of_total_revenue\n FROM customer_spending cs\n JOIN customer_categories cc ON cs.customer_id = cc.customer_id\n WHERE cs.total_rentals > 5\n ORDER BY spending_rank");
37-
return rows as unknown as Array<{ "customer_id": Apply<Row, 'customer_id', TOverride>; "first_name": Apply<Row, 'first_name', TOverride>; "last_name": Apply<Row, 'last_name', TOverride>; "total_rentals": Apply<Row, 'total_rentals', TOverride>; "total_spent": Apply<Row, 'total_spent', TOverride>; "avg_payment": Apply<Row, 'avg_payment', TOverride>; "favorite_categories": Apply<Row, 'favorite_categories', TOverride>; "spending_rank": Apply<Row, 'spending_rank', TOverride>; "rental_quartile": Apply<Row, 'rental_quartile', TOverride>; "percentage_of_total_revenue": Apply<Row, 'percentage_of_total_revenue', TOverride> }>;
38-
}
30+
},
31+
type: 'flat',
3932
},
40-
};
41-
42-
const nested_queries = {
4333
["\n SELECT\n c.customer_id AS id,\n c.first_name,\n c.last_name,\n s.manager_staff_id AS \"store.manager_staff_id\",\n a.address_id AS \"store.address.id\",\n a.address AS \"store.address.address\",\n a.address2 AS \"store.address.address2\"\n FROM customer AS c\n JOIN store AS s ON c.store_id = s.store_id\n JOIN address AS a ON c.address_id = a.address_id\n WHERE customer_id = @customer_id\n "]: {
4434
exec: async<TOverride extends Partial<{ "id": unknown; "first_name": unknown; "last_name": unknown; "store.manager_staff_id": unknown; "store.address.id": unknown; "store.address.address": unknown; "store.address.address2": unknown }> = {}>(client: QueryClient, params: { "customer_id": UUID }) => {
4535
type Row = { "id": UUID; "first_name": string; "last_name": string; "store.manager_staff_id": number; "store.address.id": number; "store.address.address": string; "store.address.address2": string | null };
46-
const { rows } = await client.query("\n SELECT\n c.customer_id AS id,\n c.first_name,\n c.last_name,\n s.manager_staff_id AS \"store.manager_staff_id\",\n a.address_id AS \"store.address.id\",\n a.address AS \"store.address.address\",\n a.address2 AS \"store.address.address2\"\n FROM customer AS c\n JOIN store AS s ON c.store_id = s.store_id\n JOIN address AS a ON c.address_id = a.address_id\n WHERE customer_id = $1", (["customer_id"] as const).map((param) => params[param]));
36+
const { rows } = await client.query("SELECT\n c.customer_id AS id,\n c.first_name,\n c.last_name,\n s.manager_staff_id AS \"store.manager_staff_id\",\n a.address_id AS \"store.address.id\",\n a.address AS \"store.address.address\",\n a.address2 AS \"store.address.address2\"\nFROM customer AS c\nJOIN store AS s ON c.store_id = s.store_id\nJOIN address AS a ON c.address_id = a.address_id\nWHERE customer_id = $1", (["customer_id"] as const).map((param) => params[param]));
4737
return unflatten_sql_results(rows as unknown as SqlRow[], {"id":{"type":"value","original_name":"id"},"first_name":{"type":"value","original_name":"first_name"},"last_name":{"type":"value","original_name":"last_name"},"store":{"type":"object","properties":{"manager_staff_id":{"type":"value","original_name":"store.manager_staff_id"},"address":{"type":"object","properties":{"id":{"type":"value","original_name":"store.address.id"},"address":{"type":"value","original_name":"store.address.address"},"address2":{"type":"value","original_name":"store.address.address2"}},"original_name":"store.address.id"}},"original_name":"store.manager_staff_id"}}) as unknown as Array<{ id: Apply<Row, 'id', TOverride>;first_name: Apply<Row, 'first_name', TOverride>;last_name: Apply<Row, 'last_name', TOverride>;store: { manager_staff_id: Apply<Row, 'store.manager_staff_id', TOverride>;address: { id: Apply<Row, 'store.address.id', TOverride>;address: Apply<Row, 'store.address.address', TOverride>;address2: Apply<Row, 'store.address.address2', TOverride> } } }>;
48-
}
38+
},
39+
type: 'nested',
40+
},
41+
["\n WITH customer_spending AS (\n SELECT \n c.customer_id,\n c.first_name,\n c.last_name,\n COUNT(r.rental_id) as total_rentals,\n SUM(p.amount) as total_spent,\n AVG(p.amount) as avg_payment\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN payment p ON r.rental_id = p.rental_id\n GROUP BY c.customer_id, c.first_name, c.last_name\n ),\n customer_categories AS (\n SELECT DISTINCT\n c.customer_id,\n STRING_AGG(cat.name, ', ') OVER (PARTITION BY c.customer_id) as favorite_categories\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN inventory i ON r.inventory_id = i.inventory_id\n JOIN film_category fc ON i.film_id = fc.film_id\n JOIN category cat ON fc.category_id = cat.category_id\n )\n SELECT \n cs.*,\n cc.favorite_categories,\n RANK() OVER (ORDER BY cs.total_spent DESC) as spending_rank,\n NTILE(4) OVER (ORDER BY cs.total_rentals) as rental_quartile,\n ROUND(cs.total_spent / SUM(cs.total_spent) OVER () * 100, 2) as percentage_of_total_revenue\n FROM customer_spending cs\n JOIN customer_categories cc ON cs.customer_id = cc.customer_id\n WHERE cs.total_rentals > 5\n ORDER BY spending_rank\n "]: {
42+
exec: async<TOverride extends Partial<{ "customer_id": unknown; "first_name": unknown; "last_name": unknown; "total_rentals": unknown; "total_spent": unknown; "avg_payment": unknown; "favorite_categories": unknown; "spending_rank": unknown; "rental_quartile": unknown; "percentage_of_total_revenue": unknown }> = {}>(client: QueryClient) => {
43+
type Row = { "customer_id": number; "first_name": string; "last_name": string; "total_rentals": number; "total_spent": number; "avg_payment": unknown; "favorite_categories": Buffer; "spending_rank": number; "rental_quartile": number; "percentage_of_total_revenue": number };
44+
const { rows } = await client.query("WITH customer_spending AS (\n SELECT \n c.customer_id,\n c.first_name,\n c.last_name,\n COUNT(r.rental_id) as total_rentals,\n SUM(p.amount) as total_spent,\n AVG(p.amount) as avg_payment\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN payment p ON r.rental_id = p.rental_id\n GROUP BY c.customer_id, c.first_name, c.last_name\n),\ncustomer_categories AS (\n SELECT DISTINCT\n c.customer_id,\n STRING_AGG(cat.name, ', ') OVER (PARTITION BY c.customer_id) as favorite_categories\n FROM customer c\n JOIN rental r ON c.customer_id = r.customer_id\n JOIN inventory i ON r.inventory_id = i.inventory_id\n JOIN film_category fc ON i.film_id = fc.film_id\n JOIN category cat ON fc.category_id = cat.category_id\n)\nSELECT \n cs.customer_id, cs.first_name, cs.last_name, cs.total_rentals, cs.total_spent, cs.avg_payment,\n cc.favorite_categories,\n RANK() OVER (ORDER BY cs.total_spent DESC) as spending_rank,\n NTILE(4) OVER (ORDER BY cs.total_rentals) as rental_quartile,\n ROUND(cs.total_spent / SUM(cs.total_spent) OVER () * 100, 2) as percentage_of_total_revenue\nFROM customer_spending cs\nJOIN customer_categories cc ON cs.customer_id = cc.customer_id\nWHERE cs.total_rentals > 5\nORDER BY spending_rank");
45+
return rows as unknown as Array<{ "customer_id": Apply<Row, 'customer_id', TOverride>; "first_name": Apply<Row, 'first_name', TOverride>; "last_name": Apply<Row, 'last_name', TOverride>; "total_rentals": Apply<Row, 'total_rentals', TOverride>; "total_spent": Apply<Row, 'total_spent', TOverride>; "avg_payment": Apply<Row, 'avg_payment', TOverride>; "favorite_categories": Apply<Row, 'favorite_categories', TOverride>; "spending_rank": Apply<Row, 'spending_rank', TOverride>; "rental_quartile": Apply<Row, 'rental_quartile', TOverride>; "percentage_of_total_revenue": Apply<Row, 'percentage_of_total_revenue', TOverride> }>;
46+
},
47+
type: 'flat',
4948
},
5049
};
5150

5251
export type mpaa_rating = 'G' | 'PG' | 'PG-13' | 'R' | 'NC-17';
5352

5453

55-
type SchemaType = 'value' | 'object' | 'array';
56-
57-
interface SchemaNode {
58-
type: SchemaType;
59-
properties?: SchemaProperties;
54+
type SchemaNode = {
55+
type: 'value' | 'object' | 'array';
56+
properties?: Record<string, SchemaNode>;
6057
original_name?: string;
61-
}
62-
63-
interface SchemaProperties {
64-
[key: string]: SchemaNode;
65-
}
66-
67-
export interface NestedSchema {
68-
[key: string]: SchemaNode;
69-
}
58+
};
7059

7160
type SqlRow = {
7261
[key: string]: unknown;
7362
'[]': number;
7463
};
7564

65+
type NestedSchema = Record<string, SchemaNode>;
66+
7667
const unflatten_row = (row: SqlRow, schema: NestedSchema): Record<string, unknown> => {
7768
// Recursive helper function to build nested objects
7869
const build_object = (schema: NestedSchema, prefix = ''): Record<string, unknown> => {
@@ -185,4 +176,4 @@ const unflatten_sql_results = (rows: SqlRow[], schema: NestedSchema): Identifiab
185176
};
186177

187178
export const sqlc = <T extends keyof Queries>(query: T) => queries[query];
188-
export const sqln = <T extends keyof NestedQueries>(query: T) => nested_queries[query];
179+
export const sqln = <T extends keyof { [K in keyof Queries]: Queries[K]['type'] extends 'nested' ? K : never; }>(query: T) => queries[query];

src/cli.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ program
4646
const spinner = ora(watching_text).start();
4747

4848
const debounced_generate = debounce(async () => {
49+
process.stdout.write('\x1Bc');
4950
spinner.start('Generating types...');
5051

5152
try {

0 commit comments

Comments
 (0)