-
-
Notifications
You must be signed in to change notification settings - Fork 139
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style: compartmentalize project structure
- Loading branch information
Showing
29 changed files
with
847 additions
and
684 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,22 @@ | ||
// @flow | ||
|
||
import { | ||
createUlid | ||
} from '../utilities'; | ||
import type { | ||
InternalQueryAnyFunctionType | ||
} from '../types'; | ||
import query from './query'; | ||
|
||
/** | ||
* Makes a query and expects any number of results. | ||
*/ | ||
const any: InternalQueryAnyFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = createUlid()) => { | ||
const { | ||
rows | ||
} = await query(connection, clientConfiguration, rawSql, values, queryId); | ||
|
||
return rows; | ||
}; | ||
|
||
export default any; |
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,47 @@ | ||
// @flow | ||
|
||
import { | ||
createUlid | ||
} from '../utilities'; | ||
import { | ||
DataIntegrityError | ||
} from '../errors'; | ||
import type { | ||
InternalQueryAnyFirstFunctionType | ||
} from '../types'; | ||
import log from '../Logger'; | ||
import any from './any'; | ||
|
||
const anyFirst: InternalQueryAnyFirstFunctionType = async (connection, clientConfigurationType, rawSql, values, queryId = createUlid()) => { | ||
const rows = await any(connection, clientConfigurationType, rawSql, values, queryId); | ||
|
||
if (rows.length === 0) { | ||
return []; | ||
} | ||
|
||
const keys = Object.keys(rows[0]); | ||
|
||
if (keys.length !== 1) { | ||
log.error({ | ||
queryId | ||
}, 'DataIntegrityError'); | ||
|
||
throw new DataIntegrityError(); | ||
} | ||
|
||
const firstColumnName = keys[0]; | ||
|
||
if (typeof firstColumnName !== 'string') { | ||
log.error({ | ||
queryId | ||
}, 'DataIntegrityError'); | ||
|
||
throw new DataIntegrityError(); | ||
} | ||
|
||
return rows.map((row) => { | ||
return row[firstColumnName]; | ||
}); | ||
}; | ||
|
||
export default anyFirst; |
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,113 @@ | ||
// @flow | ||
|
||
import pg from 'pg'; | ||
import serializeError from 'serialize-error'; | ||
import { | ||
parse as parseConnectionString | ||
} from 'pg-connection-string'; | ||
import { | ||
mapTaggedTemplateLiteralInvocation | ||
} from '../utilities'; | ||
import type { | ||
ClientConfigurationType, | ||
DatabaseConfigurationType, | ||
DatabaseSingleConnectionType | ||
} from '../types'; | ||
import log from '../Logger'; | ||
import any from './any'; | ||
import anyFirst from './anyFirst'; | ||
import many from './many'; | ||
import manyFirst from './manyFirst'; | ||
import maybeOne from './maybeOne'; | ||
import maybeOneFirst from './maybeOneFirst'; | ||
import one from './one'; | ||
import oneFirst from './oneFirst'; | ||
import query from './query'; | ||
import transaction from './transaction'; | ||
|
||
// @see https://github.com/facebook/flow/issues/2977#issuecomment-390613203 | ||
const defaultClientConfiguration = Object.freeze({}); | ||
|
||
export default async ( | ||
connectionConfiguration: DatabaseConfigurationType, | ||
clientConfiguration: ClientConfigurationType = defaultClientConfiguration | ||
): Promise<DatabaseSingleConnectionType> => { | ||
const pool = new pg.Pool(typeof connectionConfiguration === 'string' ? parseConnectionString(connectionConfiguration) : connectionConfiguration); | ||
|
||
pool.on('error', (error) => { | ||
log.error({ | ||
error: serializeError(error) | ||
}, 'client connection error'); | ||
}); | ||
|
||
pool.on('connect', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'created a new client connection'); | ||
}); | ||
|
||
pool.on('acquire', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'client is checked out from the pool'); | ||
}); | ||
|
||
pool.on('remove', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'client connection is closed and removed from the client pool'); | ||
}); | ||
|
||
const connection = await pool.connect(); | ||
|
||
connection.on('notice', (notice) => { | ||
log.info({ | ||
notice | ||
}, 'notice message'); | ||
}); | ||
|
||
let ended = false; | ||
|
||
const bindConnection = { | ||
any: mapTaggedTemplateLiteralInvocation(any.bind(null, connection, clientConfiguration)), | ||
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, connection, clientConfiguration)), | ||
end: async () => { | ||
if (ended) { | ||
return ended; | ||
} | ||
|
||
await connection.release(); | ||
|
||
ended = pool.end(); | ||
|
||
return ended; | ||
}, | ||
many: mapTaggedTemplateLiteralInvocation(many.bind(null, connection, clientConfiguration)), | ||
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, connection, clientConfiguration)), | ||
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, connection, clientConfiguration)), | ||
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, connection, clientConfiguration)), | ||
one: mapTaggedTemplateLiteralInvocation(one.bind(null, connection, clientConfiguration)), | ||
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, connection, clientConfiguration)), | ||
query: mapTaggedTemplateLiteralInvocation(query.bind(null, connection, clientConfiguration)), | ||
transaction: (handler) => { | ||
return transaction(bindConnection, handler); | ||
} | ||
}; | ||
|
||
return bindConnection; | ||
}; |
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,133 @@ | ||
// @flow | ||
|
||
import pg from 'pg'; | ||
import serializeError from 'serialize-error'; | ||
import { | ||
parse as parseConnectionString | ||
} from 'pg-connection-string'; | ||
import { | ||
mapTaggedTemplateLiteralInvocation | ||
} from '../utilities'; | ||
import type { | ||
ClientConfigurationType, | ||
DatabasePoolType, | ||
DatabaseConfigurationType | ||
} from '../types'; | ||
import log from '../Logger'; | ||
import any from './any'; | ||
import anyFirst from './anyFirst'; | ||
import many from './many'; | ||
import manyFirst from './manyFirst'; | ||
import maybeOne from './maybeOne'; | ||
import maybeOneFirst from './maybeOneFirst'; | ||
import one from './one'; | ||
import oneFirst from './oneFirst'; | ||
import query from './query'; | ||
import transaction from './transaction'; | ||
|
||
// @see https://github.com/facebook/flow/issues/2977#issuecomment-390613203 | ||
const defaultClientConfiguration = Object.freeze({}); | ||
|
||
export default ( | ||
connectionConfiguration: DatabaseConfigurationType, | ||
clientConfiguration: ClientConfigurationType = defaultClientConfiguration | ||
): DatabasePoolType => { | ||
const pool = new pg.Pool(typeof connectionConfiguration === 'string' ? parseConnectionString(connectionConfiguration) : connectionConfiguration); | ||
|
||
pool.on('error', (error) => { | ||
log.error({ | ||
error: serializeError(error) | ||
}, 'client connection error'); | ||
}); | ||
|
||
pool.on('connect', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'created a new client connection'); | ||
}); | ||
|
||
pool.on('acquire', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'client is checked out from the pool'); | ||
}); | ||
|
||
pool.on('remove', (client) => { | ||
log.info({ | ||
processId: client.processID, | ||
stats: { | ||
idleConnectionCount: pool.idleCount, | ||
totalConnectionCount: pool.totalCount, | ||
waitingRequestCount: pool.waitingCount | ||
} | ||
}, 'client connection is closed and removed from the client pool'); | ||
}); | ||
|
||
const connect = async () => { | ||
const connection = await pool.connect(); | ||
|
||
connection.on('notice', (notice) => { | ||
log.info({ | ||
notice | ||
}, 'notice message'); | ||
}); | ||
|
||
const bindConnection = { | ||
any: mapTaggedTemplateLiteralInvocation(any.bind(null, connection, clientConfiguration)), | ||
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, connection, clientConfiguration)), | ||
many: mapTaggedTemplateLiteralInvocation(many.bind(null, connection, clientConfiguration)), | ||
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, connection, clientConfiguration)), | ||
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, connection, clientConfiguration)), | ||
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, connection, clientConfiguration)), | ||
one: mapTaggedTemplateLiteralInvocation(one.bind(null, connection, clientConfiguration)), | ||
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, connection, clientConfiguration)), | ||
query: mapTaggedTemplateLiteralInvocation(query.bind(null, connection, clientConfiguration)), | ||
release: connection.release.bind(connection), | ||
transaction: (handler) => { | ||
return transaction(bindConnection, handler); | ||
} | ||
}; | ||
|
||
return bindConnection; | ||
}; | ||
|
||
return { | ||
any: mapTaggedTemplateLiteralInvocation(any.bind(null, pool, clientConfiguration)), | ||
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, pool, clientConfiguration)), | ||
connect, | ||
many: mapTaggedTemplateLiteralInvocation(many.bind(null, pool, clientConfiguration)), | ||
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, pool, clientConfiguration)), | ||
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, pool, clientConfiguration)), | ||
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, pool, clientConfiguration)), | ||
one: mapTaggedTemplateLiteralInvocation(one.bind(null, pool, clientConfiguration)), | ||
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, pool, clientConfiguration)), | ||
query: mapTaggedTemplateLiteralInvocation(query.bind(null, pool, clientConfiguration)), | ||
transaction: async (handler) => { | ||
log.debug('allocating a new connection to execute the transaction'); | ||
|
||
const connection = await connect(); | ||
|
||
let result; | ||
|
||
try { | ||
result = await connection.transaction(handler); | ||
} finally { | ||
log.debug('releasing the connection that was earlier secured to execute a transaction'); | ||
|
||
await connection.release(); | ||
} | ||
|
||
return result; | ||
} | ||
}; | ||
}; |
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,4 @@ | ||
// @flow | ||
|
||
export {default as createConnection} from './createConnection'; | ||
export {default as createPool} from './createPool'; |
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,36 @@ | ||
// @flow | ||
|
||
import { | ||
createUlid | ||
} from '../utilities'; | ||
import { | ||
NotFoundError | ||
} from '../errors'; | ||
import type { | ||
InternalQueryManyFunctionType | ||
} from '../types'; | ||
import log from '../Logger'; | ||
import query from './query'; | ||
|
||
/** | ||
* Makes a query and expects at least 1 result. | ||
* | ||
* @throws NotFoundError If query returns no rows. | ||
*/ | ||
const many: InternalQueryManyFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = createUlid()) => { | ||
const { | ||
rows | ||
} = await query(connection, clientConfiguration, rawSql, values, queryId); | ||
|
||
if (rows.length === 0) { | ||
log.error({ | ||
queryId | ||
}, 'NotFoundError'); | ||
|
||
throw new NotFoundError(); | ||
} | ||
|
||
return rows; | ||
}; | ||
|
||
export default many; |
Oops, something went wrong.