tsedio / tsed

:triangular_ruler: Ts.ED is a Node.js and TypeScript framework on top of Express to write your application with TypeScript (or ES6). It provides a lot of decorators and guideline to make your code more readable and less error-prone. ⭐️ Star to support our work!
https://tsed.io/
MIT License
2.85k stars 286 forks source link

[BUG] Connection is not assignable to type Connection #738

Closed chiqui3d closed 4 years ago

chiqui3d commented 4 years ago

Information

I've been a while without using TSED, now I'm back to take a project I have started that worked before and now it doesn't work.

Errors

[2020-01-16T00:29:29.433] [ERROR] [TSED] - src/Service/UsersService.ts:14:5 - error TS2322: Type 'import("G:/www/api-new/node_modules/@t
sed/typeorm/node_modules/typeorm/connection/Connection").Connection' is not assignable to type 'import("G:/www/api-new/node_modules/type
orm/connection/Connection").Connection'.
  Types of property 'options' are incompatible.
    Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions' is no
t assignable to type 'import("G:/www/api-new/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions'.
      Type 'MysqlConnectionOptions' is not assignable to type 'ConnectionOptions'.
        Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConnecti
onOptions' is not assignable to type 'import("G:/www/api-new/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConnectionO
ptions'.
          Types of property 'entities' are incompatible.
            Type '(string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema
").EntitySchema<any>)[]' is not assignable to type '(string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/Entit
ySchema").EntitySchema<any>)[]'.
              Type 'string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchem
a").EntitySchema<any>' is not assignable to type 'string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySc
hema").EntitySchema<any>'.
                Type 'EntitySchema<any>' is not assignable to type 'string | Function | EntitySchema<any>'.
                  Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema").EntitySchema
<any>' is not assignable to type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchema").EntitySchema<any>'.
                    The types of 'options.expression' are incompatible between these types.
                      Type 'string | ((connection: import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Con
nection").Connection) => import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/query-builder/SelectQueryBuilder").Selec
tQueryBuilder<any>)' is not assignable to type 'string | ((connection: import("G:/www/api-new/node_modules/typeorm/connection/Connection
").Connection) => import("G:/www/api-new/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQueryBuilder<any>)'.
                        Type '(connection: Connection) => SelectQueryBuilder<any>' is not assignable to type 'string | ((connection: Connection
) => SelectQueryBuilder<any>)'.
                          Type '(connection: import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Connectio
n").Connection) => import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQuery
Builder<any>' is not assignable to type '(connection: import("G:/www/api-new/node_modules/typeorm/connection/Connection").Connection) =>
 import("G:/www/api-new/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQueryBuilder<any>'.
                            Types of parameters 'connection' and 'connection' are incompatible.
                              Type 'import("G:/www/api-new/node_modules/typeorm/connection/Connection").Connection' is not assignable to
 type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Connection").Connection'.
                                Types of property 'options' are incompatible.
                                  Type 'import("G:/www/api-new/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions' is
 not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/ConnectionOptions").Connectio
nOptions'.
                                    Type 'MysqlConnectionOptions' is not assignable to type 'ConnectionOptions'.
                                      Type 'import("G:/www/api-new/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConne
ctionOptions' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/mysql/MysqlConnec
tionOptions").MysqlConnectionOptions'.
                                        Types of property 'entities' are incompatible.
                                          Type '(string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySch
ema").EntitySchema<any>)[]' is not assignable to type '(string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modul
es/typeorm/entity-schema/EntitySchema").EntitySchema<any>)[]'.
                                            Type 'string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySc
hema").EntitySchema<any>' is not assignable to type 'string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/
typeorm/entity-schema/EntitySchema").EntitySchema<any>'.
                                              Type 'EntitySchema<any>' is not assignable to type 'string | Function | EntitySchema<any>'.
                                                Type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchema").EntitySch
ema<any>' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema")
.EntitySchema<any>'.
                                                  The types of 'options.columns' are incompatible between these types.
                                                    Type '{ [x: string]: import("G:/www/api-new/node_modules/typeorm/entity-schema/Entit
ySchemaColumnOptions").EntitySchemaColumnOptions; }' is not assignable to type '{ [x: string]: import("G:/www/api-new/node_modules/@tsed
/typeorm/node_modules/typeorm/entity-schema/EntitySchemaColumnOptions").EntitySchemaColumnOptions; }'.
                                                      Index signatures are incompatible.
                                                        Type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchemaColu
mnOptions").EntitySchemaColumnOptions' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm
/entity-schema/EntitySchemaColumnOptions").EntitySchemaColumnOptions'.
                                                          Types of property 'type' are incompatible.
                                                            Type 'import("G:/www/api-new/node_modules/typeorm/driver/types/ColumnTypes")
.ColumnType' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/types/ColumnTypes"
).ColumnType'.
                                                              Type '"smalldecimal"' is not assignable to type 'ColumnType'.

