Git Product home page Git Product logo

Comments (23)

RDeluxe avatar RDeluxe commented on May 16, 2024 6

Well, I was thinking that I may not be the only developer who wants to easily use the Entities as DTOs while coding let's say a REST API. I'm still struggling to see a nice and clean way to do so.

But you're right, it's not directly linked to TypeORM. Sorry to spam this thread and thanks for your work.

from typeorm.

RDeluxe avatar RDeluxe commented on May 16, 2024 4

Sorry to come back to this, but the actual solution may not cover one use case.

Usually I'm using TypeScript interfaces, in a separate repository, for both my client and my server. This allows for easier manipulations: my client and server knows what they are going to receive, interfaces updates are shared to both repo, etc.

I'm using Nest.js and Typeorm together (and it's working quite well), but I'm struggling to find a good solution. Nest.js routes expects classes as DTOs, and while I could use the entities this lead to non-logical behavior (fields may be set, but all the methods are undefined).

  public async updateUser( @Param() params, @Body() user: User) {
    user.id = params.id;
    user = await this.userService.update(user);
    if (user == null) {
      throw new HttpException('Not Found', 404);
    }
    return user;
  }

So I'm thinking about generating (via gulp or webpack) DTOs based on the entities, to clarify the separation bewteen DTOs (data) and Entities (objects with methods). I'm not quite sure that the previously mentioned shims can do this, as I'm not well versed into webpack.

For example this file :

import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, OneToMany } from 'typeorm';
import { Project } from 'entities';

@Entity()
export class User extends BaseEntity {
    @PrimaryGeneratedColumn('uuid')
    public id: string;

    @Column()
    public firstName: string;

    @Column()
    public lastName: string;

    @Column()
    public email: string;

    @Column()
    public password: string;

    @Column()
    public admin: boolean;

    @OneToMany(type => Project, project => project.user, {
        cascade: true,
    })
    public projects: Project[];
}

Would become

import { ProjectDTO } from 'dtos';

export class UserDTO  {
    public id: string;

    public firstName: string;

    public lastName: string;

    public email: string;

    public password: string;

    public admin: boolean;

    public projects: ProjectDTO[];
}

It's not trivial, but maintaining 2 copies of the same file is also pretty cumbersome.

from typeorm.

bijeebuss avatar bijeebuss commented on May 16, 2024 2

I ran into this issue too in react native. Even though its debatable whether or not it's advisable to share models between the repository, server, and client, I think that concept is one of the best parts about typeorm. Is there any progress on making it modular? For now are the decorators from ionic-orm compatible with typeorm?

from typeorm.

strictd avatar strictd commented on May 16, 2024 1

I advised against combining the frontend and backend systems for quite awhile. There were too many advantages to typescripting everything together to not at least try. So far it's been working out great.

from typeorm.

TylerDev6 avatar TylerDev6 commented on May 16, 2024

I too experienced this issue. Had to have my BE classes subclass my FE classes in the meantime.

from typeorm.

strictd avatar strictd commented on May 16, 2024

since i webpack the FE and grunt together the BE I created a typeorm-fake.ts file with all the decorators returning empty functions. in webpack.config.js i told resolve.alias: { 'typeorm': './typeorm-fake' } been working so far, I also do not have super complex data structures.

typeorm-fake.ts

