Skip to content

Commit

Permalink
refactor(utils): improve createSchemalize (#1058)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinigami92 authored Apr 3, 2024
1 parent 9b4ec81 commit fd7dba7
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/migration-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,8 @@ export default class MigrationBuilderImpl implements MigrationBuilder {

const options: MigrationOptions = {
typeShorthands,
schemalize: createSchemalize(shouldDecamelize, false),
literal: createSchemalize(shouldDecamelize, true),
schemalize: createSchemalize({ shouldDecamelize, shouldQuote: false }),
literal: createSchemalize({ shouldDecamelize, shouldQuote: true }),
logger,
};

Expand Down
16 changes: 8 additions & 8 deletions src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ const ensureMigrationsTable = async (
try {
const schema = getMigrationTableSchema(options);
const { migrationsTable } = options;
const fullTableName = createSchemalize(
Boolean(options.decamelize),
true
)({
const fullTableName = createSchemalize({
shouldDecamelize: Boolean(options.decamelize),
shouldQuote: true,
})({
schema,
name: migrationsTable,
});
Expand Down Expand Up @@ -133,10 +133,10 @@ const ensureMigrationsTable = async (
const getRunMigrations = async (db: DBConnection, options: RunnerOption) => {
const schema = getMigrationTableSchema(options);
const { migrationsTable } = options;
const fullTableName = createSchemalize(
Boolean(options.decamelize),
true
)({
const fullTableName = createSchemalize({
shouldDecamelize: Boolean(options.decamelize),
shouldQuote: true,
})({
schema,
name: migrationsTable,
});
Expand Down
35 changes: 29 additions & 6 deletions src/utils/createSchemalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,44 @@ import decamelize from 'decamelize';
import { identity, quote } from '.';
import type { Name } from '../operations/generalTypes';

/** @deprecated Use createSchemalize(options) instead. */
export function createSchemalize(
shouldDecamelize: boolean,
shouldQuote: boolean
): (v: Name) => string {
): (value: Name) => string;
export function createSchemalize(options: {
shouldDecamelize: boolean;
shouldQuote: boolean;
}): (value: Name) => string;
export function createSchemalize(
options: boolean | { shouldDecamelize: boolean; shouldQuote: boolean },
_legacyShouldQuote?: boolean
): (value: Name) => string {
const { shouldDecamelize, shouldQuote } =
typeof options === 'boolean'
? {
shouldDecamelize: options,
shouldQuote: _legacyShouldQuote,
}
: options;

if (typeof options === 'boolean') {
console.warn(
'createSchemalize(shouldDecamelize, shouldQuote) is deprecated. Use createSchemalize({ shouldDecamelize, shouldQuote }) instead.'
);
}

const transform = [
shouldDecamelize ? decamelize : identity,
shouldQuote ? quote : identity,
].reduce((acc, fn) => (fn === identity ? acc : (x: string) => acc(fn(x))));
].reduce((acc, fn) => (fn === identity ? acc : (str) => acc(fn(str))));

return (v) => {
if (typeof v === 'object') {
const { schema, name } = v;
return (value) => {
if (typeof value === 'object') {
const { schema, name } = value;
return (schema ? `${transform(schema)}.` : '') + transform(name);
}

return transform(v);
return transform(value);
};
}
8 changes: 4 additions & 4 deletions test/presetMigrationOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { createSchemalize } from '../src/utils';

export const options1: MigrationOptions = {
typeShorthands: {},
schemalize: createSchemalize(false, false),
literal: createSchemalize(false, true),
schemalize: createSchemalize({ shouldDecamelize: false, shouldQuote: false }),
literal: createSchemalize({ shouldDecamelize: false, shouldQuote: true }),
logger: console,
};

export const options2: MigrationOptions = {
typeShorthands: {},
schemalize: createSchemalize(true, false),
literal: createSchemalize(true, true),
schemalize: createSchemalize({ shouldDecamelize: true, shouldQuote: false }),
literal: createSchemalize({ shouldDecamelize: true, shouldQuote: true }),
logger: console,
};
271 changes: 271 additions & 0 deletions test/utils/createSchemalize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import { describe, expect, it } from 'vitest';
import { createSchemalize } from '../../src/utils';

describe('utils', () => {
describe('createSchemalize', () => {
it.each([
[true, true],
[true, false],
[false, true],
[false, false],
])('should return a function', (shouldDecamelize, shouldQuote) => {
const actual = createSchemalize({
shouldDecamelize,
shouldQuote,
});

expect(actual).toBeTypeOf('function');
});

it('should decamelize and quote for string', () => {
const schemalize = createSchemalize({
shouldDecamelize: true,
shouldQuote: true,
});

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"my_table"');
});

it('should decamelize and quote for schema', () => {
const schemalize = createSchemalize({
shouldDecamelize: true,
shouldQuote: true,
});

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"my_schema"."my_table"');
});

it('should only decamelize for string', () => {
const schemalize = createSchemalize({
shouldDecamelize: true,
shouldQuote: false,
});

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('my_table');
});

it('should only decamelize for schema', () => {
const schemalize = createSchemalize({
shouldDecamelize: true,
shouldQuote: false,
});

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('my_schema.my_table');
});

it('should only quote for string', () => {
const schemalize = createSchemalize({
shouldDecamelize: false,
shouldQuote: true,
});

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"myTable"');
});

it('should only quote for schema', () => {
const schemalize = createSchemalize({
shouldDecamelize: false,
shouldQuote: true,
});

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"mySchema"."myTable"');
});

it('should not decamelize and quote for string', () => {
const schemalize = createSchemalize({
shouldDecamelize: false,
shouldQuote: false,
});

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('myTable');
});

it('should not decamelize and quote for schema', () => {
const schemalize = createSchemalize({
shouldDecamelize: false,
shouldQuote: false,
});

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('mySchema.myTable');
});

// TODO @Shinigami92 2024-04-03: Should this throw an error?
it.each([
[true, true, '""'],
[true, false, ''],
[false, true, '""'],
[false, false, ''],
])(
'should return empty string',
(shouldDecamelize, shouldQuote, expected) => {
const schemalize = createSchemalize({
shouldDecamelize,
shouldQuote,
});

const actual = schemalize('');

expect(actual).toBeTypeOf('string');
expect(actual).toBe(expected);
}
);

it.each([
[true, true, '"my_table"'],
[true, false, 'my_table'],
[false, true, '"myTable"'],
[false, false, 'myTable'],
])('should accept only name', (shouldDecamelize, shouldQuote, expected) => {
const schemalize = createSchemalize({
shouldDecamelize,
shouldQuote,
});

const actual = schemalize({ name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe(expected);
});
});

describe('createSchemalize (deprecated)', () => {
it.each([
[true, true],
[true, false],
[false, true],
[false, false],
])('should return a function', (shouldDecamelize, shouldQuote) => {
const actual = createSchemalize(shouldDecamelize, shouldQuote);

expect(actual).toBeTypeOf('function');
});

it('should decamelize and quote for string', () => {
const schemalize = createSchemalize(true, true);

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"my_table"');
});

it('should decamelize and quote for schema', () => {
const schemalize = createSchemalize(true, true);

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"my_schema"."my_table"');
});

it('should only decamelize for string', () => {
const schemalize = createSchemalize(true, false);

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('my_table');
});

it('should only decamelize for schema', () => {
const schemalize = createSchemalize(true, false);

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('my_schema.my_table');
});

it('should only quote for string', () => {
const schemalize = createSchemalize(false, true);

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"myTable"');
});

it('should only quote for schema', () => {
const schemalize = createSchemalize(false, true);

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('"mySchema"."myTable"');
});

it('should not decamelize and quote for string', () => {
const schemalize = createSchemalize(false, false);

const actual = schemalize('myTable');

expect(actual).toBeTypeOf('string');
expect(actual).toBe('myTable');
});

it('should not decamelize and quote for schema', () => {
const schemalize = createSchemalize(false, false);

const actual = schemalize({ schema: 'mySchema', name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe('mySchema.myTable');
});

// TODO @Shinigami92 2024-04-03: Should this throw an error?
it.each([
[true, true, '""'],
[true, false, ''],
[false, true, '""'],
[false, false, ''],
])(
'should return empty string',
(shouldDecamelize, shouldQuote, expected) => {
const schemalize = createSchemalize(shouldDecamelize, shouldQuote);

const actual = schemalize('');

expect(actual).toBeTypeOf('string');
expect(actual).toBe(expected);
}
);

it.each([
[true, true, '"my_table"'],
[true, false, 'my_table'],
[false, true, '"myTable"'],
[false, false, 'myTable'],
])('should accept only name', (shouldDecamelize, shouldQuote, expected) => {
const schemalize = createSchemalize(shouldDecamelize, shouldQuote);

const actual = schemalize({ name: 'myTable' });

expect(actual).toBeTypeOf('string');
expect(actual).toBe(expected);
});
});
});
Loading

0 comments on commit fd7dba7

Please sign in to comment.