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

Output information on PRIMARY KEY and UNIQUE constraints #81

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion bin/schemats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface SchematsConfig {
output: string,
camelCase: boolean,
noHeader: boolean,
exposeConstraintInfo: boolean
}

let argv: SchematsConfig = yargs
Expand All @@ -41,6 +42,7 @@ let argv: SchematsConfig = yargs
.alias('C', 'camelCase')
.describe('C', 'Camel-case columns')
.describe('noHeader', 'Do not write header')
.describe('exposeConstraintInfo', 'Export meta interfaces with constraint information')
.demand('o')
.nargs('o', 1)
.alias('o', 'output')
Expand All @@ -61,7 +63,7 @@ let argv: SchematsConfig = yargs
}

let formattedOutput = await typescriptOfSchema(
argv.conn, argv.table, argv.schema, { camelCase: argv.camelCase, writeHeader: !argv.noHeader })
argv.conn, argv.table, argv.schema, { camelCase: argv.camelCase, writeHeader: !argv.noHeader, exposeConstraintInfo: argv.exposeConstraintInfo })
fs.writeFileSync(argv.output, formattedOutput)

} catch (e) {
Expand Down
21 changes: 20 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Created by xiamx on 2016-08-10.
*/

import { generateEnumType, generateTableTypes, generateTableInterface } from './typescript'
import { generateEnumType, generateTableTypes, generateTableInterface, generateExports } from './typescript'
import { getDatabase, Database } from './schema'
import Options, { OptionValues } from './options'
import { processString, Options as ITFOptions } from 'typescript-formatter'
Expand Down Expand Up @@ -45,6 +45,20 @@ function buildHeader (db: Database, tables: string[], schema: string|null, optio
`
}

function helperTypes () {
return `
type HasTypeKey<T> = {
[K in keyof T]: {
type: any
}
}

type SimpleSchema<T extends HasTypeKey<T>> = {
[K in keyof T] : T[K]['type']
}
`
}

export async function typescriptOfTable (db: Database|string,
table: string,
schema: string,
Expand All @@ -57,6 +71,8 @@ export async function typescriptOfTable (db: Database|string,
let tableTypes = await db.getTableTypes(table, schema, options)
interfaces += generateTableTypes(table, tableTypes, options)
interfaces += generateTableInterface(table, tableTypes, options)
interfaces += generateExports(table, tableTypes, options)

return interfaces
}

Expand Down Expand Up @@ -87,6 +103,9 @@ export async function typescriptOfSchema (db: Database|string,
if (optionsObject.options.writeHeader) {
output += buildHeader(db, tables, schema, options)
}
if (!optionsObject.exposeConstraintInfo()) {
output += helperTypes()
}
output += enumTypes
output += interfaces

Expand Down
8 changes: 7 additions & 1 deletion src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { camelCase, upperFirst } from 'lodash'

const DEFAULT_OPTIONS: OptionValues = {
writeHeader: true,
camelCase: false
camelCase: false,
exposeConstraintInfo: false
}

export type OptionValues = {
camelCase?: boolean
writeHeader?: boolean // write schemats description header
exposeConstraintInfo?: boolean
}

export default class Options {
Expand All @@ -24,4 +26,8 @@ export default class Options {
transformColumnName (columnName: string) {
return this.options.camelCase ? camelCase(columnName) : columnName
}

exposeConstraintInfo () {
return this.options.exposeConstraintInfo
}
}
4 changes: 3 additions & 1 deletion src/schemaInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import Options from './options'
export interface ColumnDefinition {
udtName: string,
nullable: boolean,
tsType?: string
tsType?: string,
primaryKey?: boolean,
unique?: boolean
}

export interface TableDefinition {
Expand Down
20 changes: 18 additions & 2 deletions src/schemaPostgres.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class PostgresDatabase implements Database {

public async getTableDefinition (tableName: string, tableSchema: string) {
let tableDefinition: TableDefinition = {}
type T = { column_name: string, udt_name: string, is_nullable: string }
type T = { column_name: string, udt_name: string, is_nullable: string, constraint_type: 'UNIQUE' | 'PRIMARY KEY' }
await this.db.each<T>(
'SELECT column_name, udt_name, is_nullable ' +
'FROM information_schema.columns ' +
Expand All @@ -128,9 +128,25 @@ export class PostgresDatabase implements Database {
(schemaItem: T) => {
tableDefinition[schemaItem.column_name] = {
udtName: schemaItem.udt_name,
nullable: schemaItem.is_nullable === 'YES'
nullable: schemaItem.is_nullable === 'YES',
primaryKey: false,
unique: false
}
})

// Fill in PRIMARY KEY and UNIQUE constraint details
await this.db.each<T>(
'SELECT kcu.column_name, tc.constraint_type ' +
'FROM information_schema.table_constraints AS tc ' +
'JOIN information_schema.key_column_usage AS kcu ' +
'ON tc.constraint_name = kcu.constraint_name ' +
'WHERE tc.table_name = $1 and tc.table_schema = $2',
[tableName, tableSchema],
(schemaItem: T) => {
tableDefinition[schemaItem.column_name].unique = schemaItem.constraint_type === 'UNIQUE'
tableDefinition[schemaItem.column_name].primaryKey = schemaItem.constraint_type === 'PRIMARY KEY'
}
)
return tableDefinition
}

Expand Down
37 changes: 33 additions & 4 deletions src/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function generateTableInterface (tableNameRaw: string, tableDefinition: T
})

return `
export interface ${normalizeName(tableName, options)} {
interface ${normalizeName(tableName, options)}Meta {
${members}
}
`
Expand All @@ -54,10 +54,23 @@ export function generateTableTypes (tableNameRaw: string, tableDefinition: Table
const tableName = options.transformTypeName(tableNameRaw)
let fields = ''
Object.keys(tableDefinition).forEach((columnNameRaw) => {
let type = tableDefinition[columnNameRaw].tsType
let nullable = tableDefinition[columnNameRaw].nullable ? '| null' : ''
const columnName = options.transformColumnName(columnNameRaw)
fields += `export type ${normalizeName(columnName, options)} = ${type}${nullable};\n`
fields += `export type ${normalizeName(columnName, options)} = {`

const { tsType, nullable, primaryKey, unique } = tableDefinition[columnNameRaw]

// Mapped TS type
fields += `type: ${tsType}`
fields += nullable ? '| null' : ''
fields += `,`

// Primary key constraint
fields += primaryKey !== undefined ? `primaryKey: ${primaryKey},` : ''

// Unique constraint
fields += unique !== undefined ? `unique: ${unique},` : ''

fields += '};\n'
})

return `
Expand All @@ -66,3 +79,19 @@ export function generateTableTypes (tableNameRaw: string, tableDefinition: Table
}
`
}

export function generateExports (tableNameRaw: string, tableDefinition: TableDefinition, options: Options) {
const tableName = options.transformTypeName(tableNameRaw)

if (options.exposeConstraintInfo()) {
// If `--exposeConstraintInfo` flag is passed, simply rename <table>Meta to <table>
return `
export type ${normalizeName(tableName, options)} = ${normalizeName(tableName, options)}Meta
`
}

// If no `--exposeConstraintInfo` flag is passed, transform the meta interfaces to simple interfaces
return `
export type ${normalizeName(tableName, options)} = SimpleSchema<${normalizeName(tableName, options)}Meta>
`
}
152 changes: 84 additions & 68 deletions test/expected/mysql/osm.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,84 @@
/* tslint:disable */

type HasTypeKey<T> = {
[K in keyof T]: {
type: any
}
}

type SimpleSchema<T extends HasTypeKey<T>> = {
[K in keyof T]: T[K]['type']
}

export type enum_enum_col = 'enum1' | 'enum2' | 'enum3';
export type enum_nullable_enum_col = 'enum1' | 'enum2' | 'enum3';
export type set_set_col = 'set1' | 'set2' | 'set3';
export type set_nullable_set_col = 'set1' | 'set2' | 'set3';

export namespace usersFields {
export type char_col = string;
export type nullable_char_col = string | null;
export type text_col = string;
export type nullable_text_col = string | null;
export type tinytext_col = string;
export type nullable_tinytext_col = string | null;
export type mediumtext_col = string;
export type nullable_mediumtext_col = string | null;
export type longtext_col = string;
export type nullable_longtext_col = string | null;
export type time_col = string;
export type nullable_time_col = string | null;
export type geometry_col = string;
export type nullable_geometry_col = string | null;
export type integer_col = number;
export type nullable_integer_col = number | null;
export type int_col = number;
export type nullable_int_col = number | null;
export type smallint_col = number;
export type nullable_smallint_col = number | null;
export type mediumint_col = number;
export type nullable_mediumint_col = number | null;
export type bigint_col = number;
export type nullable_bigint_col = number | null;
export type double_col = number;
export type nullable_double_col = number | null;
export type decimal_col = number;
export type nullable_decimal_col = number | null;
export type numeric_col = number;
export type nullable_numeric_col = number | null;
export type float_col = number;
export type nullable_float_col = number | null;
export type year_col = number;
export type nullable_year_col = number | null;
export type tinyint_col = boolean;
export type nullable_tinyint_col = boolean | null;
export type date_col = Date;
export type nullable_date_col = Date | null;
export type datetime_col = Date;
export type nullable_datetime_col = Date | null;
export type timestamp_col = Date;
export type tinyblob_col = Buffer;
export type nullable_tinyblob_col = Buffer | null;
export type mediumblob_col = Buffer;
export type nullable_mediumblob_col = Buffer | null;
export type longblob_col = Buffer;
export type nullable_longblob_col = Buffer | null;
export type blob_col = Buffer;
export type nullable_blob_col = Buffer | null;
export type binary_col = Buffer;
export type nullable_binary_col = Buffer | null;
export type varbinary_col = Buffer;
export type nullable_varbinary_col = Buffer | null;
export type bit_col = Buffer;
export type nullable_bit_col = Buffer | null;
export type enum_col = enum_enum_col;
export type nullable_enum_col = enum_nullable_enum_col | null;
export type set_col = set_set_col;
export type nullable_set_col = set_nullable_set_col | null;
export type char_col = { type: string, };
export type nullable_char_col = { type: string | null, };
export type text_col = { type: string, };
export type nullable_text_col = { type: string | null, };
export type tinytext_col = { type: string, };
export type nullable_tinytext_col = { type: string | null, };
export type mediumtext_col = { type: string, };
export type nullable_mediumtext_col = { type: string | null, };
export type longtext_col = { type: string, };
export type nullable_longtext_col = { type: string | null, };
export type time_col = { type: string, };
export type nullable_time_col = { type: string | null, };
export type geometry_col = { type: string, };
export type nullable_geometry_col = { type: string | null, };
export type integer_col = { type: number, };
export type nullable_integer_col = { type: number | null, };
export type int_col = { type: number, };
export type nullable_int_col = { type: number | null, };
export type smallint_col = { type: number, };
export type nullable_smallint_col = { type: number | null, };
export type mediumint_col = { type: number, };
export type nullable_mediumint_col = { type: number | null, };
export type bigint_col = { type: number, };
export type nullable_bigint_col = { type: number | null, };
export type double_col = { type: number, };
export type nullable_double_col = { type: number | null, };
export type decimal_col = { type: number, };
export type nullable_decimal_col = { type: number | null, };
export type numeric_col = { type: number, };
export type nullable_numeric_col = { type: number | null, };
export type float_col = { type: number, };
export type nullable_float_col = { type: number | null, };
export type year_col = { type: number, };
export type nullable_year_col = { type: number | null, };
export type tinyint_col = { type: boolean, };
export type nullable_tinyint_col = { type: boolean | null, };
export type date_col = { type: Date, };
export type nullable_date_col = { type: Date | null, };
export type datetime_col = { type: Date, };
export type nullable_datetime_col = { type: Date | null, };
export type timestamp_col = { type: Date, };
export type tinyblob_col = { type: Buffer, };
export type nullable_tinyblob_col = { type: Buffer | null, };
export type mediumblob_col = { type: Buffer, };
export type nullable_mediumblob_col = { type: Buffer | null, };
export type longblob_col = { type: Buffer, };
export type nullable_longblob_col = { type: Buffer | null, };
export type blob_col = { type: Buffer, };
export type nullable_blob_col = { type: Buffer | null, };
export type binary_col = { type: Buffer, };
export type nullable_binary_col = { type: Buffer | null, };
export type varbinary_col = { type: Buffer, };
export type nullable_varbinary_col = { type: Buffer | null, };
export type bit_col = { type: Buffer, };
export type nullable_bit_col = { type: Buffer | null, };
export type enum_col = { type: enum_enum_col, };
export type nullable_enum_col = { type: enum_nullable_enum_col | null, };
export type set_col = { type: set_set_col, };
export type nullable_set_col = { type: set_nullable_set_col | null, };

}

export interface users {
interface usersMeta {
char_col: usersFields.char_col;
nullable_char_col: usersFields.nullable_char_col;
text_col: usersFields.text_col;
Expand Down Expand Up @@ -131,30 +141,36 @@ export interface users {

}

export type users = SimpleSchema<usersMeta>

export namespace user_enumsFields {
export type enum_col = enum_enum_col;
export type nullable_enum_col = enum_nullable_enum_col | null;
export type set_col = set_set_col;
export type nullable_set_col = set_nullable_set_col | null;
export type enum_col = { type: enum_enum_col, };
export type nullable_enum_col = { type: enum_nullable_enum_col | null, };
export type set_col = { type: set_set_col, };
export type nullable_set_col = { type: set_nullable_set_col | null, };

}

export interface user_enums {
interface user_enumsMeta {
enum_col: user_enumsFields.enum_col;
nullable_enum_col: user_enumsFields.nullable_enum_col;
set_col: user_enumsFields.set_col;
nullable_set_col: user_enumsFields.nullable_set_col;

}

export type user_enums = SimpleSchema<user_enumsMeta>

export namespace packageFields {
export type number_ = number;
export type string_ = string;
export type number_ = { type: number, };
export type string_ = { type: string, };

}

export interface package_ {
interface package_Meta {
number: packageFields.number_;
string: packageFields.string_;

}

export type package_ = SimpleSchema<package_Meta>
Loading