14     this.connection = this.typeORMService.get()
       ~~~~~~~~~~~~~~~

[nodemon] app crashed - waiting for file changes before starting...
[nodemon] restarting due to changes...
[nodemon] starting `ts-node src/index.ts`
[2020-01-16T00:30:18.637] [ERROR] [TSED] - src/Service/UsersService.ts:14:5 - error TS2322: Type 'import("G:/www/api-new/node_modules/@t
sed/typeorm/node_modules/typeorm/connection/Connection").Connection' is not assignable to type 'import("G:/www/api-new/node_modules/type
orm/connection/Connection").Connection'.
  Types of property 'options' are incompatible.
    Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions' is no
t assignable to type 'import("G:/www/api-new/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions'.
      Type 'MysqlConnectionOptions' is not assignable to type 'ConnectionOptions'.
        Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConnecti
onOptions' is not assignable to type 'import("G:/www/api-new/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConnectionO
ptions'.
          Types of property 'entities' are incompatible.
            Type '(string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema
").EntitySchema<any>)[]' is not assignable to type '(string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/Entit
ySchema").EntitySchema<any>)[]'.
              Type 'string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchem
a").EntitySchema<any>' is not assignable to type 'string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySc
hema").EntitySchema<any>'.
                Type 'EntitySchema<any>' is not assignable to type 'string | Function | EntitySchema<any>'.
                  Type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema").EntitySchema
<any>' is not assignable to type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchema").EntitySchema<any>'.
                    The types of 'options.expression' are incompatible between these types.
                      Type 'string | ((connection: import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Con
nection").Connection) => import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/query-builder/SelectQueryBuilder").Selec
tQueryBuilder<any>)' is not assignable to type 'string | ((connection: import("G:/www/api-new/node_modules/typeorm/connection/Connection
").Connection) => import("G:/www/api-new/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQueryBuilder<any>)'.
                        Type '(connection: Connection) => SelectQueryBuilder<any>' is not assignable to type 'string | ((connection: Connection
) => SelectQueryBuilder<any>)'.
                          Type '(connection: import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Connectio
n").Connection) => import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQuery
Builder<any>' is not assignable to type '(connection: import("G:/www/api-new/node_modules/typeorm/connection/Connection").Connection) =>
 import("G:/www/api-new/node_modules/typeorm/query-builder/SelectQueryBuilder").SelectQueryBuilder<any>'.
                            Types of parameters 'connection' and 'connection' are incompatible.
                              Type 'import("G:/www/api-new/node_modules/typeorm/connection/Connection").Connection' is not assignable to
 type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/Connection").Connection'.
                                Types of property 'options' are incompatible.
                                  Type 'import("G:/www/api-new/node_modules/typeorm/connection/ConnectionOptions").ConnectionOptions' is
 not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/connection/ConnectionOptions").Connectio
nOptions'.
                                    Type 'MysqlConnectionOptions' is not assignable to type 'ConnectionOptions'.
                                      Type 'import("G:/www/api-new/node_modules/typeorm/driver/mysql/MysqlConnectionOptions").MysqlConne
ctionOptions' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/mysql/MysqlConnec
tionOptions").MysqlConnectionOptions'.
                                        Types of property 'entities' are incompatible.
                                          Type '(string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySch
ema").EntitySchema<any>)[]' is not assignable to type '(string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modul
es/typeorm/entity-schema/EntitySchema").EntitySchema<any>)[]'.
                                            Type 'string | Function | import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySc
