Skip to content

Commit

Permalink
fix(decorators): fix BooleanField default and WhereUnique query varia…
Browse files Browse the repository at this point in the history
…ble list (#261)

* use unique info from @unique() when building WhereUnique

* fix(decorators): use unique info from @unique() when building WhereUnique

* fix(decorators): adding default and editable to various decorators and fully support arbtrary model hierarchies
  • Loading branch information
pjpritch authored and goldcaddy77 committed Nov 24, 2019
1 parent 939ce9c commit 8f3adb1
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 33 deletions.
4 changes: 3 additions & 1 deletion src/decorators/BooleanField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ interface BooleanFieldOptions {
filter?: boolean;
nullable?: boolean;
sort?: boolean;
editable?: boolean;
}

export function BooleanField(args: BooleanFieldOptions = {}): any {
const options = { ...decoratorDefaults, ...args };
const nullableOption = options.nullable === true ? { nullable: true } : {};
const defaultOption = options.default ? { default: options.default } : {};
const defaultOption =
options.default === true || options.default === false ? { default: options.default } : {};

const factories = [
WarthogField('boolean', options),
Expand Down
3 changes: 2 additions & 1 deletion src/decorators/EnumField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { decoratorDefaults, getMetadataStorage } from '../metadata';
import { composeMethodDecorators, generatedFolderPath, MethodDecoratorFactory } from '../utils';

interface EnumFieldOptions {
nullable?: boolean;
default?: any;
editable?: boolean;
filter?: boolean;
nullable?: boolean;
sort?: boolean;
}

Expand Down
5 changes: 4 additions & 1 deletion src/decorators/FloatField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { WarthogField } from './WarthogField';

interface FloatFieldOptions {
dataType?: FloatColumnType; // int16, jsonb, etc...
default?: number;
filter?: boolean;
nullable?: boolean;
sort?: boolean;
Expand All @@ -17,6 +18,7 @@ interface FloatFieldOptions {
export function FloatField(args: FloatFieldOptions = decoratorDefaults): any {
const options = { ...decoratorDefaults, ...args };
const nullableOption = options.nullable === true ? { nullable: true } : {};
const defaultOption = options.default ? { default: options.default } : {};
const databaseConnection: string = process.env.WARTHOG_DB_CONNECTION || '';
const type = defaultColumnType(databaseConnection, 'float');

Expand All @@ -28,7 +30,8 @@ export function FloatField(args: FloatFieldOptions = decoratorDefaults): any {
Column({
// This type will be different per database driver
type: args.dataType || type,
...nullableOption
...nullableOption,
...defaultOption
}) as MethodDecoratorFactory
];

Expand Down
5 changes: 4 additions & 1 deletion src/decorators/IntField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { WarthogField } from './WarthogField';

interface IntFieldOptions {
dataType?: IntColumnType;
default?: number;
filter?: boolean;
nullable?: boolean;
sort?: boolean;
}

export function IntField(args: IntFieldOptions = decoratorDefaults): any {
const options = { ...decoratorDefaults, ...args };
const defaultOption = options.default ? { default: options.default } : {};
const nullableOption = options.nullable === true ? { nullable: true } : {};

const factories = [
Expand All @@ -25,7 +27,8 @@ export function IntField(args: IntFieldOptions = decoratorDefaults): any {
}),
Column({
type: args.dataType || 'int',
...nullableOption
...nullableOption,
...defaultOption
}) as MethodDecoratorFactory
];

Expand Down
1 change: 1 addition & 0 deletions src/decorators/StringField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface StringFieldOptions {
nullable?: boolean;
sort?: boolean;
unique?: boolean;
editable?: boolean;
}

export function StringField(args: StringFieldOptions = decoratorDefaults): any {
Expand Down
79 changes: 50 additions & 29 deletions src/schema/TypeORMConverter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Container } from 'typedi';
import { getMetadataArgsStorage } from 'typeorm';

import { ColumnMetadata, getMetadataStorage, ModelMetadata } from '../metadata';

Expand All @@ -10,6 +11,26 @@ import {

const ignoreBaseModels = ['BaseModel', 'BaseModelUUID'];

export function getColumnsForModel(model: ModelMetadata) {
const models = [model];
const columns: { [key: string]: ColumnMetadata } = {};

let superProto = model.klass ? model.klass.__proto__ : null;
while (superProto) {
const superModel = getMetadataStorage().getModel(superProto.name);
superModel && models.unshift(superModel);
superProto = superProto.__proto__;
}

models.forEach(aModel => {
aModel.columns.forEach((col: ColumnMetadata) => {
columns[col.propertyName] = col;
});
});

return Object.values(columns);
}

export function filenameToImportPath(filename: string): string {
return filename.replace(/\.(j|t)s$/, '').replace(/\\/g, '/');
}
Expand Down Expand Up @@ -51,14 +72,31 @@ export function generateEnumMapImports(): string[] {

export function entityToWhereUniqueInput(model: ModelMetadata): string {
const uniques = getMetadataStorage().uniquesForModel(model);
const others = getMetadataArgsStorage().uniques;
const modelUniques: { [key: string]: string } = {};
others.forEach(o => {
const name = (o.target as Function).name;
const columns = o.columns as string[];
if (name === model.name && columns) {
columns.forEach((col: string) => {
modelUniques[col] = col;
});
}
});
uniques.forEach(unique => {
modelUniques[unique] = unique;
});
const distinctUniques = Object.keys(modelUniques);

// If there is only one unique field, it should not be nullable
const uniqueFieldsAreNullable = uniques.length > 1;
const uniqueFieldsAreNullable = distinctUniques.length > 1;

let fieldsTemplate = '';

model.columns.forEach((column: ColumnMetadata) => {
if (!column.unique) {
const modelColumns = getColumnsForModel(model);
modelColumns.forEach((column: ColumnMetadata) => {
// Uniques can be from Field or Unique annotations
if (!modelUniques[column.propertyName]) {
return;
}

Expand Down Expand Up @@ -109,7 +147,8 @@ export function entityToCreateInput(model: ModelMetadata): string {
`;
}

model.columns.forEach((column: ColumnMetadata) => {
const modelColumns = getColumnsForModel(model);
modelColumns.forEach((column: ColumnMetadata) => {
if (!column.editable) {
return;
}
Expand Down Expand Up @@ -157,7 +196,8 @@ export function entityToCreateInput(model: ModelMetadata): string {
export function entityToUpdateInput(model: ModelMetadata): string {
let fieldTemplates = '';

model.columns.forEach((column: ColumnMetadata) => {
const modelColumns = getColumnsForModel(model);
modelColumns.forEach((column: ColumnMetadata) => {
if (!column.editable) {
return;
}
Expand Down Expand Up @@ -224,7 +264,8 @@ function columnToTypes(column: ColumnMetadata) {
export function entityToWhereInput(model: ModelMetadata): string {
let fieldTemplates = '';

model.columns.forEach((column: ColumnMetadata) => {
const modelColumns = getColumnsForModel(model);
modelColumns.forEach((column: ColumnMetadata) => {
// Don't allow filtering on these fields
if (!column.filter) {
return;
Expand Down Expand Up @@ -406,35 +447,15 @@ export function entityToCreateManyArgs(model: ModelMetadata): string {
}

export function entityToOrderByEnum(model: ModelMetadata): string {
const metadata = getMetadataStorage();
const superName = model.klass ? model.klass.__proto__.name : null;
const superModel = superName ? metadata.getModel(superName) : undefined;

let fieldsTemplate = '';
const hitCache: { [key: string]: boolean } = {};

if (superModel) {
superModel.columns.forEach((column: ColumnMetadata) => {
if (column.type === 'json') {
return;
}

if (column.sort) {
hitCache[column.propertyName] = true;
fieldsTemplate += `
${column.propertyName}_ASC = '${column.propertyName}_ASC',
${column.propertyName}_DESC = '${column.propertyName}_DESC',
`;
}
});
}

model.columns.forEach((column: ColumnMetadata) => {
const modelColumns = getColumnsForModel(model);
modelColumns.forEach((column: ColumnMetadata) => {
if (column.type === 'json') {
return;
}

if (column.sort && !hitCache[column.propertyName]) {
if (column.sort) {
fieldsTemplate += `
${column.propertyName}_ASC = '${column.propertyName}_ASC',
${column.propertyName}_DESC = '${column.propertyName}_DESC',
Expand Down

0 comments on commit 8f3adb1

Please sign in to comment.