fix(issuer/user): fix TypeORM databaseName error in coupon join + wallet frozen column name
- Replace leftJoinAndMapOne(Issuer entity) with two-step query to avoid TypeORM
metadata lookup error ('Cannot read databaseName of undefined')
- Extract unique issuer IDs from coupon results, then batch-fetch issuers and attach
- Fix wallet entity: map frozenBalance to 'frozen' column (not 'frozen_balance')
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fa512dd2eb
commit
6f70d7a2c2
|
|
@ -1,6 +1,6 @@
|
||||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository, DataSource } from 'typeorm';
|
import { Repository, DataSource, In } from 'typeorm';
|
||||||
import { Coupon, CouponStatus } from '../../domain/entities/coupon.entity';
|
import { Coupon, CouponStatus } from '../../domain/entities/coupon.entity';
|
||||||
import { Issuer } from '../../domain/entities/issuer.entity';
|
import { Issuer } from '../../domain/entities/issuer.entity';
|
||||||
import {
|
import {
|
||||||
|
|
@ -61,8 +61,6 @@ export class CouponRepository implements ICouponRepository {
|
||||||
const { category, status, search, issuerId, page, limit } = filters;
|
const { category, status, search, issuerId, page, limit } = filters;
|
||||||
const qb = this.repo.createQueryBuilder('c');
|
const qb = this.repo.createQueryBuilder('c');
|
||||||
|
|
||||||
qb.leftJoinAndMapOne('c.issuer', Issuer, 'i', 'i.id = c.issuer_id');
|
|
||||||
|
|
||||||
if (status) qb.andWhere('c.status = :status', { status });
|
if (status) qb.andWhere('c.status = :status', { status });
|
||||||
if (issuerId) qb.andWhere('c.issuer_id = :issuerId', { issuerId });
|
if (issuerId) qb.andWhere('c.issuer_id = :issuerId', { issuerId });
|
||||||
if (category) qb.andWhere('c.category = :category', { category });
|
if (category) qb.andWhere('c.category = :category', { category });
|
||||||
|
|
@ -76,23 +74,33 @@ export class CouponRepository implements ICouponRepository {
|
||||||
.skip((page - 1) * limit)
|
.skip((page - 1) * limit)
|
||||||
.take(limit);
|
.take(limit);
|
||||||
|
|
||||||
return qb.getManyAndCount();
|
const [coupons, total] = await qb.getManyAndCount();
|
||||||
|
await this._attachIssuers(coupons);
|
||||||
|
return [coupons, total];
|
||||||
}
|
}
|
||||||
|
|
||||||
async findByOwnerWithIssuerJoin(userId: string, filters: CouponListFilters): Promise<[Coupon[], number]> {
|
async findByOwnerWithIssuerJoin(userId: string, filters: CouponListFilters): Promise<[Coupon[], number]> {
|
||||||
const { status, page, limit } = filters;
|
const { status, page, limit } = filters;
|
||||||
const qb = this.repo.createQueryBuilder('c');
|
const qb = this.repo.createQueryBuilder('c');
|
||||||
|
|
||||||
qb.leftJoinAndMapOne('c.issuer', Issuer, 'i', 'i.id = c.issuer_id');
|
|
||||||
qb.andWhere('c.owner_user_id = :userId', { userId });
|
qb.andWhere('c.owner_user_id = :userId', { userId });
|
||||||
|
|
||||||
if (status) qb.andWhere('c.status = :status', { status });
|
if (status) qb.andWhere('c.status = :status', { status });
|
||||||
|
|
||||||
qb.orderBy('c.created_at', 'DESC')
|
qb.orderBy('c.created_at', 'DESC')
|
||||||
.skip((page - 1) * limit)
|
.skip((page - 1) * limit)
|
||||||
.take(limit);
|
.take(limit);
|
||||||
|
|
||||||
return qb.getManyAndCount();
|
const [coupons, total] = await qb.getManyAndCount();
|
||||||
|
await this._attachIssuers(coupons);
|
||||||
|
return [coupons, total];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _attachIssuers(coupons: Coupon[]): Promise<void> {
|
||||||
|
if (coupons.length === 0) return;
|
||||||
|
const issuerIds = [...new Set(coupons.map((c) => c.issuerId))];
|
||||||
|
const issuers = await this.dataSource.getRepository(Issuer).findBy({ id: In(issuerIds) });
|
||||||
|
const issuerMap = new Map(issuers.map((i) => [i.id, i]));
|
||||||
|
coupons.forEach((c) => { c.issuer = issuerMap.get(c.issuerId); });
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOwnerSummary(userId: string): Promise<OwnerSummary> {
|
async getOwnerSummary(userId: string): Promise<OwnerSummary> {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export class Wallet {
|
||||||
@PrimaryGeneratedColumn('uuid') id: string;
|
@PrimaryGeneratedColumn('uuid') id: string;
|
||||||
@Column({ name: 'user_id', type: 'uuid', unique: true }) userId: string;
|
@Column({ name: 'user_id', type: 'uuid', unique: true }) userId: string;
|
||||||
@Column({ type: 'numeric', precision: 20, scale: 8, default: '0' }) balance: string;
|
@Column({ type: 'numeric', precision: 20, scale: 8, default: '0' }) balance: string;
|
||||||
@Column({ name: 'frozen_balance', type: 'numeric', precision: 20, scale: 8, default: '0' }) frozenBalance: string;
|
@Column({ name: 'frozen', type: 'numeric', precision: 20, scale: 8, default: '0' }) frozenBalance: string;
|
||||||
@Column({ type: 'varchar', length: 10, default: 'USD' }) currency: string;
|
@Column({ type: 'varchar', length: 10, default: 'USD' }) currency: string;
|
||||||
@Column({ type: 'varchar', length: 20, default: 'active' }) status: string;
|
@Column({ type: 'varchar', length: 20, default: 'active' }) status: string;
|
||||||
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt: Date;
|
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) createdAt: Date;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue