RobinCK / typeorm-fixtures

:pill: Fixtures loader for typeorm πŸ‡ΊπŸ‡¦
https://robinck.github.io/typeorm-fixtures/
MIT License
566 stars 45 forks source link

[Bug] Postgres 'timestamptz' column failing at parsing long date #188

Open lordrip opened 2 years ago

lordrip commented 2 years ago

Your Environment

Software Version(s)
typeorm-fixtures 1.11.0
typeorm 0.2.45
pg 8.7.3
Node 16.14.0
npm/Yarn yarn 3.2.0
Operating System Windows 11

Hi there, first of all, thanks for providing this library to the community, very cool project πŸ™†β€β™‚οΈ .

I'm facing a situation in which when I use a column marked as timestamptz, any kind of date gets transformed into a long date string

Column definition

  @Column({ type: 'timestamptz' })
  syncDateTime: Date;
entity: MyEntity
items:
  sync{1..3}:
    topic: 'a-given-topic'
    id: '{{datatype.uuid}}'
    company: '@company*'
    syncDateTime: '{{datatype.datetime}}'

then it fails because it cannot parse the following date format Mon Nov 16 1992 23:28:29 GMT+0100 (Central European Standard Time)

Stacktrace excerpt

Fail fixture loading: invalid input syntax for type timestamp with time zone: "Mon Nov 16 1992 23:28:29 GMT+0100 (Central European Standard Time)"
QueryFailedError: invalid input syntax for type timestamp with time zone: "Mon Nov 16 1992 23:28:29 GMT+0100 (Central European Standard Time)"
    at QueryFailedError.TypeORMError [as constructor] (src/error/TypeORMError.ts:7:9)
    at new QueryFailedError (src/error/QueryFailedError.ts:9:9)
    at PostgresQueryRunner.<anonymous> (src/driver/postgres/PostgresQueryRunner.ts:263:19)
    at step (node_modules/tslib/tslib.js:143:27)
    at Object.throw (node_modules/tslib/tslib.js:124:57)
    at rejected (node_modules/tslib/tslib.js:115:69)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  query: 'INSERT INTO "sync_entity"("topic", "id", "syncDateTime", "createdAt", "updatedAt", "deletedAt", "companyId") VALUES ($1, $2, $3, DEFAULT, DEFAULT, DEFAULT, $4) RETURNING "id", "createdAt", "updatedAt", "deletedAt"',
  parameters: [
    'inventory',
    'fbbd57dd-9ca2-4513-bbe8-5d060dc7f4c9',
    'Mon Nov 16 1992 23:28:29 GMT+0100 (Central European Standard Time)',
    'b4dc4d0a-ab11-425a-a772-d0d094f49fc8'
  ],
  driverError: error: invalid input syntax for type timestamp with time zone: "Mon Nov 16 1992 23:28:29 GMT+0100 (Central European Standard Time)"
      at Parser.parseErrorMessage (node_modules/pg-protocol/src/parser.ts:369:69)
      at Parser.handlePacket (node_modules/pg-protocol/src/parser.ts:188:21)
      at Parser.parse (node_modules/pg-protocol/src/parser.ts:103:30)
      at Socket.<anonymous> (node_modules/pg-protocol/src/index.ts:7:48)

Curious enough, If I remove it, then it works

  @Column()
  syncDateTime: Date;

Have you face a similar situation in the past?

lordrip commented 2 years ago

I've forgot to mention, if I can help somehow investigating this further, just let me know :)

lordrip commented 2 years ago

As a workaround, I'm using ejs forcing an ISO string

entity: MyEntity
items:
  sync{1..3}:
    topic: 'a-given-topic'
    id: '{{datatype.uuid}}'
    company: '@company*'
    syncDateTime: <%= (new Date()).toISOString() %>
CiotkaCierpienia commented 2 years ago

Hi, I have the same problem, I would love to see just ISO date returned by date.past and date.future, as faker-js returns exactly that, forcing us to use Date().toISOString defeats all purposes of using faker here...

(thanks @lordrip for the workaround)

lordrip commented 1 year ago

Another way to approach this in the meantime could be leveraging Processors.

import { IProcessor } from 'typeorm-fixtures-cli';
//  Importing 'YourEntityEntity' it's optional, it's mostly for typing purposes
import { YourEntity } from './yourentity';
import { faker } from '@faker-js/faker';

export default class EntityProcessor implements IProcessor<YourEntity> {
  async preProcess(name: string, entity: YourEntity): Promise<YourEntity> {

    // Here we can leverage any fakerjs module
    // We could also leverage location.zipCode but for the sake of the example, we send some parameters as well
    const zipCode = faker.string.numeric({ length: 5, allowLeadingZeros: true });

    return { ...entity, zipCode };
  }
}

then in the fixture yaml file

entity: YourEntity
processor: ./EntityProcessor # Load the above processor
items:
  provider{1..10}:
    id: '{{string.uuid}}'
    # zipCode is no longer required here as we're providing it through the processor
    name: '{{company.name}}'
    address: '{{location.streetAddress}}'
    phone: '{{phone.number}}'
    email: '{{internet.email}}'
    representativeName: '{{person.fullName}}'
    representativePhone: '{{phone.number}}'
    representativeEmail: '{{internet.email}}'