diff --git a/examples/01-simple-model/.env b/examples/01-simple-model/.env index 96308dae..a2264e11 100644 --- a/examples/01-simple-model/.env +++ b/examples/01-simple-model/.env @@ -1,8 +1,6 @@ NODE_ENV=development PGUSER=postgres WARTHOG_API_BASE_URL=http://localhost:4100 -WARTHOG_DB_DATABASE=warthog-example-1 -WARTHOG_DB_USERNAME=postgres -WARTHOG_DB_PASSWORD=postgres +WARTHOG_DB_URL=postgres://postgres:postgres@localhost:5432/warthog-example-1 WARTHOG_DB_SYNCHRONIZE=true WARTHOG_FILTER_BY_DEFAULT=true diff --git a/examples/01-simple-model/generated/binding.ts b/examples/01-simple-model/generated/binding.ts index 2c56edaf..c479c081 100644 --- a/examples/01-simple-model/generated/binding.ts +++ b/examples/01-simple-model/generated/binding.ts @@ -59,6 +59,8 @@ export type UserOrderByInput = 'firstName_ASC' | 'stringEnumField_DESC' | 'rating_ASC' | 'rating_DESC' | + 'profileId_ASC' | + 'profileId_DESC' | 'createdAt_ASC' | 'createdAt_DESC' | 'createdById_ASC' | @@ -78,6 +80,57 @@ export type UserOrderByInput = 'firstName_ASC' | 'id_ASC' | 'id_DESC' +export interface ProfileCreateInput { + body: String +} + +export interface ProfileUpdateInput { + body?: String | null +} + +export interface ProfileWhereInput { + body_eq?: String | null + body_contains?: String | null + body_startsWith?: String | null + body_endsWith?: String | null + body_in?: String[] | String | null + createdAt_eq?: DateTime | null + createdAt_lt?: DateTime | null + createdAt_lte?: DateTime | null + createdAt_gt?: DateTime | null + createdAt_gte?: DateTime | null + createdById_eq?: ID_Input | null + createdById_in?: ID_Output[] | ID_Output | null + updatedAt_eq?: DateTime | null + updatedAt_lt?: DateTime | null + updatedAt_lte?: DateTime | null + updatedAt_gt?: DateTime | null + updatedAt_gte?: DateTime | null + updatedById_eq?: ID_Input | null + updatedById_in?: ID_Output[] | ID_Output | null + deletedAt_all?: Boolean | null + deletedAt_eq?: DateTime | null + deletedAt_lt?: DateTime | null + deletedAt_lte?: DateTime | null + deletedAt_gt?: DateTime | null + deletedAt_gte?: DateTime | null + deletedById_eq?: ID_Input | null + deletedById_in?: ID_Output[] | ID_Output | null + version_eq?: Int | null + version_gt?: Int | null + version_gte?: Int | null + version_lt?: Int | null + version_lte?: Int | null + version_in?: Int[] | Int | null + ownerId_eq?: ID_Input | null + ownerId_in?: ID_Output[] | ID_Output | null + id_in?: ID_Output[] | ID_Output | null +} + +export interface ProfileWhereUniqueInput { + id: ID_Output +} + export interface UserCreateInput { firstName: String lastName?: String | null @@ -86,6 +139,7 @@ export interface UserCreateInput { isRequired: Boolean stringEnumField: StringEnum rating: Float + profileId: String } export interface UserUpdateInput { @@ -96,6 +150,7 @@ export interface UserUpdateInput { isRequired?: Boolean | null stringEnumField?: StringEnum | null rating?: Float | null + profileId?: String | null } export interface UserWhereInput { @@ -130,6 +185,8 @@ export interface UserWhereInput { rating_lt?: Float | null rating_lte?: Float | null rating_in?: Float[] | Float | null + profileId_eq?: String | null + profileId_in?: String[] | String | null createdAt_eq?: DateTime | null createdAt_lt?: DateTime | null createdAt_lte?: DateTime | null @@ -179,6 +236,20 @@ export interface PageInfo { endCursor?: String | null } +export interface Profile { + id: ID_Output + createdAt: DateTime + createdById: ID_Output + updatedAt?: DateTime | null + updatedById?: ID_Output | null + deletedAt?: DateTime | null + deletedById?: ID_Output | null + version: Int + ownerId: ID_Output + body: String + user: User +} + export interface StandardDeleteResponse { id: ID_Output } @@ -200,6 +271,8 @@ export interface User { isRequired: Boolean stringEnumField: StringEnum rating: Float + profile: Profile + profileId: String } /* diff --git a/examples/01-simple-model/generated/classes.ts b/examples/01-simple-model/generated/classes.ts index 935260cb..1e88ca80 100644 --- a/examples/01-simple-model/generated/classes.ts +++ b/examples/01-simple-model/generated/classes.ts @@ -28,6 +28,10 @@ import { StringEnum } from "../src/user.model"; import { User } from "../src/user.model"; +// @ts-ignore + +import { Profile } from "../src/profile.model"; + export enum UserOrderByEnum { firstName_ASC = "firstName_ASC", firstName_DESC = "firstName_DESC", @@ -50,6 +54,9 @@ export enum UserOrderByEnum { rating_ASC = "rating_ASC", rating_DESC = "rating_DESC", + profileId_ASC = "profileId_ASC", + profileId_DESC = "profileId_DESC", + createdAt_ASC = "createdAt_ASC", createdAt_DESC = "createdAt_DESC", @@ -177,6 +184,12 @@ export class UserWhereInput { @TypeGraphQLField(() => [Float], { nullable: true }) rating_in?: number[]; + @TypeGraphQLField({ nullable: true }) + profileId_eq?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + profileId_in?: string[]; + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_eq?: DateTimeString; @@ -302,6 +315,9 @@ export class UserCreateInput { @TypeGraphQLField() rating!: number; + + @TypeGraphQLField() + profileId!: string; } @TypeGraphQLInputType() @@ -326,6 +342,9 @@ export class UserUpdateInput { @TypeGraphQLField({ nullable: true }) rating?: number; + + @TypeGraphQLField({ nullable: true }) + profileId?: string; } @ArgsType() @@ -348,3 +367,189 @@ export class UserUpdateArgs { @TypeGraphQLField() data!: UserUpdateInput; @TypeGraphQLField() where!: UserWhereUniqueInput; } + +export enum ProfileOrderByEnum { + body_ASC = "body_ASC", + body_DESC = "body_DESC", + + createdAt_ASC = "createdAt_ASC", + createdAt_DESC = "createdAt_DESC", + + createdById_ASC = "createdById_ASC", + createdById_DESC = "createdById_DESC", + + updatedAt_ASC = "updatedAt_ASC", + updatedAt_DESC = "updatedAt_DESC", + + updatedById_ASC = "updatedById_ASC", + updatedById_DESC = "updatedById_DESC", + + deletedAt_ASC = "deletedAt_ASC", + deletedAt_DESC = "deletedAt_DESC", + + deletedById_ASC = "deletedById_ASC", + deletedById_DESC = "deletedById_DESC", + + version_ASC = "version_ASC", + version_DESC = "version_DESC", + + ownerId_ASC = "ownerId_ASC", + ownerId_DESC = "ownerId_DESC", + + id_ASC = "id_ASC", + id_DESC = "id_DESC" +} + +registerEnumType(ProfileOrderByEnum, { + name: "ProfileOrderByInput" +}); + +@TypeGraphQLInputType() +export class ProfileWhereInput { + @TypeGraphQLField({ nullable: true }) + body_eq?: string; + + @TypeGraphQLField({ nullable: true }) + body_contains?: string; + + @TypeGraphQLField({ nullable: true }) + body_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + body_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + body_in?: string[]; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + createdAt_eq?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + createdAt_lt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + createdAt_lte?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + createdAt_gt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + createdAt_gte?: DateTimeString; + + @TypeGraphQLField(() => ID, { nullable: true }) + createdById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + createdById_in?: string[]; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + updatedAt_eq?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + updatedAt_lt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + updatedAt_lte?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + updatedAt_gt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + updatedAt_gte?: DateTimeString; + + @TypeGraphQLField(() => ID, { nullable: true }) + updatedById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + updatedById_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + deletedAt_all?: Boolean; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + deletedAt_eq?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + deletedAt_lt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + deletedAt_lte?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + deletedAt_gt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + deletedAt_gte?: DateTimeString; + + @TypeGraphQLField(() => ID, { nullable: true }) + deletedById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + deletedById_in?: string[]; + + @TypeGraphQLField(() => Int, { nullable: true }) + version_eq?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + version_gt?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + version_gte?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + version_lt?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + version_lte?: number; + + @TypeGraphQLField(() => [Int], { nullable: true }) + version_in?: number[]; + + @TypeGraphQLField(() => ID, { nullable: true }) + ownerId_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + ownerId_in?: string[]; + + @TypeGraphQLField(() => [ID], { nullable: true }) + id_in?: string[]; +} + +@TypeGraphQLInputType() +export class ProfileWhereUniqueInput { + @TypeGraphQLField(() => ID) + id?: string; +} + +@TypeGraphQLInputType() +export class ProfileCreateInput { + @TypeGraphQLField() + body!: string; +} + +@TypeGraphQLInputType() +export class ProfileUpdateInput { + @TypeGraphQLField({ nullable: true }) + body?: string; +} + +@ArgsType() +export class ProfileWhereArgs extends PaginationArgs { + @TypeGraphQLField(() => ProfileWhereInput, { nullable: true }) + where?: ProfileWhereInput; + + @TypeGraphQLField(() => ProfileOrderByEnum, { nullable: true }) + orderBy?: ProfileOrderByEnum; +} + +@ArgsType() +export class ProfileCreateManyArgs { + @TypeGraphQLField(() => [ProfileCreateInput]) + data!: ProfileCreateInput[]; +} + +@ArgsType() +export class ProfileUpdateArgs { + @TypeGraphQLField() data!: ProfileUpdateInput; + @TypeGraphQLField() where!: ProfileWhereUniqueInput; +} diff --git a/examples/01-simple-model/generated/schema.graphql b/examples/01-simple-model/generated/schema.graphql index 463d203b..86171753 100644 --- a/examples/01-simple-model/generated/schema.graphql +++ b/examples/01-simple-model/generated/schema.graphql @@ -20,6 +20,71 @@ type PageInfo { endCursor: String } +type Profile { + id: ID! + createdAt: DateTime! + createdById: ID! + updatedAt: DateTime + updatedById: ID + deletedAt: DateTime + deletedById: ID + version: Int! + ownerId: ID! + body: String! + user: User! +} + +input ProfileCreateInput { + body: String! +} + +input ProfileUpdateInput { + body: String +} + +input ProfileWhereInput { + body_eq: String + body_contains: String + body_startsWith: String + body_endsWith: String + body_in: [String!] + createdAt_eq: DateTime + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + createdById_eq: ID + createdById_in: [ID!] + updatedAt_eq: DateTime + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + updatedById_eq: ID + updatedById_in: [ID!] + deletedAt_all: Boolean + deletedAt_eq: DateTime + deletedAt_lt: DateTime + deletedAt_lte: DateTime + deletedAt_gt: DateTime + deletedAt_gte: DateTime + deletedById_eq: ID + deletedById_in: [ID!] + version_eq: Int + version_gt: Int + version_gte: Int + version_lt: Int + version_lte: Int + version_in: [Int!] + ownerId_eq: ID + ownerId_in: [ID!] + id_in: [ID!] +} + +input ProfileWhereUniqueInput { + id: ID! +} + type Query { users(offset: Int, limit: Int = 50, where: UserWhereInput, orderBy: UserOrderByInput): [User!]! user(where: UserWhereUniqueInput!): User! @@ -51,6 +116,8 @@ type User { isRequired: Boolean! stringEnumField: StringEnum! rating: Float! + profile: Profile! + profileId: String! } input UserCreateInput { @@ -61,6 +128,7 @@ input UserCreateInput { isRequired: Boolean! stringEnumField: StringEnum! rating: Float! + profileId: String! } enum UserOrderByInput { @@ -78,6 +146,8 @@ enum UserOrderByInput { stringEnumField_DESC rating_ASC rating_DESC + profileId_ASC + profileId_DESC createdAt_ASC createdAt_DESC createdById_ASC @@ -106,6 +176,7 @@ input UserUpdateInput { isRequired: Boolean stringEnumField: StringEnum rating: Float + profileId: String } input UserWhereInput { @@ -140,6 +211,8 @@ input UserWhereInput { rating_lt: Float rating_lte: Float rating_in: [Float!] + profileId_eq: String + profileId_in: [String!] createdAt_eq: DateTime createdAt_lt: DateTime createdAt_lte: DateTime diff --git a/examples/01-simple-model/src/profile.model.ts b/examples/01-simple-model/src/profile.model.ts new file mode 100644 index 00000000..d6882fe4 --- /dev/null +++ b/examples/01-simple-model/src/profile.model.ts @@ -0,0 +1,14 @@ +import { BaseModel, Model, OneToOne, StringField } from '../../../src'; +import { User } from './user.model'; + +@Model() +export class Profile extends BaseModel { + @StringField() + body?: string; + + @OneToOne( + () => User, + user => user.profile + ) + user: User; +} diff --git a/examples/01-simple-model/src/user.model.ts b/examples/01-simple-model/src/user.model.ts index 3bf18c1b..fe9de873 100644 --- a/examples/01-simple-model/src/user.model.ts +++ b/examples/01-simple-model/src/user.model.ts @@ -1,3 +1,4 @@ +import { JoinColumn } from 'typeorm'; import { BaseModel, BooleanField, @@ -6,8 +7,10 @@ import { FloatField, IntField, Model, + OneToOne, StringField } from '../../../src'; +import { Profile } from './profile.model'; // Note: this must be exported and in the same file where it's attached with @EnumField // Also - must use string enums @@ -38,4 +41,14 @@ export class User extends BaseModel { @FloatField() rating?: number; + + @OneToOne( + () => Profile, + profile => profile.user + ) + @JoinColumn() + profile!: Profile; + + @StringField({ filter: ['eq', 'in'] }) + profileId?: string; } diff --git a/src/decorators/OneToOne.ts b/src/decorators/OneToOne.ts new file mode 100644 index 00000000..9c2520c2 --- /dev/null +++ b/src/decorators/OneToOne.ts @@ -0,0 +1,17 @@ +import { Field } from 'type-graphql'; +import { JoinColumn, ObjectType, OneToOne as TypeORMOneToOne, RelationOptions } from 'typeorm'; +import { composeMethodDecorators, MethodDecoratorFactory } from '../utils'; + +export function OneToOne( + typeFunctionOrTarget: (type?: any) => ObjectType, + inverseSide?: string | ((object: T) => any), + options?: RelationOptions +): any { + const factories = [ + JoinColumn() as MethodDecoratorFactory, + Field(typeFunctionOrTarget, options) as MethodDecoratorFactory, + TypeORMOneToOne(typeFunctionOrTarget, inverseSide, options) as MethodDecoratorFactory + ]; + + return composeMethodDecorators(...factories); +} diff --git a/src/decorators/OneToOne.ts.bak b/src/decorators/OneToOne.ts.bak deleted file mode 100644 index f79b3586..00000000 --- a/src/decorators/OneToOne.ts.bak +++ /dev/null @@ -1,16 +0,0 @@ -import { Field } from 'type-graphql'; -import { JoinTable, ManyToMany as TypeORMManyToMany } from 'typeorm'; -import { composeMethodDecorators, MethodDecoratorFactory } from '../utils'; - -// Note: for many to many relationships, you need to set one item as the "JoinTable" -// therefore, we have 2 separate decorators. Just make sure to add one to one table and -// One to the other in the relationship -export function OneToOne(parentType: any, joinFunc: any, options: any = {}): any { - const factories = [ - JoinTable() as MethodDecoratorFactory, - Field(() => [parentType()], { nullable: true, ...options }) as MethodDecoratorFactory, - TypeORMManyToMany(parentType, joinFunc, options) as MethodDecoratorFactory - ]; - - return composeMethodDecorators(...factories); -} diff --git a/src/decorators/index.ts b/src/decorators/index.ts index 69fd2aa9..a6092ed9 100644 --- a/src/decorators/index.ts +++ b/src/decorators/index.ts @@ -23,6 +23,7 @@ export * from './ManyToOne'; export * from './Model'; export * from './NumericField'; export * from './OneToMany'; +export * from './OneToOne'; export * from './OwnerIdField'; export * from './PrimaryIdField'; export * from './StringField';