/* typeorm/src/decorator/columns/ */
export function Column(): Function;
export function Column(type: any): Function;
export function Column(options: any): Function;
export function Column(type: any, options: any): Function;
export function Column(typeOrOptions?: any, options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function CreateDateColumn(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function DiscriminatorColumn(discriminatorOptions: any): Function {
  return function (target: Function) {};
}

export function PrimaryGeneratedColumn(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function PrimaryColumn(options?: any): Function;
export function PrimaryColumn(type?: any, options?: any): Function;
export function PrimaryColumn(typeOrOptions?: any, options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function UpdateDateColumn(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function VersionColumn(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}


/* typeorm/src/decorator/listeners/ */
export function AfterInsert() {
  return function (object: Object, propertyName: string) {};
}

export function AfterLoad() {
  return function (object: Object, propertyName: string) {};
}

export function AfterRemove() {
  return function (object: Object, propertyName: string) {};
}

export function AfterUpdate() {
  return function (object: Object, propertyName: string) {};
}

export function BeforeInsert() {
  return function (object: Object, propertyName: string) {};
}

export function BeforeRemove() {
  return function (object: Object, propertyName: string) {};
}

export function BeforeUpdate() {
  return function (object: Object, propertyName: string) {};
}

export function EventSubscriber() {
  return function (target: Function) {};
}


/* typeorm/src/decorator/options/ */
export function JoinColumn(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function JoinTable(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function ManyToMany<T>(typeFunction: any, options?: any): Function;
export function ManyToMany<T>(typeFunction: any,
                              inverseSide?: any,
                              options?: any): Function;
export function ManyToMany<T>(typeFunction: any,
                              inverseSideOrOptions?: any,
                              options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function ManyToOne<T>(typeFunction: any, options?: any): Function;
export function ManyToOne<T>(typeFunction: any,
                             inverseSide?: any,
                             options?: any): Function;
export function ManyToOne<T>(typeFunction: any,
                              inverseSideOrOptions?: any,
                              options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function OneToMany<T>(typeFunction: any,
                             inverseSide: any,
                             options?: any): Function;
export function OneToMany<T>(typeFunction: any,
                             inverseSideOrOptions: any,
                             options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function OneToOne<T>(typeFunction: any, options?: any): Function;
export function OneToOne<T>(typeFunction: any,
                            inverseSide?: any,
                            options?: any): Function;
export function OneToOne<T>(typeFunction: any,
                            inverseSideOrOptions?: any,
                            options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function RelationCount<T>(relation: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function RelationId<T>(relation: any): Function {
  return function (object: Object, propertyName: string) {};
}


/* typeorm/src/decorator/tables/ */
export function AbstractTable() {
  return function (target: Function) {};
}

export function ClassTableChild(tableName?: any, options?: any) {
  return function (target: Function) {};
}

export function ClosureTable(name?: any, options?: any) {
  return function (target: Function) {};
}

export function EmbeddableTable(): Function {
  return function (target: Function) {};
}

export function SingleTableChild() {
  return function (target: Function) {};
}

export function Table(name?: any, options?: any) {
  return function (target: Function) {};
}

export function TableInheritance(type: any) {
  return function (target: Function) {};
}


/* typeorm/src/decorator/tree/ */
export function TreeChildren(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}

export function TreeLevelColumn(): Function {
  return function (object: Object, propertyName: string) {};
}

export function TreeParent(options?: any): Function {
  return function (object: Object, propertyName: string) {};
}


/* typeorm/src/decorator/ */
export function DiscriminatorValue(value: any): Function {
  return function (target: Function) {};
}
export function Embedded<T>(typeFunction: any) {
  return function (object: Object, propertyName: string) {};
}

export function Index(options?: any): Function;
export function Index(name: any, options?: any): Function;
export function Index(name: any, fields: any, options?: any): Function;
export function Index(fields: any, options?: any): Function;
export function Index(fields: any, options?: any): Function;
export function Index(name: any, fields: any, options?: any): Function;
export function Index(nameOrFields: any,
                      maybeFieldsOrOptions?: any,
                      maybeOptions?: any): Function {
  return function (clsOrObject: Function|Object, propertyName?: string) {};
}

export function NamingStrategy(name?: any): Function {
  return function (target: Function) {};
}

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

I didn't get what is your suggestion here? (because I have no idea how to handle this situation)

from typeorm.

TylerDev6 avatar TylerDev6 commented on May 16, 2024

Essentially, if you write the decorators as interfaces then using them in a FE application means we won't have to import the Node dependencies

from typeorm.

strictd avatar strictd commented on May 16, 2024

My suggestion with typeorm-fake is a hacky fix. It looks like you have an IDEA comment already in place that may solve this issue. src/metadata/EntityMetadata.ts importing LazyRelationsWrapper seems to be the only library, when loading a decorator, that requires a db connection. I believe if you implemented your // todo: IDEA. store all entity metadata in the EntityMetadata too? (this will open more features for metadata objects + no need to access connection in lot of places) Since the problem is accessing any sort of db connection from the client side.

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

if you write the decorators as interfaces

@TylerDev6 can you please tell more about this implementation? I didn't get what do you mean by "decorators as interfaces"

@strictd why did you talk about LazyRelationsWrapper? Is problem there? I thought problem in decorators

from typeorm.

strictd avatar strictd commented on May 16, 2024

Ok in my current development setup. I have a single src/ directory that is broken down into;
src/api
src/browser
src/mobile
src/models
src/providers

I am using typescripted classes from src/models for all components, frontend and backend.
browser view (typescript/ng2),
mobile view (typescript/ng2/ionic2),
api server (typescript/express/typeorm)

Since i'm using one set of models for both frontend and backend, when the frontend attempts to import { Table, Column } from 'typeorm'; typeorm attempts to use the connection manager, which from a client side isn't possible. Following down the chain of declaration imports, i've found one place where LazyRelationsWrapper is getting imported and through that import requires the use of the connection manager, which is unavailable from a frontend component.

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

generally I don't recommend people to use shared model between frontend and backend, because of such issues. I have no idea how to resolve this issue properly, because even if we resolve some issue in LazyRelationsWrapper frontend will load all other unnecessary dependencies.

For now fake "mapping" file as you created for webpack seems best solution, but yeah its very big monkey patch. I would like to find better solution, but nothing comes to my mind

from typeorm.

BradyNadeau avatar BradyNadeau commented on May 16, 2024

@strictd I have forked the repo and created ionic-orm -will work in angularjs2 as well.. just primarily for me to do it in Cordova/Ionic2 platform. We can use this on the client side. So far it's only supporting WebSQL. SQLite for the Apache Cordova plugin in coming soon. Feel free to check it out.
ionic-orm

I hope that one day we can get TypeORM to be modularized in a way where we could have it in the same repo..

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

@BradyLiles provide a plan how to make it modularized (what changes are needed) and lets investigate on this side

from typeorm.

BradyNadeau avatar BradyNadeau commented on May 16, 2024

I completely agree. Let's take this one offline. I'll Skype you.

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

we havent talk too much with @BradyLiles about it, but I hope if he'll have some progress on this issue and create a PR against typeorm. If not, I'll have my own plans to implement these things in the future.

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

@strictd do you still use typeorm-fake.ts file? Can you checkout this . This file will generate:

// columns
/* export */ function Column(typeOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function CreateDateColumn(options) {
    return function (object, propertyName) {
    };
}
/* export */ function DiscriminatorColumn(discriminatorOptions) {
    return function (object, propertyName) {
    };
}
/* export */ function PrimaryColumn(typeOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function PrimaryGeneratedColumn(options) {
    return function (object, propertyName) {
    };
}
/* export */ function UpdateDateColumn(options) {
    return function (object, propertyName) {
    };
}
/* export */ function VersionColumn(options) {
    return function (object, propertyName) {
    };
}
// listeners
/* export */ function AfterInsert() {
    return function (object, propertyName) {
    };
}
/* export */ function AfterLoad() {
    return function (object, propertyName) {
    };
}
/* export */ function AfterRemove() {
    return function (object, propertyName) {
    };
}
/* export */ function AfterUpdate() {
    return function (object, propertyName) {
    };
}
/* export */ function BeforeInsert() {
    return function (object, propertyName) {
    };
}
/* export */ function BeforeRemove() {
    return function (object, propertyName) {
    };
}
/* export */ function BeforeUpdate() {
    return function (object, propertyName) {
    };
}
/* export */ function EventSubscriber() {
    return function (object, propertyName) {
    };
}
// relations
/* export */ function JoinColumn(options) {
    return function (object, propertyName) {
    };
}
/* export */ function JoinTable(options) {
    return function (object, propertyName) {
    };
}
/* export */ function ManyToMany(typeFunction, inverseSideOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function ManyToOne(typeFunction, inverseSideOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function OneToMany(typeFunction, inverseSideOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function OneToOne(typeFunction, inverseSideOrOptions, options) {
    return function (object, propertyName) {
    };
}
/* export */ function RelationCount(relation) {
    return function (object, propertyName) {
    };
}
/* export */ function RelationId(relation) {
    return function (object, propertyName) {
    };
}
// tables
/* export */ function AbstractTable() {
    return function (object) {
    };
}
/* export */ function ClassTableChild(tableName, options) {
    return function (object) {
    };
}
/* export */ function ClosureTable(name, options) {
    return function (object) {
    };
}
/* export */ function EmbeddableTable() {
    return function (object) {
    };
}
/* export */ function SingleTableChild() {
    return function (object) {
    };
}
/* export */ function Table(name, options) {
    return function (object) {
    };
}
/* export */ function TableInheritance(type) {
    return function (object) {
    };
}
// tree
/* export */ function TreeChildren(options) {
    return function (object, propertyName) {
    };
}
/* export */ function TreeLevelColumn() {
    return function (object, propertyName) {
    };
}
/* export */ function TreeParent(options) {
    return function (object, propertyName) {
    };
}
//# sourceMappingURL=decorators-shim.js.map

and if you include it as like a shim in index.html like this:

<script src="node_modules/typeorm/decorators-shim.js"></script>

will it work 100% and resolve all problems?

from typeorm.

bijeebuss avatar bijeebuss commented on May 16, 2024

This is what I have been doing with typeorm-fake.ts for the time being.
I have a common lib project where I put the models and other common functionality.
In my models I have

import {Table, Column, PrimaryColumn, OneToOne} from "./typeorm";
...

then in ./typeorm.ts I have

export * from "typeorm"

and I have a file called buildClient.sh which does this

echo 'export * from "./typeorm-fake"' > src/entities/typeorm.ts;
tsc;
echo 'export * from "typeorm"' > src/entities/typeorm.ts;

Then in the package.json for my client application I have

...
"dependencies": {
    "project-lib": "file:///Users/Michael/Git/project-lib",
   ...
  },
...

so after running buildClient.sh in the lib project I do 'npm install' in the client project which imports the shim file. Then back in the lib project I run tsc to put it back to the actual typeorm. This way I can run 'npm link ../project-lib' in my server project.

I think the build tools for react-native and nativescript traverse all the require() statements in the compiled js files and if fs or any node-specific modules are hit it errors out because it cant find the modules. So for me importing a script shim wont work because there is no place i can put a script tag.

Edit: Also I found out if you do this you need to export connection from the typeorm you imported in your lib project, otherwise your server project will have a different instance of connection and it wont be able to find the metadata for your models. So essentially my server project has no dependency on typeorm, only project-lib which has a dependency on typeorm

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

this feature released in 0.0.7-alpha.22. Look here to understand how it works. I'll need to add some documentation for this feature.

from typeorm.

xavdid avatar xavdid commented on May 16, 2024

Hate to bring up an old thread, but i've got a related question.

I'm currently bundling some functionality into my user model (the validatePassword() function, which returns a bool. It would be extra cool if it were possible to import my model into the React code and re-use that function in a form. I realize I could break the function off of the model, but it's convenient to have everything bundled together if possible.

import { User } from '../../entity'

// ... 
const u = new User()
u.validatePassword(this.state.password)

Currently getting a webpack missing module error: Uncaught Error: Cannot find module "fs". Is there a known way to handle this?

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

So, you want to reuse models on the frontend, right? If yes, then did you map typeorm package to the shim in webpack config? If yes, then what gives you this error?

from typeorm.

xavdid avatar xavdid commented on May 16, 2024

Ah sorry, I didn't read the comments closely on the webpack thing and had it pointed incorrectly. Even when fixed, it still complains about fs from mongo (which is included in one of my classes so that I can use new ObjectId(id) for queries.

In any case, I don't it's a typeorm issue. thanks for the 👀, sorry for false alarm!

from typeorm.

pleerock avatar pleerock commented on May 16, 2024

@RDeluxe I do not see how this is related to typeorm

from typeorm.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.