Skip to content

Commit a5f61a6

Browse files
committed
Extracted SQL builder from execution on collection to enable unit testing SQL generation in the future
1 parent 4b33197 commit a5f61a6

File tree

3 files changed

+116
-129
lines changed

3 files changed

+116
-129
lines changed
+2-111
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
1-
import pg from 'pg';
2-
import { v4 as uuid } from 'uuid';
3-
import {
4-
type DbClient,
5-
type PongoCollection,
6-
type PongoDeleteResult,
7-
type PongoFilter,
8-
type PongoInsertOneResult,
9-
type PongoUpdate,
10-
type PongoUpdateResult,
11-
} from '../main';
12-
import { executeSQL } from './execute';
13-
import { constructFilterQuery } from './filter';
1+
import { type DbClient } from '../main';
142
import { endPool, getPool } from './pool';
15-
import { sql } from './sql';
16-
import { buildUpdateQuery } from './update';
3+
import { postgresCollection } from './postgresCollection';
174

185
export const postgresClient = (
196
connectionString: string,
@@ -27,99 +14,3 @@ export const postgresClient = (
2714
collection: <T>(name: string) => postgresCollection<T>(name, pool),
2815
};
2916
};
30-
31-
export const postgresCollection = <T>(
32-
collectionName: string,
33-
pool: pg.Pool,
34-
): PongoCollection<T> => {
35-
const createCollection = executeSQL(
36-
pool,
37-
sql(
38-
'CREATE TABLE IF NOT EXISTS %I (_id UUID PRIMARY KEY, data JSONB)',
39-
collectionName,
40-
),
41-
);
42-
return {
43-
createCollection: async () => {
44-
await createCollection;
45-
},
46-
insertOne: async (document: T): Promise<PongoInsertOneResult> => {
47-
await createCollection;
48-
49-
const id = uuid();
50-
51-
const result = await executeSQL(
52-
pool,
53-
sql(
54-
'INSERT INTO %I (_id, data) VALUES (%L, %L)',
55-
collectionName,
56-
id,
57-
JSON.stringify({ ...document, _id: id }),
58-
),
59-
);
60-
61-
return result.rowCount
62-
? { insertedId: id, acknowledged: true }
63-
: { insertedId: null, acknowledged: false };
64-
},
65-
updateOne: async (
66-
filter: PongoFilter<T>,
67-
update: PongoUpdate<T>,
68-
): Promise<PongoUpdateResult> => {
69-
await createCollection;
70-
71-
const filterQuery = constructFilterQuery(filter);
72-
const updateQuery = buildUpdateQuery(update);
73-
74-
const result = await executeSQL(
75-
pool,
76-
sql(
77-
'UPDATE %I SET data = %s WHERE %s',
78-
collectionName,
79-
updateQuery,
80-
filterQuery,
81-
),
82-
);
83-
return result.rowCount
84-
? { acknowledged: true, modifiedCount: result.rowCount }
85-
: { acknowledged: false, modifiedCount: 0 };
86-
},
87-
deleteOne: async (filter: PongoFilter<T>): Promise<PongoDeleteResult> => {
88-
await createCollection;
89-
90-
const filterQuery = constructFilterQuery(filter);
91-
const result = await executeSQL(
92-
pool,
93-
sql('DELETE FROM %I WHERE %s', collectionName, filterQuery),
94-
);
95-
return result.rowCount
96-
? { acknowledged: true, deletedCount: result.rowCount }
97-
: { acknowledged: false, deletedCount: 0 };
98-
},
99-
findOne: async (filter: PongoFilter<T>): Promise<T | null> => {
100-
await createCollection;
101-
102-
const filterQuery = constructFilterQuery(filter);
103-
const result = await executeSQL(
104-
pool,
105-
sql(
106-
'SELECT data FROM %I WHERE %s LIMIT 1',
107-
collectionName,
108-
filterQuery,
109-
),
110-
);
111-
return (result.rows[0]?.data ?? null) as T | null;
112-
},
113-
find: async (filter: PongoFilter<T>): Promise<T[]> => {
114-
await createCollection;
115-
116-
const filterQuery = constructFilterQuery(filter);
117-
const result = await executeSQL(
118-
pool,
119-
sql('SELECT data FROM %I WHERE %s', collectionName, filterQuery),
120-
);
121-
122-
return result.rows.map((row) => row.data as T);
123-
},
124-
};
125-
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import pg from 'pg';
2+
import { v4 as uuid } from 'uuid';
3+
import {
4+
type PongoCollection,
5+
type PongoDeleteResult,
6+
type PongoFilter,
7+
type PongoInsertOneResult,
8+
type PongoUpdate,
9+
type PongoUpdateResult,
10+
} from '../main';
11+
import { executeSQL } from './execute';
12+
import { constructFilterQuery } from './filter';
13+
import { sql, type SQL } from './sql';
14+
import { buildUpdateQuery } from './update';
15+
16+
export const postgresCollection = <T>(
17+
collectionName: string,
18+
pool: pg.Pool,
19+
): PongoCollection<T> => {
20+
const execute = (sql: SQL) => executeSQL(pool, sql);
21+
const SqlFor = collectionSQLBuilder(collectionName);
22+
23+
const createCollection = execute(SqlFor.createCollection());
24+
25+
return {
26+
createCollection: async () => {
27+
await createCollection;
28+
},
29+
insertOne: async (document: T): Promise<PongoInsertOneResult> => {
30+
await createCollection;
31+
32+
const id = uuid();
33+
34+
const result = await execute(SqlFor.insertOne(id, document));
35+
36+
return result.rowCount
37+
? { insertedId: id, acknowledged: true }
38+
: { insertedId: null, acknowledged: false };
39+
},
40+
updateOne: async (
41+
filter: PongoFilter<T>,
42+
update: PongoUpdate<T>,
43+
): Promise<PongoUpdateResult> => {
44+
await createCollection;
45+
46+
const result = await execute(SqlFor.updateOne(filter, update));
47+
return result.rowCount
48+
? { acknowledged: true, modifiedCount: result.rowCount }
49+
: { acknowledged: false, modifiedCount: 0 };
50+
},
51+
deleteOne: async (filter: PongoFilter<T>): Promise<PongoDeleteResult> => {
52+
await createCollection;
53+
54+
const result = await execute(SqlFor.deleteOne(filter));
55+
return result.rowCount
56+
? { acknowledged: true, deletedCount: result.rowCount }
57+
: { acknowledged: false, deletedCount: 0 };
58+
},
59+
findOne: async (filter: PongoFilter<T>): Promise<T | null> => {
60+
await createCollection;
61+
62+
const result = await execute(SqlFor.findOne(filter));
63+
return (result.rows[0]?.data ?? null) as T | null;
64+
},
65+
find: async (filter: PongoFilter<T>): Promise<T[]> => {
66+
await createCollection;
67+
68+
const result = await execute(SqlFor.find(filter));
69+
return result.rows.map((row) => row.data as T);
70+
},
71+
};
72+
};
73+
74+
export const collectionSQLBuilder = (collectionName: string) => ({
75+
createCollection: (): SQL =>
76+
sql(
77+
'CREATE TABLE IF NOT EXISTS %I (_id UUID PRIMARY KEY, data JSONB)',
78+
collectionName,
79+
),
80+
insertOne: <T>(id: string, document: T): SQL =>
81+
sql(
82+
'INSERT INTO %I (_id, data) VALUES (%L, %L)',
83+
collectionName,
84+
id,
85+
JSON.stringify({ ...document, _id: id }),
86+
),
87+
updateOne: <T>(filter: PongoFilter<T>, update: PongoUpdate<T>): SQL => {
88+
const filterQuery = constructFilterQuery(filter);
89+
const updateQuery = buildUpdateQuery(update);
90+
91+
return sql(
92+
'UPDATE %I SET data = %s WHERE %s',
93+
collectionName,
94+
updateQuery,
95+
filterQuery,
96+
);
97+
},
98+
deleteOne: <T>(filter: PongoFilter<T>): SQL => {
99+
const filterQuery = constructFilterQuery(filter);
100+
return sql('DELETE FROM %I WHERE %s', collectionName, filterQuery);
101+
},
102+
findOne: <T>(filter: PongoFilter<T>): SQL => {
103+
const filterQuery = constructFilterQuery(filter);
104+
return sql(
105+
'SELECT data FROM %I WHERE %s LIMIT 1',
106+
collectionName,
107+
filterQuery,
108+
);
109+
},
110+
find: <T>(filter: PongoFilter<T>): SQL => {
111+
const filterQuery = constructFilterQuery(filter);
112+
return sql('SELECT data FROM %I WHERE %s', collectionName, filterQuery);
113+
},
114+
});

src/packages/pongo/src/postgres/update/index.ts

-18
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,6 @@ export const buildUpdateQuery = <T>(update: PongoUpdate<T>): SQL =>
1818
}
1919
}, sql('data'));
2020

21-
export const buildUpdateQueryOld = <T>(update: PongoUpdate<T>): SQL => {
22-
let updateQuery = sql('data');
23-
24-
if ('$set' in update && update.$set)
25-
updateQuery = buildSetQuery(update.$set, updateQuery);
26-
27-
if ('$unset' in update && update.$unset)
28-
updateQuery = buildUnsetQuery(update.$unset, updateQuery);
29-
30-
if ('$inc' in update && update.$inc)
31-
updateQuery = buildIncQuery(update.$inc, updateQuery);
32-
33-
if ('$push' in update && update.$push)
34-
updateQuery = buildPushQuery(update.$push, updateQuery);
35-
36-
return updateQuery;
37-
};
38-
3921
export const buildSetQuery = <T>(set: $set<T>, currentUpdateQuery: SQL): SQL =>
4022
sql(
4123
'jsonb_set(%s, %L, data || %L)',

0 commit comments

Comments
 (0)