2
votes

I have 2 entities that have a OneToOne relation (User and CodUser) and where User has the JoinColumn. When TypeOrm syncs this pattern to the database it create the CodUser columns within the user, so it embeds the CodUser AND creates a separate table for the CodUser entity.

What I want is that the 2 entities are separate and the columns in the CodUser only appear in the CodUser table in my (Postgres) database. I believe this is the exact pattern used by TypeOrm to demonstrate OneToOne relations but there seems to be something off.

user.entity.ts

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;

@Column({ unique: true })
email: string;

@Column({ nullable: true })
avatar: string;

@Column()
password: string;

@Column({
    type: "text",
    array: true,
    nullable: false,
    default: `{${Role.Player}}`
})
roles: Role[];

@OneToOne((type) => CodUser, {
    cascade: true
})
@JoinColumn()
codUser: CodUser;

@Column({ default: 0 })
invalidLoginAttempts: number;

@Column({ nullable: true })
activationCode: string;

@Column({ nullable: false, default: false })
active: boolean;

@Column({ nullable: true })
lockedUntil: Date;

@Column({ nullable: true })
lastLoginAttemptAt: Date;

@OneToMany((type) => ChallangeUser, (challangeUser) => challangeUser.user)
challanges: ChallangeUser[];

@CreateDateColumn({ type: "timestamp" })
createdAt: Date;

@UpdateDateColumn({ type: "timestamp" })
updatedAt: Date;

constructor(email: string, username: string, platform: Platform, password: string) {
    this.email = email;
    this.codUser = new CodUser(username, platform);
    this.password = password;
}
}

cod-user.entity.ts

@Entity()
export class CodUser {
@PrimaryGeneratedColumn()
id: string;

@Column({ unique: true })
username: string;

@Column({ nullable: false })
platform: Platform;

@Column({ type: "jsonb", nullable: true })
recentWarzoneMatches: object[];

@Column({ nullable: true })
recentWarzoneMatchesSyncedAt: Date;

constructor(username: string, platform: Platform) {
    this.username = username;
    this.platform = platform;
}
}

Result:

Database explorer

Transaction while syncing:

