Skip to content
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

Slonik/interceptor/camelize result #184

Merged
merged 4 commits into from
Jan 28, 2023
Merged
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
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Test suite"

on:
push

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v3
name: Use node ${{ matrix.node-version }}

- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 7

- name: Install Dependencies
run: pnpm install --frozen-lockfile

- name: Build packages
run: pnpm build

- name: Run tests
run: pnpm test
4 changes: 3 additions & 1 deletion packages/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"main": "./dist/dzangolab-fastify-config.umd.cjs",
"module": "./dist/dzangolab-fastify-config.js",
"types": "./dist/types/index.d.ts",
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "vite build && tsc --emitDeclarationOnly && mv dist/src dist/types",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore",
Expand Down
6 changes: 3 additions & 3 deletions packages/multi-tenant/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@
"@types/pg": "8.6.6",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"eslint": "8.31.0",
"eslint": "8.32.0",
"eslint-config-custom": "0.14.1",
"fastify": "4.10.2",
"fastify-plugin": "4.4.0",
"prettier": "2.8.1",
"prettier": "2.8.3",
"slonik": "30.3.1",
"tsconfig": "0.14.1",
"typescript": "4.9.4",
"vite": "4.0.3"
"vite": "4.0.4"
},
"peerDependencies": {
"@dzangolab/fastify-config": "0.14.1",
Expand Down
13 changes: 10 additions & 3 deletions packages/slonik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,28 @@
"main": "./dist/dzangolab-fastify-slonik.umd.cjs",
"module": "./dist/dzangolab-fastify-slonik.js",
"types": "./dist/types/index.d.ts",
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "vite build && tsc --emitDeclarationOnly && mv dist/src dist/types",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore",
"lint:fix": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"sort-package": "npx sort-package-json",
"test": "vitest run --coverage",
"typecheck": "tsc --noEmit -p tsconfig.json --composite false"
},
"dependencies": {
"@dzangolab/postgres-migrations": "5.4.1"
"@dzangolab/postgres-migrations": "5.4.1",
"humps": "2.0.1"
},
"devDependencies": {
"@dzangolab/fastify-config": "0.14.1",
"@types/humps": "2.0.2",
"@types/node": "18.11.18",
"@typescript-eslint/eslint-plugin": "5.49.0",
"@typescript-eslint/parser": "5.49.0",
"@vitest/coverage-istanbul": "0.28.1",
"eslint": "8.32.0",
"eslint-config-custom": "0.14.1",
"fastify": "4.10.2",
Expand All @@ -37,7 +43,8 @@
"slonik": "30.3.1",
"tsconfig": "0.14.1",
"typescript": "4.9.4",
"vite": "4.0.4"
"vite": "4.0.4",
"vitest": "0.28.3"
},
"peerDependencies": {
"@dzangolab/fastify-config": "0.14.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, expect, it } from "vitest";

import fieldNameCaseConverter from "../../interceptors/fieldNameCaseConverter";
import createClientConfiguration from "../createClientConfiguration";

import type { Query, QueryContext } from "slonik";

describe("createClientConfiguration helper", () => {
const defaultConfiguration = {
captureStackTrace: false,
connectionRetryLimit: 3,
connectionTimeout: 5000,
idleInTransactionSessionTimeout: 60000,
idleTimeout: 5000,
interceptors: [fieldNameCaseConverter],
maximumPoolSize: 10,
queryRetryLimit: 5,
statementTimeout: 60000,
transactionRetryLimit: 5,
};

it("creates default configuration", () => {
const configuration = createClientConfiguration();

expect(configuration).toEqual(defaultConfiguration);
});

it("includes fieldNameCaseConvertor interceptor", () => {
const interceptor = {
transformQuery: (context: QueryContext, query: Query): Query => {
return query;
},
};

const configuration = createClientConfiguration({
interceptors: [interceptor],
});

expect(configuration.interceptors).toContain(fieldNameCaseConverter);
});
});
31 changes: 31 additions & 0 deletions packages/slonik/src/factories/createClientConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import fieldNameCaseConverter from "../interceptors/fieldNameCaseConverter";

import type { ClientConfigurationInput } from "slonik/dist/src/types";

const createClientConfiguration = (
config?: ClientConfigurationInput
): ClientConfigurationInput => {
const configuration = {
captureStackTrace: false,
connectionRetryLimit: 3,
connectionTimeout: 5000,
idleInTransactionSessionTimeout: 60000,
idleTimeout: 5000,
interceptors: [],
maximumPoolSize: 10,
queryRetryLimit: 5,
statementTimeout: 60000,
transactionRetryLimit: 5,

...config,
};

configuration.interceptors = [
fieldNameCaseConverter,
...(config?.interceptors ?? []),
];

return configuration;
};

export default createClientConfiguration;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { describe, expect, it } from "vitest";

import createQueryContext from "./helpers/createQueryContext";
import fieldNameCaseConverter from "../fieldNameCaseConverter";

describe("fielNameCaseConverter interceptor", () => {
const interceptor = fieldNameCaseConverter;

it("transforms result field names to camelcase", () => {
const { transformRow } = interceptor;

if (!transformRow) {
throw new Error("Unexpected state.");
}

const result = transformRow(
createQueryContext(),
{
sql: "SELECT 1",
values: [],
},
{
created_at: "2022-01-01 00:00:01",
foo_bar: 1,
is_enabled: true,
is_enabled_some_of_the_time: false,
/* [OP 2023-01-28] See https://github.com/gajus/slonik/issues/428
object_child: {
user_id: 1,
},
some_children: [
{
user_id: 1,
},
{
user_id: 2,
},
],
*/
updated_at: "2022-01-01 00:00:01",
},
[
{
dataTypeId: 1,
name: "foo_bar",
},
]
);

const expected = {
createdAt: "2022-01-01 00:00:01",
fooBar: 1,
isEnabled: true,
isEnabledSomeOfTheTime: false,
/* [OP 2023-01-28] See https://github.com/gajus/slonik/issues/428
firstChild: {
userId: 1,
},
someChildren: [
{
userId: 1,
},
{
userId: 2,
},
],
*/
updatedAt: "2022-01-01 00:00:01",
};

expect(expected).toEqual(result);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { QueryContext } from "slonik";

const helper = (): QueryContext => {
return {
connectionId: "1",
log: {
getContext: () => {
return {
connectionId: "1",
poolId: "1",
};
},
},
poolId: "1",
sandbox: {},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
};

export default helper;
24 changes: 24 additions & 0 deletions packages/slonik/src/interceptors/fieldNameCaseConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import humps from "humps";

import type {
Field,
Interceptor,
Query,
QueryContext,
QueryResultRow,
} from "slonik";

const fieldNameCaseConverter: Interceptor = {
transformRow: (
/* eslint-disable @typescript-eslint/no-unused-vars */
queryContext: QueryContext,
query: Query,
row: QueryResultRow,
fields: readonly Field[]
/* eslint-enable */
): QueryResultRow => {
return humps.camelizeKeys(row) as QueryResultRow;
},
};

export default fieldNameCaseConverter;
3 changes: 2 additions & 1 deletion packages/slonik/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import FastifyPlugin from "fastify-plugin";
import { stringifyDsn } from "slonik";

import createClientConfiguration from "./factories/createClientConfiguration";
import migrate from "./migrate";
import { fastifySlonik } from "./slonik";

Expand All @@ -17,7 +18,7 @@ const plugin = async (

fastify.register(fastifySlonik, {
connectionString: stringifyDsn(config.db),
clientConfiguration: config?.clientConfiguration,
clientConfiguration: createClientConfiguration(config?.clientConfiguration),
});

fastify.log.info("Running database migrations");
Expand Down
2 changes: 2 additions & 0 deletions packages/slonik/src/sqlFactory.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { sql } from "slonik";

import {
createFilterFragment,
createLimitFragment,
Expand Down
4 changes: 4 additions & 0 deletions packages/slonik/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "tsconfig/base.json",
"exclude": [
"src/**/__test__/**/*",
],
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist",
},
"include": [
Expand Down
13 changes: 13 additions & 0 deletions packages/slonik/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineConfig(({ mode }) => {
"@dzangolab/postgres-migrations",
"fastify",
"fastify-plugin",
"humps",
"slonik",
],
output: {
Expand All @@ -29,11 +30,23 @@ export default defineConfig(({ mode }) => {
"@dzangolab/postgres-migrations": "DzangolabPostgresMigrations",
fastify: "Fastify",
"fastify-plugin": "FastifyPlugin",
humps: "Humps",
slonik: "Slonik",
},
},
},
target: "es2022",
},
resolve: {
alias: {
"@/": new URL("src/", import.meta.url).pathname,
},
},
test: {
coverage: {
provider: "istanbul",
reporter: ["text", "json", "html"],
},
},
};
});
Loading