hema").EntitySchema<any>' is not assignable to type 'string | Function | import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/
typeorm/entity-schema/EntitySchema").EntitySchema<any>'.
                                              Type 'EntitySchema<any>' is not assignable to type 'string | Function | EntitySchema<any>'.
                                                Type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchema").EntitySch
ema<any>' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/entity-schema/EntitySchema")
.EntitySchema<any>'.
                                                  The types of 'options.columns' are incompatible between these types.
                                                    Type '{ [x: string]: import("G:/www/api-new/node_modules/typeorm/entity-schema/Entit
ySchemaColumnOptions").EntitySchemaColumnOptions; }' is not assignable to type '{ [x: string]: import("G:/www/api-new/node_modules/@tsed
/typeorm/node_modules/typeorm/entity-schema/EntitySchemaColumnOptions").EntitySchemaColumnOptions; }'.
                                                      Index signatures are incompatible.
                                                        Type 'import("G:/www/api-new/node_modules/typeorm/entity-schema/EntitySchemaColu
mnOptions").EntitySchemaColumnOptions' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm
/entity-schema/EntitySchemaColumnOptions").EntitySchemaColumnOptions'.
                                                          Types of property 'type' are incompatible.
                                                            Type 'import("G:/www/api-new/node_modules/typeorm/driver/types/ColumnTypes")
.ColumnType' is not assignable to type 'import("G:/www/api-new/node_modules/@tsed/typeorm/node_modules/typeorm/driver/types/ColumnTypes"
).ColumnType'.
                                                              Type '"smalldecimal"' is not assignable to type 'ColumnType'.

14     this.connection = this.typeORMService.get()
       ~~~~~~~~~~~~~~~

It gives me a lot of errors regarding types, plus it can't connect to the database either, I think it's because of this.

The exact error:

this.connection = this.typeORMService.get()

Example

This code is taken from the same example repository with TypeORM https://github.com/TypedProject/tsed-example-typeorm/

import { Service } from '@tsed/common'
import { TypeORMService } from '@tsed/typeorm'
import { Connection } from 'typeorm'
import { User } from '../entity/User'

@Service()
export class UsersService {
  private connection: Connection

  constructor (private typeORMService: TypeORMService) {
  }

  $afterRoutesInit () {
    -----> error this.connection = this.typeORMService.get()
  }

  async create (user: User): Promise<User> {
    await this.connection.manager.save(user)
    console.log('Saved a new user with id: ' + user.id)
    return user
  }

  async find (): Promise<User[]> {
    const users = await this.connection.manager.find(User)
    console.log('Loaded users: ', users)
    return users
  }
  async findByID (id): Promise<User> {
    return this.connection.manager.findOne(id)
  }

}
chiqui3d commented 4 years ago

In addition to the above marked supposedly when adding the typeormoptions to @ServerSettings it should create a connection as shown in the TypeORM documentation https://typeorm.io/#example-with-express/adding-express-to-the-application, as this does not create it, I have had to manually add the function, also add ormconfig.yml to make it work.

And finally based on your example of repository injection into the Controller/Service/Provider http://tsed.io/tutorials/typeorm.html#entityrepository it doesn't work either.

I have had to do it without injection in a Controllerand with the options offered by TypeORM itself.

the behaviour expected:

https://github.com/typeorm/typeorm-typedi-extensions#injectrepository

Romakita commented 4 years ago

Hello @chiqui3d The next release will solve issue on type checking (I guess). I also updated the typeorm example. You'll find a working example with a docker-compose file. The database is correctly connected to server application and you can use swagger to play with the API.

Can you checkout the new example and compare with your code, please :).

See you, Romain

chiqui3d commented 4 years ago

Okay, perfect.

In my example I had to remove the type in the connection property, because if I didn't get the same error as before, I guess because in my example I use Typescript 3.7.

Then I need to be able to directly inject a custom EntityRepository into the Controller, without having to create a Service/Connection in between, very similar to how https://github.com/typeorm/typeorm-typedi-extensions#injectrepository does, since I followed your example http://tsed.io/tutorials/typeorm.html#entityrepository and it didn't work for me in the controller. Maybe I need something else? But the ideal is to be able to do it directly.

Romakita commented 4 years ago

It should work for me. Controller and Service are build by injector with the same mechanism.

