-
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extracted SQL builder from execution on collection to enable unit tes…
…ting SQL generation in the future
- Loading branch information
1 parent
4b33197
commit c2bb851
Showing
2 changed files
with
134 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import pg from 'pg'; | ||
import { v4 as uuid } from 'uuid'; | ||
import { | ||
type PongoCollection, | ||
type PongoDeleteResult, | ||
type PongoFilter, | ||
type PongoInsertOneResult, | ||
type PongoUpdate, | ||
type PongoUpdateResult, | ||
} from '../main'; | ||
import { executeSQL } from './execute'; | ||
import { constructFilterQuery } from './filter'; | ||
import { sql, type SQL } from './sql'; | ||
import { buildUpdateQuery } from './update'; | ||
|
||
export const postgresCollection = <T>( | ||
collectionName: string, | ||
pool: pg.Pool, | ||
): PongoCollection<T> => { | ||
const createCollection = executeSQL( | ||
pool, | ||
SQLBuilder.createCollection(collectionName), | ||
); | ||
return { | ||
createCollection: async () => { | ||
await createCollection; | ||
}, | ||
insertOne: async (document: T): Promise<PongoInsertOneResult> => { | ||
await createCollection; | ||
|
||
const id = uuid(); | ||
|
||
const result = await executeSQL( | ||
pool, | ||
SQLBuilder.insertOne(collectionName, id, document), | ||
); | ||
|
||
return result.rowCount | ||
? { insertedId: id, acknowledged: true } | ||
: { insertedId: null, acknowledged: false }; | ||
}, | ||
updateOne: async ( | ||
filter: PongoFilter<T>, | ||
update: PongoUpdate<T>, | ||
): Promise<PongoUpdateResult> => { | ||
await createCollection; | ||
|
||
const result = await executeSQL( | ||
pool, | ||
SQLBuilder.updateOne(collectionName, filter, update), | ||
); | ||
return result.rowCount | ||
? { acknowledged: true, modifiedCount: result.rowCount } | ||
: { acknowledged: false, modifiedCount: 0 }; | ||
}, | ||
deleteOne: async (filter: PongoFilter<T>): Promise<PongoDeleteResult> => { | ||
await createCollection; | ||
|
||
const result = await executeSQL( | ||
pool, | ||
SQLBuilder.deleteOne(collectionName, filter), | ||
); | ||
return result.rowCount | ||
? { acknowledged: true, deletedCount: result.rowCount } | ||
: { acknowledged: false, deletedCount: 0 }; | ||
}, | ||
findOne: async (filter: PongoFilter<T>): Promise<T | null> => { | ||
await createCollection; | ||
|
||
const result = await executeSQL( | ||
pool, | ||
SQLBuilder.findOne(collectionName, filter), | ||
); | ||
return (result.rows[0]?.data ?? null) as T | null; | ||
}, | ||
find: async (filter: PongoFilter<T>): Promise<T[]> => { | ||
await createCollection; | ||
|
||
const result = await executeSQL( | ||
pool, | ||
SQLBuilder.find(collectionName, filter), | ||
); | ||
return result.rows.map((row) => row.data as T); | ||
}, | ||
}; | ||
}; | ||
|
||
export const SQLBuilder = { | ||
createCollection: (collectionName: string): SQL => | ||
sql( | ||
'CREATE TABLE IF NOT EXISTS %I (_id UUID PRIMARY KEY, data JSONB)', | ||
collectionName, | ||
), | ||
insertOne: <T>(collectionName: string, id: string, document: T): SQL => | ||
sql( | ||
'INSERT INTO %I (_id, data) VALUES (%L, %L)', | ||
collectionName, | ||
id, | ||
JSON.stringify({ ...document, _id: id }), | ||
), | ||
updateOne: <T>( | ||
collectionName: string, | ||
filter: PongoFilter<T>, | ||
update: PongoUpdate<T>, | ||
): SQL => { | ||
const filterQuery = constructFilterQuery(filter); | ||
const updateQuery = buildUpdateQuery(update); | ||
|
||
return sql( | ||
'UPDATE %I SET data = %s WHERE %s', | ||
collectionName, | ||
updateQuery, | ||
filterQuery, | ||
); | ||
}, | ||
deleteOne: <T>(collectionName: string, filter: PongoFilter<T>): SQL => { | ||
const filterQuery = constructFilterQuery(filter); | ||
return sql('DELETE FROM %I WHERE %s', collectionName, filterQuery); | ||
}, | ||
findOne: <T>(collectionName: string, filter: PongoFilter<T>): SQL => { | ||
const filterQuery = constructFilterQuery(filter); | ||
return sql( | ||
'SELECT data FROM %I WHERE %s LIMIT 1', | ||
collectionName, | ||
filterQuery, | ||
); | ||
}, | ||
find: <T>(collectionName: string, filter: PongoFilter<T>): SQL => { | ||
const filterQuery = constructFilterQuery(filter); | ||
return sql('SELECT data FROM %I WHERE %s', collectionName, filterQuery); | ||
}, | ||
}; |