query: START TRANSACTION
query: SELECT * FROM current_schema()
query: SELECT * FROM "information_schema"."tables" WHERE ("table_schema" = 'public' AND "table_name" = 'challange') OR ("table_schema" = 'public' AND "table_name" = 'challange_user') OR ("table_schema" = 'public' AND "table_name" = 'cod_user') OR ("table_schema" = 'public' AND "table_name" = 'user') OR ("table_schema" = 'public' AND "table_name" = 'user') OR ("table_schema" = 'public' AND "table_name" = 'challange') OR ("table_schema" = 'public' AND "table_name" = 'challange_user')
query: SELECT *, ('"' || "udt_schema" || '"."' || "udt_name" || '"')::"regtype" AS "regtype" FROM "information_schema"."columns" WHERE ("table_schema" = 'public' AND "table_name" = 'challange') OR ("table_schema" = 'public' AND "table_name" = 'challange_user') OR ("table_schema" = 'public' AND "table_name" = 
'cod_user') OR ("table_schema" = 'public' AND "table_name" = 'user') OR ("table_schema" = 'public' AND "table_name" = 'user') OR ("table_schema" = 'public' AND "table_name" = 'challange') OR ("table_schema" = 'public' AND "table_name" = 'challange_user')
query: SELECT "ns"."nspname" AS "table_schema", "t"."relname" AS "table_name", "cnst"."conname" AS "constraint_name", pg_get_constraintdef("cnst"."oid") AS "expression", CASE "cnst"."contype" WHEN 'p' THEN 'PRIMARY' WHEN 'u' THEN 'UNIQUE' WHEN 'c' THEN 'CHECK' WHEN 'x' THEN 'EXCLUDE' END AS "constraint_type", "a"."attname" AS "column_name" FROM "pg_constraint" "cnst" INNER JOIN "pg_class" "t" ON "t"."oid" = "cnst"."conrelid" INNER JOIN "pg_namespace" "ns" ON "ns"."oid" = "cnst"."connamespace" LEFT JOIN "pg_attribute" "a" ON "a"."attrelid" = "cnst"."conrelid" AND "a"."attnum" = ANY ("cnst"."conkey") WHERE "t"."relkind" = 'r' AND (("ns"."nspname" = 'public' AND "t"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange_user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'cod_user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange_user'))
query: SELECT "ns"."nspname" AS "table_schema", "t"."relname" AS "table_name", "i"."relname" AS "constraint_name", "a"."attname" AS "column_name", CASE "ix"."indisunique" WHEN 't' THEN 'TRUE' ELSE'FALSE' END AS "is_unique", pg_get_expr("ix"."indpred", "ix"."indrelid") AS "condition", "types"."typname" AS "type_name" FROM "pg_class" "t" INNER JOIN "pg_index" "ix" ON "ix"."indrelid" = "t"."oid" INNER JOIN "pg_attribute" "a" ON "a"."attrelid" = "t"."oid"  AND "a"."attnum" = ANY ("ix"."indkey") INNER JOIN "pg_namespace" "ns" ON "ns"."oid" = "t"."relnamespace" INNER JOIN "pg_class" "i" ON "i"."oid" = "ix"."indexrelid" INNER JOIN "pg_type" "types" ON "types"."oid" = "a"."atttypid" LEFT JOIN "pg_constraint" "cnst" ON "cnst"."conname" = "i"."relname" WHERE "t"."relkind" = 'r' AND "cnst"."contype" IS NULL AND (("ns"."nspname" = 'public' AND "t"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange_user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'cod_user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "t"."relname" = 'challange_user'))
query: SELECT "con"."conname" AS "constraint_name", "con"."nspname" AS "table_schema", "con"."relname" AS "table_name", "att2"."attname" AS "column_name", "ns"."nspname" AS "referenced_table_schema", "cl"."relname" AS "referenced_table_name", "att"."attname" AS "referenced_column_name", "con"."confdeltype" AS "on_delete", "con"."confupdtype" AS "on_update", "con"."condeferrable" AS "deferrable", "con"."condeferred" AS "deferred" FROM ( SELECT UNNEST ("con1"."conkey") AS "parent", UNNEST ("con1"."confkey") AS "child", "con1"."confrelid", "con1"."conrelid", "con1"."conname", "con1"."contype", "ns"."nspname", "cl"."relname", "con1"."condeferrable", CASE WHEN "con1"."condeferred" THEN 'INITIALLY DEFERRED' ELSE 'INITIALLY IMMEDIATE' END as condeferred, CASE "con1"."confdeltype" WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END as "confdeltype", CASE "con1"."confupdtype" WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END as "confupdtype" FROM "pg_class" "cl" INNER JOIN "pg_namespace" "ns" ON "cl"."relnamespace" = "ns"."oid" INNER JOIN "pg_constraint" "con1" ON "con1"."conrelid" = "cl"."oid" WHERE "con1"."contype" = 'f' AND (("ns"."nspname" = 'public' AND "cl"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'challange_user') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'cod_user') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'user') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'challange') OR ("ns"."nspname" = 'public' AND "cl"."relname" = 'challange_user')) ) "con" INNER JOIN "pg_attribute" "att" ON "att"."attrelid" = "con"."confrelid" AND "att"."attnum" = "con"."child" INNER JOIN "pg_class" "cl" ON "cl"."oid" = "con"."confrelid" INNER JOIN "pg_namespace" "ns" ON "cl"."relnamespace" = "ns"."oid" INNER JOIN "pg_attribute" "att2" ON "att2"."attrelid" = "con"."conrelid" AND "att2"."attnum" = "con"."parent"
query: SELECT * FROM "information_schema"."tables" WHERE "table_schema" = current_schema() AND "table_name" = 'typeorm_metadata'
query: ALTER TABLE "user" DROP CONSTRAINT "FK_c8521799e9a87cab5983c57ba1c"
query: ALTER TABLE "challange_user" DROP CONSTRAINT "FK_0c9f41f81c2f9cadd1154c90499"
query: ALTER TABLE "challange" DROP COLUMN "userLimit"
query: ALTER TABLE "user" DROP CONSTRAINT "UQ_c8521799e9a87cab5983c57ba1c"
query: ALTER TABLE "user" DROP COLUMN "custom_cod_user"
query: ALTER TABLE "user" DROP CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb"
query: ALTER TABLE "user" DROP COLUMN "username"
query: ALTER TABLE "user" DROP COLUMN "platform"
query: ALTER TABLE "user" DROP COLUMN "recentWarzoneMatches"
query: ALTER TABLE "user" DROP COLUMN "recentWarzoneMatchesSyncedAt"
query: ALTER TABLE "user" DROP COLUMN "roles"
query: ALTER TABLE "challange" DROP COLUMN "slots"
query: ALTER TABLE "challange_user" DROP COLUMN "isConfirmed"
query: ALTER TABLE "challange_user" DROP COLUMN "challangeId"
query: ALTER TABLE "challange" ADD "slots" integer NOT NULL DEFAULT -1
query: ALTER TABLE "challange_user" ADD "isConfirmed" boolean NOT NULL DEFAULT false
query: ALTER TABLE "challange_user" ADD "challangeId" uuid
query: ALTER TABLE "user" ADD "roles" text array NOT NULL DEFAULT '{player}'::text[]
query: ALTER TABLE "user" ADD "codUserId" integer
query: ALTER TABLE "user" ADD CONSTRAINT "UQ_4ee803ddc575ea07a96a0aa5f40" UNIQUE ("codUserId")
query: ALTER TABLE "user" ADD "username" character varying NOT NULL
query: ALTER TABLE "user" ADD CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username")
query: ALTER TABLE "user" ADD "platform" character varying NOT NULL
query: ALTER TABLE "user" ADD "recentWarzoneMatches" jsonb
query: ALTER TABLE "user" ADD "recentWarzoneMatchesSyncedAt" TIMESTAMP
query: ALTER TABLE "challange" ADD "userLimit" integer NOT NULL DEFAULT -1
query: ALTER TABLE "challange_user" ADD CONSTRAINT "FK_0c9f41f81c2f9cadd1154c90499" FOREIGN KEY ("challangeId") REFERENCES "challange"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
query: ALTER TABLE "user" ADD CONSTRAINT "FK_4ee803ddc575ea07a96a0aa5f40" FOREIGN KEY ("codUserId") REFERENCES "cod_user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
query: COMMIT
1

1 Answers

0
votes

Removing the /dist folder in my NestJS project resolved the issue, seems like it was a NestJS issue after all.