So this code should work:

import {Inject, Injectable} from "@tsed/di";
import {UserRepository} from "./repository/UserRepository";

@Controller("/")
export class MyController {
  constructor(userRepository: UserRepository) {

  }
}
chiqui3d commented 4 years ago

For me not:

I'll give you the example:

import {Repository} from 'typeorm'
import { Order } from '../Entity/Orderp'
import {EntityRepository} from '@tsed/typeorm'

@EntityRepository(Order)
export class OrderRepository extends Repository<Order> {

  findByID (id: number): Promise<Order> {
    return this.findOne(id)
  }

}
import {Inject, Injectable} from "@tsed/di";

import { Controller, Get, PathParams } from '@tsed/common'
import { Order } from '../Entity/Orderp'
import { NotFound } from 'ts-httpexceptions'
import { OrderRepository } from '../Repository/OrderRepository'

@Controller('/order')
export class OrderController {
  constructor (private orderRepository: OrderRepository) {
  }

  @Get('/:id')
  async get (@PathParams('id') id: number): Promise<Order | NotFound> {
    const order = this.orderRepository.findByID(id)
    if (!order) {
      throw new NotFound('Not Order Found')
    }
    return order
  }

}

Error: "Cannot read property 'findOne' of undefined",

Romakita commented 4 years ago

And with this example:

import {Inject, Injectable} from "@tsed/di";

import { Controller, Get, PathParams } from '@tsed/common'
import { Order } from '../Entity/Orderp'
import { NotFound } from 'ts-httpexceptions'
import { OrderRepository } from '../Repository/OrderRepository'

@Controller('/order')
export class OrderController {
  @Inject() // use Inject decorator
  private orderRepository: OrderRepository

  @Get('/:id')
  async get (@PathParams('id') id: number): Promise<Order | NotFound> {
    const order = this.orderRepository.findByID(id)
    if (!order) {
      throw new NotFound('Not Order Found')
    }
    return order
  }
}
chiqui3d commented 4 years ago

Hey @Romakita, same error.

Romakita commented 4 years ago

Ok I'll check on my side :)

Meanwhile, can you try this pls:

import {Inject, Injectable} from "@tsed/di";

import { Controller, Get, PathParams } from '@tsed/common'
import { Order } from '../Entity/Orderp'
import { NotFound } from 'ts-httpexceptions'
import { OrderRepository } from '../Repository/OrderRepository'

console.log('===> OrderRepository', OrderRepository) // if it's undefined, you have a circular ref

@Controller('/order')
export class OrderController {
  @Inject() // use Inject decorator
  private orderRepository: OrderRepository

  @Get('/:id')
  async get (@PathParams('id') id: number): Promise<Order | NotFound> {
    const order = this.orderRepository.findByID(id)
    if (!order) {
      throw new NotFound('Not Order Found')
    }
    return order
  }
}

See you

chiqui3d commented 4 years ago

Result ===> OrderRepository [Function: OrderRepository]

Romakita commented 4 years ago

ok I added example with a Repository. The example will be release soon.

Have you used the EntityRepository decorator from Ts.ED to declare your repository ?

import {EntityRepository} from "@tsed/typeorm"; /// important
@EntityRepository(User)
export class UserRepository extends Repository<User> {

}
chiqui3d commented 4 years ago
import {Repository} from 'typeorm'
import { Order } from '../Entity/Orderp'
import {EntityRepository} from '@tsed/typeorm'

@EntityRepository(Order)
export class OrderRepository extends Repository<Order> {

  findByID (id: number): Promise<Order> {
    return this.findOne(id)
  }

}
Romakita commented 4 years ago

ok

Romakita commented 4 years ago

I added also:

@ServerSettings({
  componentsScan: [
    `${rootDir}/repositories/*{.ts,.js}`
  ],
})

Not sure if it change something.

Romakita commented 4 years ago

The version 5.38.2 is released. It should fix typescript et dependencies issues.

chiqui3d commented 4 years ago

I tried that too, I put you the @ServerSettings just in case.

import { GlobalAcceptMimesMiddleware, ServerLoader, ServerSettings } from '@tsed/common'
import '@tsed/swagger'
import '@tsed/typeorm'
import { join } from 'path'

