Skip to content

Commit

Permalink
feat: add camel case support
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinBlomberg committed Aug 10, 2022
1 parent ddebea1 commit bd2325e
Show file tree
Hide file tree
Showing 16 changed files with 293 additions and 104 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# kysely-codegen changelog

## 0.5.0

### Notable changes

- feat: add camel case support

## 0.4.0

### Notable changes
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kysely-codegen",
"version": "0.4.0-beta.3",
"version": "0.5.0",
"author": "Robin Blomberg",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand All @@ -18,9 +18,12 @@
"scripts": {
"build": "tsc",
"dev": "ts-node-dev --quiet --respawn ./src/bin/index.ts",
"docker:get-mysql-ip": "docker inspect -f {{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}} kysely_codegen_mysql",
"docker:get-postgres-ip": "docker inspect -f {{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}} kysely_codegen_postgres",
"docker:up": "docker-compose up -d",
"start": "node ./dist/bin/index.js",
"test": "ts-node-dev ./src/tests/index.test.ts"
"test": "ts-node-dev ./src/tests/index.test.ts",
"test:watch": "ts-node-dev --quiet --respawn ./src/tests/index.test.ts"
},
"dependencies": {
"chalk": "^4.1.2",
Expand Down
51 changes: 51 additions & 0 deletions src/case-converter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { CamelCasePlugin } from 'kysely';

class CaseConverter extends CamelCasePlugin {
toCamelCase(string: string) {
return this.camelCase(string);
}

toSnakeCase(string: string) {
return this.snakeCase(string);
}
}

/**
* Returns a camelCased string.
*
* @example
* ```ts
* camelCase('foo_bar')
* // fooBar
* ```
*/
export const toCamelCase = (string: string) => {
return new CaseConverter().toCamelCase(string);
};

/**
* Returns a PascalCased string.
*
* @example
* ```ts
* pascalCase('foo_bar')
* // FooBar
* ```
*/
export const toPascalCase = (string: string) => {
const camelCased = toCamelCase(string);
return camelCased.slice(0, 1).toUpperCase() + camelCased.slice(1);
};

/**
* Returns a snake_cased string.
*
* @example
* ```ts
* snakeCase('FooBar')
* // foo_bar
* ```
*/
export const toSnakeCase = (string: string) => {
return new CaseConverter().toSnakeCase(string);
};
35 changes: 24 additions & 11 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const DEFAULT_OUT_FILE = './node_modules/kysely-codegen/dist/db.d.ts';
const VALID_DIALECTS = ['mysql', 'postgres', 'sqlite'];
const VALID_FLAGS = new Set([
'_',
'camel-case',
'dialect',
'h',
'help',
Expand All @@ -19,6 +20,7 @@ const VALID_FLAGS = new Set([
]);

export type CliOptions = {
camelCase: boolean;
dialectName: DialectName | undefined;
logLevel: LogLevel;
outFile: string;
Expand All @@ -31,6 +33,8 @@ export type CliOptions = {
*/
export class Cli {
async #generate(options: CliOptions) {
const { camelCase } = options;

const logger = new Logger(options.logLevel);

const connectionStringParser = new ConnectionStringParser();
Expand All @@ -52,7 +56,12 @@ export class Cli {
options.dialectName ?? inferredDialectName,
);

const generator = new Generator({ connectionString, dialect, logger });
const generator = new Generator({
camelCase,
connectionString,
dialect,
logger,
});
await generator.generate(options);
}

Expand All @@ -75,6 +84,7 @@ export class Cli {
const argv = minimist(args);

const _: string[] = argv._;
const camelCase = !!argv['camel-case'];
const dialectName = argv.dialect as DialectName | undefined;
const help =
!!argv.h || !!argv.help || _.includes('-h') || _.includes('--help');
Expand All @@ -96,15 +106,18 @@ export class Cli {

if (help) {
logger.log(
'\n' +
'kysely-codegen [options]\n' +
'\n' +
` --dialect Set the SQL dialect. (values: [${dialectValues}])\n` +
' --help, -h Print this message.\n' +
' --log-level Set the terminal log level. (values: [debug, info, warn, error, silent], default: warn)\n' +
` --out-file Set the file build path. (default: ${DEFAULT_OUT_FILE})\n` +
' --print Print the generated output to the terminal.\n' +
' --url Set the database connection string URL. This may point to an environment variable. (default: env(DATABASE_URL))\n',
'',
'kysely-codegen [options]',
'',
' --all Display all options.',
' --camel-case Use the Kysely CamelCasePlugin.',
` --dialect Set the SQL dialect. (values: [${dialectValues}])`,
' --help, -h Print this message.',
' --log-level Set the terminal log level. (values: [debug, info, warn, error, silent], default: warn)',
` --out-file Set the file build path. (default: ${DEFAULT_OUT_FILE})`,
' --print Print the generated output to the terminal.',
' --url Set the database connection string URL. This may point to an environment variable. (default: env(DATABASE_URL))',
'',
);

process.exit(0);
Expand Down Expand Up @@ -140,7 +153,7 @@ export class Cli {
}
}

return { dialectName, logLevel, outFile, print, url };
return { camelCase, dialectName, logLevel, outFile, print, url };
}

async run(argv: string[]) {
Expand Down
8 changes: 4 additions & 4 deletions src/dialect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dialect as KyselyDialect, TableMetadata } from 'kysely';
import { Adapter } from './adapter';
import { pascalCase } from './util';
import { toCamelCase, toPascalCase } from './case-converter';

export type DriverInstantiateOptions = {
connectionString: string;
Expand All @@ -26,14 +26,14 @@ export abstract class Dialect {
/**
* Returns the name of the table in the exported `DB` interface.
*/
getExportedTableName(table: TableMetadata): string {
return table.name;
getExportedTableName(table: TableMetadata, camelCase: boolean): string {
return camelCase ? toCamelCase(table.name) : table.name;
}

/**
* Returns the TypeScript symbol name for the given table.
*/
getSymbolName(table: TableMetadata): string {
return pascalCase(table.name);
return toPascalCase(table.name);
}
}
17 changes: 11 additions & 6 deletions src/dialects/postgres/postgres-dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {
PostgresDialect as KyselyPostgresDialect,
TableMetadata,
} from 'kysely';
import { toPascalCase } from '../../case-converter';
import { Dialect, DriverInstantiateOptions } from '../../dialect';
import { pascalCase } from '../../util';
import { PostgresAdapter } from './postgres-adapter';

export class PostgresDialect extends Dialect {
Expand All @@ -20,15 +20,20 @@ export class PostgresDialect extends Dialect {
});
}

override getExportedTableName(table: TableMetadata): string {
override getExportedTableName(
table: TableMetadata,
camelCase: boolean,
): string {
const tableName = super.getExportedTableName(table, camelCase);
return table.schema === 'public'
? super.getExportedTableName(table)
: `${table.schema}.${table.name}`;
? tableName
: `${table.schema}.${tableName}`;
}

override getSymbolName(table: TableMetadata): string {
const symbolName = super.getSymbolName(table);
return table.schema === 'public'
? super.getSymbolName(table)
: pascalCase(`${table.schema}_${table.name}`);
? symbolName
: toPascalCase(`${table.schema}_${symbolName}`);
}
}
5 changes: 4 additions & 1 deletion src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Serializer } from './serializer';
import { Transformer } from './transformer';

export type GeneratorOptions = {
camelCase: boolean;
connectionString: string;
dialect: Dialect;
introspector?: Introspector;
Expand Down Expand Up @@ -37,7 +38,9 @@ export class Generator {
this.introspector = options.introspector ?? new Introspector();
this.logger = options.logger;
this.serializer = options.serializer ?? new Serializer();
this.transformer = options.transformer ?? new Transformer(options.dialect);
this.transformer =
options.transformer ??
new Transformer(options.dialect, options.camelCase);
}

async generate(options: GenerateOptions) {
Expand Down
24 changes: 18 additions & 6 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,33 @@ export class Logger {

debug(...values: unknown[]) {
if (this.logLevel >= LogLevel.DEBUG) {
console.debug(this.serializeDebug(...values));
for (const value of values) {
console.debug(this.serializeDebug(value));
}
}
}

error(...values: unknown[]) {
if (this.logLevel >= LogLevel.ERROR) {
console.error(this.serializeError(...values));
for (const value of values) {
console.error(this.serializeError(value));
}
}
}

info(...values: unknown[]) {
if (this.logLevel >= LogLevel.INFO) {
console.info(this.serializeInfo(...values));
for (const value of values) {
console.info(this.serializeInfo(value));
}
}
}

log(...values: unknown[]) {
if (this.logLevel >= LogLevel.INFO) {
console.log(...values);
for (const value of values) {
console.log(value);
}
}
}

Expand All @@ -68,13 +76,17 @@ export class Logger {

success(...values: unknown[]) {
if (this.logLevel >= LogLevel.INFO) {
console.log(this.serializeSuccess(...values));
for (const value of values) {
console.log(this.serializeSuccess(value));
}
}
}

warn(...values: unknown[]) {
if (this.logLevel >= LogLevel.WARN) {
console.warn(this.serializeWarn(...values));
for (const value of values) {
console.warn(this.serializeWarn(value));
}
}
}
}
4 changes: 2 additions & 2 deletions src/nodes/alias-declaration-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export class AliasDeclarationNode {
readonly name: string;
readonly type = NodeType.ALIAS_DECLARATION;

constructor(name: string, generics: string[], body: ExpressionNode) {
constructor(name: string, args: string[], body: ExpressionNode) {
this.name = name;
this.args = generics;
this.args = args;
this.body = body;
}
}
4 changes: 2 additions & 2 deletions src/nodes/object-expression-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export class ObjectExpressionNode {
readonly properties: PropertyNode[];
readonly type = NodeType.OBJECT_EXPRESSION;

constructor(body: PropertyNode[]) {
this.properties = body;
constructor(properties: PropertyNode[]) {
this.properties = properties;
}
}
14 changes: 7 additions & 7 deletions src/tests/connection-string-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { describe, it } from './test.utils';

const parser = new ConnectionStringParser();

void describe('connection-string-parser', async () => {
await describe('postgres', async () => {
await it('should infer the correct dialect name', () => {
void describe('connection-string-parser', () => {
void describe('postgres', () => {
void it('should infer the correct dialect name', () => {
deepStrictEqual(
parser.parse({
connectionString: 'postgres://username:password@hostname/database',
Expand All @@ -19,8 +19,8 @@ void describe('connection-string-parser', async () => {
});
});

await describe('mysql', async () => {
await it('should infer the correct dialect name', () => {
void describe('mysql', () => {
void it('should infer the correct dialect name', () => {
deepStrictEqual(
parser.parse({
connectionString: 'mysql://username:password@hostname/database',
Expand All @@ -42,8 +42,8 @@ void describe('connection-string-parser', async () => {
});
});

await describe('sqlite', async () => {
await it('should infer the correct dialect name', () => {
void describe('sqlite', () => {
void it('should infer the correct dialect name', () => {
deepStrictEqual(
parser.parse({
connectionString: 'C:/Program Files/sqlite3/db',
Expand Down
1 change: 1 addition & 0 deletions src/tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import './connection-string-parser.test';
import './transformer.test';
Loading

0 comments on commit bd2325e

Please sign in to comment.