import * as bodyParser from "body-parser";
import * as compress from "compression";
import * as methodOverride from "method-override";
import * as session from "express-session";

const srcDir = __dirname
const rootDir = join(__dirname, '../')

@ServerSettings({
  srcDir,
  viewsDir: `${rootDir}views`,
  statics: {
    '/': `${rootDir}public`
  },
  uploadDir: `${rootDir}public/uploads`,
  httpPort: '127.0.0.1:3000',
  httpsPort: '127.0.0.1:8000',
  acceptMimes: ['application/json'],
  debug: true,
  validationModelStrict: true,
  mount: {
    '/': `${srcDir}/Controller/**/*.ts`
  },
  componentsScan: [
    `${srcDir}/Service/**/*.ts`,
    `${srcDir}/Repository/**/*.ts`
  ],
  logger: {
    requestFields: ['method', 'url']
  },
  typeorm: [
    {
      name: 'default',
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '******',
      database: 'api_wp',
      synchronize: true,
      logging: true,
      entities: [
        `${srcDir}/Entity/*{.ts,.js}`
      ],
      migrations: [
        `${srcDir}/Migration/*{.ts,.js}`
      ],
      subscribers: [
        `${srcDir}/Subscriber/*{.ts,.js}`
      ]
    }
  ],
  swagger: {
    path: '/api-docs'
  }
})
export class Server extends ServerLoader {

  $beforeInit () {
    this.set('views', this.settings.get('viewsDir'))
    this.set('view engine', 'twig')
  }
  $beforeRoutesInit (): void | Promise<any> {
    this
      .use(GlobalAcceptMimesMiddleware)
      .use(compress({}))
      .use(methodOverride())
      .use(bodyParser.json())
      .use(bodyParser.urlencoded({
        extended: true
      }))

    this.set('trust proxy', 1)
    this.use(session({
      secret: 'keyboard cat',
      resave: false,
      saveUninitialized: true,
      cookie: {
        secure: false,  // `true` require HTTPS. Set `false` if you reach the server with HTTP
        path: '/',
        httpOnly: true,
        maxAge: null
      }
    }))

    return null
  }
}
Romakita commented 4 years ago

Can you try a npm list typeorm. You must have this:

├─┬ @tsed/typeorm@5.38.2
│ └── typeorm@0.2.22  deduped // dedup is important
└── typeorm@0.2.22 

If not run npm dedup :)

Romakita commented 4 years ago

New example version is available :) https://github.com/TypedProject/tsed-example-typeorm/tree/v5.38.2

chiqui3d commented 4 years ago

Yeah!! :), Now it works perfectly. Thank you

chiqui3d commented 4 years ago

Hello @Romakita

I am now injecting my custom UserRepositoryinto a Service that implements BeforeRoutesInit, AfterRoutesInit for Local Passport

Before I confirm that the componentScanoption I have assigned the correct folders, in this case Authdirectory.

I haven't finished the code yet, I'm testing it, I also tried to use getCustomRepositoryof typeORMand it works fine with it, but injecting the repository with DI doesn't work.

LocalAuth.ts

import {
    AfterRoutesInit,
    BeforeRoutesInit,
    Configuration,
    ExpressApplication,
    Inject,
    Service
} from '@tsed/common'
import * as Passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import { UserRepository } from '../Repository/UserRepository';

console.log('UserRepository => ',UserRepository) // UserRepository =>  [Function: UserRepository]

@Service()
export class LocalAuth implements BeforeRoutesInit, AfterRoutesInit {
    // I've also tried with @Inject(UserRepository) 
    constructor (private userRepository: UserRepository,
                 @Configuration() private configuration: Configuration,
                 @Inject(ExpressApplication) private expressApplication: ExpressApplication) {
    }

    $beforeRoutesInit () {
        const options: any = this.configuration.get('passport') || {} as any;
        const { userProperty, pauseStream } = options;
        this.expressApplication.use(Passport.initialize({ userProperty }));
        this.expressApplication.use(Passport.session({ pauseStream }));
    }

    $afterRoutesInit () {
        Passport.use('local', new LocalStrategy(this.localStrategy));
    }

    localStrategy (username, password, done) {
        const user = this.userRepository.findOne({ 'username': username });
        if (!user) {
            return done(null, false, { message: 'An incorrect username or password.' });
        }
        return done(null, user);
    }
}

The error is the same as above:

"Cannot read property 'findOne' of undefined",

chiqui3d commented 4 years ago

Hello @Romakita

Is this fixed?

Romakita commented 4 years ago

Hello :)

I try to reproduce the problem. And give you a complete example ;)

See you

Romakita commented 4 years ago

Fixed with v5.39.0 :)

chiqui3d commented 4 years ago

The example you gave me in the other issue I haven't tested it, now what I've done is update the version to 5.39.1 and test it in my current code:

import {
  AfterRoutesInit,
  BeforeRoutesInit,
  Configuration,
  ExpressApplication,
  Inject,
  Service
} from '@tsed/common'
import * as Passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import { UserRepository } from '../Repository/UserRepository';
import { getCustomRepository } from 'typeorm'
import { User } from '../Entity/User'
import { plainToClass } from 'class-transformer';

@Service()
export class LocalAuth implements BeforeRoutesInit, AfterRoutesInit {

  constructor (private userRepository: UserRepository,
                @Configuration() private configuration: Configuration,
                @Inject(ExpressApplication) private expressApplication: ExpressApplication) {
  }

  $beforeRoutesInit () {
    this.expressApplication.use(Passport.initialize());
    this.expressApplication.use(Passport.session());
  }

  $afterRoutesInit () {
    Passport.use('local', new LocalStrategy({ passReqToCallback: true }, this.localStrategy));
    Passport.serializeUser((user, done) => LocalAuth.serialize(user, done));
    Passport.deserializeUser((id, done) => LocalAuth.deserialize(id, done));
  }

  async localStrategy (req, username: string, password: string, done: Function) {
    const bcrypt = require('bcrypt');
    const user = await getCustomRepository(UserRepository).findOne({ 'username': username });
    if (!user) {
      return done(null, false, { message: 'Username incorrect' });
    }
    const matchPassword = await bcrypt.compare(password, user.password);
    if (matchPassword) {
      return done(null, user);
    }
    return done(null, false, { message: 'Password incorrect.' });
  }

  static async serialize (user, done) {
    done(null, user.id);
  }
  static async deserialize (id, done) {
    const user: User = await getCustomRepository(UserRepository).findOne(id);
    const userDto: User = plainToClass(User, user);
    // const userConverter = converter.deserialize(user, UserDTO);
    done(null, userDto);
  }
}

This code currently works perfectly, but without using the repository injection dependency, I've tried it and it doesn't work. So do I forget to inject my custom repository through DI? or is there something that doesn't work when you implement the BeforeRoutesInit, AfterRoutesInit in the service.

I also noticed that the custom repository in your example has put import {EntityRepository, Repository} from "typeorm"; should we finally use your library or the typeorm library, or is it the same thing?

I've also seen that you've uploaded new documentation to the repository, but I don't see it updated on the tsed.io page either, I don't know if you've forgotten or need to finish something.

Romakita commented 4 years ago

Hello @chiqui3d Now you can use EntityRepository directly from repository. I introduce a new feature, that allow to configure external DI with Ts.ED. The @tsed/typeorm package configure your app to share symbols between TypeORM DI and Ts.ED DI.

I forgot to update typeorm documentation page.

This code currently works perfectly, but without using the repository injection dependency, I've tried it and it doesn't work.

I don't know why, because the tsed-typeorm example work perfectly with the injection. The only way to understand why it doesn't is to have an access to your repository so that I can test your application.

BeforeRoutesInit, AfterRoutesInit are just a lifecycle hook to intercept event. Normally you must have the repository instance on the constructor.

See you Romain

chiqui3d commented 4 years ago

Sorry I just tried it again and it works, don't tell me how, but I'm sure it would be something caching or I don't know, lol.

Thank you!

Romakita commented 4 years ago

Ha ok Good news. (probably you compile your tsfile before run your node process? do you use tsnode ?)

chiqui3d commented 4 years ago

Yes I use ts-node, exactly:

"start:dev": "nodemon --watch \"src/**/*.ts\" --ignore \"node_modules/**/*\" --exec ts-node src/index.ts",

Romakita commented 4 years ago

Ok strange ^^