inmemory to postgres
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity({ name: 'payments_member_payments' })
|
||||
export class PaymentsMemberPaymentOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
feeId!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
driverId!: string;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
amount!: number;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
platformFee!: number;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
netAmount!: number;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
status!: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
dueDate!: Date;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
paidAt!: Date | null;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity({ name: 'payments_membership_fees' })
|
||||
export class PaymentsMembershipFeeOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column({ type: 'text' })
|
||||
leagueId!: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
seasonId!: string | null;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
type!: string;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
amount!: number;
|
||||
|
||||
@Column({ type: 'boolean' })
|
||||
enabled!: boolean;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
updatedAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity({ name: 'payments_payments' })
|
||||
export class PaymentsPaymentOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
leagueId!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
payerId!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
type!: string;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
amount!: number;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
platformFee!: number;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
netAmount!: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
payerType!: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
seasonId!: string | null;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
status!: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
completedAt!: Date | null;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Index('IDX_payments_prizes_league_season_position_unique', ['leagueId', 'seasonId', 'position'], { unique: true })
|
||||
@Entity({ name: 'payments_prizes' })
|
||||
export class PaymentsPrizeOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
leagueId!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
seasonId!: string;
|
||||
|
||||
@Column({ type: 'int' })
|
||||
position!: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
name!: string;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
amount!: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
type!: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description!: string | null;
|
||||
|
||||
@Column({ type: 'boolean' })
|
||||
awarded!: boolean;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
awardedTo!: string | null;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
awardedAt!: Date | null;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity({ name: 'payments_wallet_transactions' })
|
||||
export class PaymentsTransactionOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index()
|
||||
@Column({ type: 'text' })
|
||||
walletId!: string;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
type!: string;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
amount!: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
description!: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
referenceId!: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
referenceType!: string | null;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity({ name: 'payments_wallets' })
|
||||
export class PaymentsWalletOrmEntity {
|
||||
@PrimaryColumn({ type: 'text' })
|
||||
id!: string;
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column({ type: 'text' })
|
||||
leagueId!: string;
|
||||
|
||||
@Column({ type: 'double precision', default: 0 })
|
||||
balance!: number;
|
||||
|
||||
@Column({ type: 'double precision', default: 0 })
|
||||
totalRevenue!: number;
|
||||
|
||||
@Column({ type: 'double precision', default: 0 })
|
||||
totalPlatformFees!: number;
|
||||
|
||||
@Column({ type: 'double precision', default: 0 })
|
||||
totalWithdrawn!: number;
|
||||
|
||||
@Column({ type: 'text' })
|
||||
currency!: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
createdAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export type TypeOrmPaymentsSchemaErrorReason =
|
||||
| 'missing'
|
||||
| 'not_string'
|
||||
| 'empty_string'
|
||||
| 'not_number'
|
||||
| 'not_integer'
|
||||
| 'not_boolean'
|
||||
| 'not_date'
|
||||
| 'invalid_date'
|
||||
| 'invalid_enum_value'
|
||||
| 'invalid_shape';
|
||||
|
||||
export class TypeOrmPaymentsSchemaError extends Error {
|
||||
readonly entityName: string;
|
||||
readonly fieldName: string;
|
||||
readonly reason: TypeOrmPaymentsSchemaErrorReason | (string & {});
|
||||
|
||||
constructor(params: {
|
||||
entityName: string;
|
||||
fieldName: string;
|
||||
reason: TypeOrmPaymentsSchemaError['reason'];
|
||||
message?: string;
|
||||
}) {
|
||||
const message =
|
||||
params.message ?? `Invalid persisted ${params.entityName}.${params.fieldName}: ${params.reason}`;
|
||||
super(message);
|
||||
this.name = 'TypeOrmPaymentsSchemaError';
|
||||
this.entityName = params.entityName;
|
||||
this.fieldName = params.fieldName;
|
||||
this.reason = params.reason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { MemberPayment } from '@core/payments/domain/entities/MemberPayment';
|
||||
import { MemberPayment as MemberPaymentFactory, MemberPaymentStatus } from '@core/payments/domain/entities/MemberPayment';
|
||||
|
||||
import { PaymentsMemberPaymentOrmEntity } from '../entities/PaymentsMemberPaymentOrmEntity';
|
||||
import {
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertOptionalDate,
|
||||
} from '../schema/TypeOrmPaymentsSchemaGuards';
|
||||
|
||||
export class PaymentsMemberPaymentOrmMapper {
|
||||
toOrmEntity(domain: MemberPayment): PaymentsMemberPaymentOrmEntity {
|
||||
const entity = new PaymentsMemberPaymentOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.feeId = domain.feeId;
|
||||
entity.driverId = domain.driverId;
|
||||
entity.amount = domain.amount;
|
||||
entity.platformFee = domain.platformFee;
|
||||
entity.netAmount = domain.netAmount;
|
||||
entity.status = domain.status;
|
||||
entity.dueDate = domain.dueDate;
|
||||
entity.paidAt = domain.paidAt ?? null;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomain(entity: PaymentsMemberPaymentOrmEntity): MemberPayment {
|
||||
const entityName = 'PaymentsMemberPayment';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertNonEmptyString(entityName, 'feeId', entity.feeId);
|
||||
assertNonEmptyString(entityName, 'driverId', entity.driverId);
|
||||
assertNumber(entityName, 'amount', entity.amount);
|
||||
assertNumber(entityName, 'platformFee', entity.platformFee);
|
||||
assertNumber(entityName, 'netAmount', entity.netAmount);
|
||||
assertEnumValue(entityName, 'status', entity.status, Object.values(MemberPaymentStatus));
|
||||
assertDate(entityName, 'dueDate', entity.dueDate);
|
||||
assertOptionalDate(entityName, 'paidAt', entity.paidAt);
|
||||
|
||||
return MemberPaymentFactory.rehydrate({
|
||||
id: entity.id,
|
||||
feeId: entity.feeId,
|
||||
driverId: entity.driverId,
|
||||
amount: entity.amount,
|
||||
platformFee: entity.platformFee,
|
||||
netAmount: entity.netAmount,
|
||||
status: entity.status,
|
||||
dueDate: entity.dueDate,
|
||||
...(entity.paidAt !== null && entity.paidAt !== undefined ? { paidAt: entity.paidAt } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import type { MembershipFee } from '@core/payments/domain/entities/MembershipFee';
|
||||
import { MembershipFee as MembershipFeeFactory, MembershipFeeType } from '@core/payments/domain/entities/MembershipFee';
|
||||
|
||||
import { PaymentsMembershipFeeOrmEntity } from '../entities/PaymentsMembershipFeeOrmEntity';
|
||||
import {
|
||||
assertBoolean,
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertOptionalStringOrNull,
|
||||
} from '../schema/TypeOrmPaymentsSchemaGuards';
|
||||
|
||||
export class PaymentsMembershipFeeOrmMapper {
|
||||
toOrmEntity(domain: MembershipFee): PaymentsMembershipFeeOrmEntity {
|
||||
const entity = new PaymentsMembershipFeeOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.leagueId = domain.leagueId;
|
||||
entity.seasonId = domain.seasonId ?? null;
|
||||
entity.type = domain.type;
|
||||
entity.amount = domain.amount;
|
||||
entity.enabled = domain.enabled;
|
||||
entity.createdAt = domain.createdAt;
|
||||
entity.updatedAt = domain.updatedAt;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomain(entity: PaymentsMembershipFeeOrmEntity): MembershipFee {
|
||||
const entityName = 'PaymentsMembershipFee';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertNonEmptyString(entityName, 'leagueId', entity.leagueId);
|
||||
assertOptionalStringOrNull(entityName, 'seasonId', entity.seasonId);
|
||||
assertEnumValue(entityName, 'type', entity.type, Object.values(MembershipFeeType));
|
||||
assertNumber(entityName, 'amount', entity.amount);
|
||||
assertBoolean(entityName, 'enabled', entity.enabled);
|
||||
assertDate(entityName, 'createdAt', entity.createdAt);
|
||||
assertDate(entityName, 'updatedAt', entity.updatedAt);
|
||||
|
||||
return MembershipFeeFactory.rehydrate({
|
||||
id: entity.id,
|
||||
leagueId: entity.leagueId,
|
||||
type: entity.type,
|
||||
amount: entity.amount,
|
||||
enabled: entity.enabled,
|
||||
createdAt: entity.createdAt,
|
||||
updatedAt: entity.updatedAt,
|
||||
...(entity.seasonId !== null && entity.seasonId !== undefined ? { seasonId: entity.seasonId } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { Payment } from '@core/payments/domain/entities/Payment';
|
||||
import {
|
||||
Payment as PaymentFactory,
|
||||
PaymentStatus,
|
||||
PaymentType,
|
||||
PayerType,
|
||||
} from '@core/payments/domain/entities/Payment';
|
||||
|
||||
import { PaymentsPaymentOrmEntity } from '../entities/PaymentsPaymentOrmEntity';
|
||||
import {
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertOptionalStringOrNull,
|
||||
} from '../schema/TypeOrmPaymentsSchemaGuards';
|
||||
|
||||
export class PaymentsPaymentOrmMapper {
|
||||
toOrmEntity(domain: Payment): PaymentsPaymentOrmEntity {
|
||||
const entity = new PaymentsPaymentOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.type = domain.type;
|
||||
entity.amount = domain.amount;
|
||||
entity.platformFee = domain.platformFee;
|
||||
entity.netAmount = domain.netAmount;
|
||||
entity.payerId = domain.payerId;
|
||||
entity.payerType = domain.payerType;
|
||||
entity.leagueId = domain.leagueId;
|
||||
entity.seasonId = domain.seasonId ?? null;
|
||||
entity.status = domain.status;
|
||||
entity.createdAt = domain.createdAt;
|
||||
entity.completedAt = domain.completedAt ?? null;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomain(entity: PaymentsPaymentOrmEntity): Payment {
|
||||
const entityName = 'PaymentsPayment';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertEnumValue(entityName, 'type', entity.type, Object.values(PaymentType));
|
||||
assertNumber(entityName, 'amount', entity.amount);
|
||||
assertNumber(entityName, 'platformFee', entity.platformFee);
|
||||
assertNumber(entityName, 'netAmount', entity.netAmount);
|
||||
assertNonEmptyString(entityName, 'payerId', entity.payerId);
|
||||
assertEnumValue(entityName, 'payerType', entity.payerType, Object.values(PayerType));
|
||||
assertNonEmptyString(entityName, 'leagueId', entity.leagueId);
|
||||
assertOptionalStringOrNull(entityName, 'seasonId', entity.seasonId);
|
||||
assertEnumValue(entityName, 'status', entity.status, Object.values(PaymentStatus));
|
||||
assertDate(entityName, 'createdAt', entity.createdAt);
|
||||
|
||||
if (entity.completedAt !== null && entity.completedAt !== undefined) {
|
||||
assertDate(entityName, 'completedAt', entity.completedAt);
|
||||
}
|
||||
|
||||
return PaymentFactory.rehydrate({
|
||||
id: entity.id,
|
||||
type: entity.type,
|
||||
amount: entity.amount,
|
||||
platformFee: entity.platformFee,
|
||||
netAmount: entity.netAmount,
|
||||
payerId: entity.payerId,
|
||||
payerType: entity.payerType,
|
||||
leagueId: entity.leagueId,
|
||||
status: entity.status,
|
||||
createdAt: entity.createdAt,
|
||||
...(entity.seasonId !== null && entity.seasonId !== undefined ? { seasonId: entity.seasonId } : {}),
|
||||
...(entity.completedAt !== null && entity.completedAt !== undefined ? { completedAt: entity.completedAt } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { Prize } from '@core/payments/domain/entities/Prize';
|
||||
import { Prize as PrizeFactory, PrizeType } from '@core/payments/domain/entities/Prize';
|
||||
|
||||
import { PaymentsPrizeOrmEntity } from '../entities/PaymentsPrizeOrmEntity';
|
||||
import {
|
||||
assertBoolean,
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertInteger,
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertOptionalDate,
|
||||
assertOptionalStringOrNull,
|
||||
} from '../schema/TypeOrmPaymentsSchemaGuards';
|
||||
|
||||
export class PaymentsPrizeOrmMapper {
|
||||
toOrmEntity(domain: Prize): PaymentsPrizeOrmEntity {
|
||||
const entity = new PaymentsPrizeOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.leagueId = domain.leagueId;
|
||||
entity.seasonId = domain.seasonId;
|
||||
entity.position = domain.position;
|
||||
entity.name = domain.name;
|
||||
entity.amount = domain.amount;
|
||||
entity.type = domain.type;
|
||||
entity.description = domain.description ?? null;
|
||||
entity.awarded = domain.awarded;
|
||||
entity.awardedTo = domain.awardedTo ?? null;
|
||||
entity.awardedAt = domain.awardedAt ?? null;
|
||||
entity.createdAt = domain.createdAt;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomain(entity: PaymentsPrizeOrmEntity): Prize {
|
||||
const entityName = 'PaymentsPrize';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertNonEmptyString(entityName, 'leagueId', entity.leagueId);
|
||||
assertNonEmptyString(entityName, 'seasonId', entity.seasonId);
|
||||
assertInteger(entityName, 'position', entity.position);
|
||||
assertNonEmptyString(entityName, 'name', entity.name);
|
||||
assertNumber(entityName, 'amount', entity.amount);
|
||||
assertEnumValue(entityName, 'type', entity.type, Object.values(PrizeType));
|
||||
assertOptionalStringOrNull(entityName, 'description', entity.description);
|
||||
assertBoolean(entityName, 'awarded', entity.awarded);
|
||||
assertOptionalStringOrNull(entityName, 'awardedTo', entity.awardedTo);
|
||||
assertOptionalDate(entityName, 'awardedAt', entity.awardedAt);
|
||||
assertDate(entityName, 'createdAt', entity.createdAt);
|
||||
|
||||
return PrizeFactory.rehydrate({
|
||||
id: entity.id,
|
||||
leagueId: entity.leagueId,
|
||||
seasonId: entity.seasonId,
|
||||
position: entity.position,
|
||||
name: entity.name,
|
||||
amount: entity.amount,
|
||||
type: entity.type,
|
||||
awarded: entity.awarded,
|
||||
createdAt: entity.createdAt,
|
||||
...(entity.description !== null && entity.description !== undefined ? { description: entity.description } : {}),
|
||||
...(entity.awardedTo !== null && entity.awardedTo !== undefined ? { awardedTo: entity.awardedTo } : {}),
|
||||
...(entity.awardedAt !== null && entity.awardedAt !== undefined ? { awardedAt: entity.awardedAt } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { TransactionType } from '@core/payments/domain/entities/Wallet';
|
||||
|
||||
import { TypeOrmPaymentsSchemaError } from '../errors/TypeOrmPaymentsSchemaError';
|
||||
import { PaymentsWalletOrmEntity } from '../entities/PaymentsWalletOrmEntity';
|
||||
import { PaymentsWalletOrmMapper } from './PaymentsWalletOrmMapper';
|
||||
|
||||
describe('PaymentsWalletOrmMapper', () => {
|
||||
it('maps Wallet domain <-> orm', () => {
|
||||
const wallet = {
|
||||
id: 'wallet-1',
|
||||
leagueId: 'league-1',
|
||||
balance: 10,
|
||||
totalRevenue: 20,
|
||||
totalPlatformFees: 1,
|
||||
totalWithdrawn: 5,
|
||||
currency: 'USD',
|
||||
createdAt: new Date('2025-01-01T00:00:00.000Z'),
|
||||
};
|
||||
|
||||
const mapper = new PaymentsWalletOrmMapper();
|
||||
const orm = mapper.toOrmEntity(wallet);
|
||||
const rehydrated = mapper.toDomain(orm);
|
||||
|
||||
expect(rehydrated.id).toBe('wallet-1');
|
||||
expect(rehydrated.leagueId).toBe('league-1');
|
||||
expect(rehydrated.balance).toBe(10);
|
||||
expect(rehydrated.currency).toBe('USD');
|
||||
expect(rehydrated.createdAt.toISOString()).toBe('2025-01-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('throws schema error on invalid Wallet', () => {
|
||||
const mapper = new PaymentsWalletOrmMapper();
|
||||
|
||||
const orm = new PaymentsWalletOrmEntity();
|
||||
orm.id = '';
|
||||
orm.leagueId = 'league-1';
|
||||
orm.balance = 0;
|
||||
orm.totalRevenue = 0;
|
||||
orm.totalPlatformFees = 0;
|
||||
orm.totalWithdrawn = 0;
|
||||
orm.currency = 'USD';
|
||||
orm.createdAt = new Date();
|
||||
|
||||
expect(() => mapper.toDomain(orm)).toThrow(TypeOrmPaymentsSchemaError);
|
||||
});
|
||||
|
||||
it('maps Transaction domain <-> orm', () => {
|
||||
const transaction = {
|
||||
id: 'txn-1',
|
||||
walletId: 'wallet-1',
|
||||
type: TransactionType.DEPOSIT,
|
||||
amount: 123,
|
||||
description: 'Deposit',
|
||||
createdAt: new Date('2025-01-01T00:00:00.000Z'),
|
||||
};
|
||||
|
||||
const mapper = new PaymentsWalletOrmMapper();
|
||||
const orm = mapper.toOrmTransaction(transaction);
|
||||
const rehydrated = mapper.toDomainTransaction(orm);
|
||||
|
||||
expect(rehydrated.id).toBe('txn-1');
|
||||
expect(rehydrated.walletId).toBe('wallet-1');
|
||||
expect(rehydrated.type).toBe(TransactionType.DEPOSIT);
|
||||
expect(rehydrated.amount).toBe(123);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
import type { Wallet, Transaction } from '@core/payments/domain/entities/Wallet';
|
||||
import { ReferenceType, Transaction as TransactionFactory, TransactionType, Wallet as WalletFactory } from '@core/payments/domain/entities/Wallet';
|
||||
|
||||
import { PaymentsTransactionOrmEntity } from '../entities/PaymentsTransactionOrmEntity';
|
||||
import { PaymentsWalletOrmEntity } from '../entities/PaymentsWalletOrmEntity';
|
||||
import {
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertOptionalStringOrNull,
|
||||
} from '../schema/TypeOrmPaymentsSchemaGuards';
|
||||
|
||||
export class PaymentsWalletOrmMapper {
|
||||
toOrmEntity(domain: Wallet): PaymentsWalletOrmEntity {
|
||||
const entity = new PaymentsWalletOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.leagueId = domain.leagueId;
|
||||
entity.balance = domain.balance;
|
||||
entity.totalRevenue = domain.totalRevenue;
|
||||
entity.totalPlatformFees = domain.totalPlatformFees;
|
||||
entity.totalWithdrawn = domain.totalWithdrawn;
|
||||
entity.currency = domain.currency;
|
||||
entity.createdAt = domain.createdAt;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomain(entity: PaymentsWalletOrmEntity): Wallet {
|
||||
const entityName = 'PaymentsWallet';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertNonEmptyString(entityName, 'leagueId', entity.leagueId);
|
||||
assertNumber(entityName, 'balance', entity.balance);
|
||||
assertNumber(entityName, 'totalRevenue', entity.totalRevenue);
|
||||
assertNumber(entityName, 'totalPlatformFees', entity.totalPlatformFees);
|
||||
assertNumber(entityName, 'totalWithdrawn', entity.totalWithdrawn);
|
||||
assertNonEmptyString(entityName, 'currency', entity.currency);
|
||||
assertDate(entityName, 'createdAt', entity.createdAt);
|
||||
|
||||
return WalletFactory.rehydrate({
|
||||
id: entity.id,
|
||||
leagueId: entity.leagueId,
|
||||
balance: entity.balance,
|
||||
totalRevenue: entity.totalRevenue,
|
||||
totalPlatformFees: entity.totalPlatformFees,
|
||||
totalWithdrawn: entity.totalWithdrawn,
|
||||
currency: entity.currency,
|
||||
createdAt: entity.createdAt,
|
||||
});
|
||||
}
|
||||
|
||||
toOrmTransaction(domain: Transaction): PaymentsTransactionOrmEntity {
|
||||
const entity = new PaymentsTransactionOrmEntity();
|
||||
entity.id = domain.id;
|
||||
entity.walletId = domain.walletId;
|
||||
entity.type = domain.type;
|
||||
entity.amount = domain.amount;
|
||||
entity.description = domain.description;
|
||||
entity.referenceId = domain.referenceId ?? null;
|
||||
entity.referenceType = domain.referenceType ?? null;
|
||||
entity.createdAt = domain.createdAt;
|
||||
return entity;
|
||||
}
|
||||
|
||||
toDomainTransaction(entity: PaymentsTransactionOrmEntity): Transaction {
|
||||
const entityName = 'PaymentsTransaction';
|
||||
|
||||
assertNonEmptyString(entityName, 'id', entity.id);
|
||||
assertNonEmptyString(entityName, 'walletId', entity.walletId);
|
||||
assertNonEmptyString(entityName, 'type', entity.type);
|
||||
assertEnumValue(entityName, 'type', entity.type, Object.values(TransactionType));
|
||||
assertNumber(entityName, 'amount', entity.amount);
|
||||
assertNonEmptyString(entityName, 'description', entity.description);
|
||||
assertOptionalStringOrNull(entityName, 'referenceId', entity.referenceId);
|
||||
assertOptionalStringOrNull(entityName, 'referenceType', entity.referenceType);
|
||||
assertDate(entityName, 'createdAt', entity.createdAt);
|
||||
|
||||
if (entity.referenceType !== null && entity.referenceType !== undefined) {
|
||||
assertEnumValue(entityName, 'referenceType', entity.referenceType, Object.values(ReferenceType));
|
||||
}
|
||||
|
||||
return TransactionFactory.rehydrate({
|
||||
id: entity.id,
|
||||
walletId: entity.walletId,
|
||||
type: entity.type,
|
||||
amount: entity.amount,
|
||||
description: entity.description,
|
||||
createdAt: entity.createdAt,
|
||||
...(entity.referenceId !== null && entity.referenceId !== undefined ? { referenceId: entity.referenceId } : {}),
|
||||
...(entity.referenceType !== null && entity.referenceType !== undefined ? { referenceType: entity.referenceType as ReferenceType } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import type { IMemberPaymentRepository, IMembershipFeeRepository } from '@core/payments/domain/repositories/IMembershipFeeRepository';
|
||||
import type { MemberPayment } from '@core/payments/domain/entities/MemberPayment';
|
||||
import type { MembershipFee } from '@core/payments/domain/entities/MembershipFee';
|
||||
|
||||
import { PaymentsMemberPaymentOrmEntity } from '../entities/PaymentsMemberPaymentOrmEntity';
|
||||
import { PaymentsMembershipFeeOrmEntity } from '../entities/PaymentsMembershipFeeOrmEntity';
|
||||
import { PaymentsMemberPaymentOrmMapper } from '../mappers/PaymentsMemberPaymentOrmMapper';
|
||||
import { PaymentsMembershipFeeOrmMapper } from '../mappers/PaymentsMembershipFeeOrmMapper';
|
||||
|
||||
export class TypeOrmMembershipFeeRepository implements IMembershipFeeRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsMembershipFeeOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<MembershipFee | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<MembershipFee | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
|
||||
const entity = await repo.findOne({ where: { leagueId } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async create(fee: MembershipFee): Promise<MembershipFee> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(fee));
|
||||
return fee;
|
||||
}
|
||||
|
||||
async update(fee: MembershipFee): Promise<MembershipFee> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMembershipFeeOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(fee));
|
||||
return fee;
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeOrmMemberPaymentRepository implements IMemberPaymentRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsMemberPaymentOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<MemberPayment | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByFeeIdAndDriverId(feeId: string, driverId: string): Promise<MemberPayment | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
|
||||
const entity = await repo.findOne({ where: { feeId, driverId } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByLeagueIdAndDriverId(
|
||||
leagueId: string,
|
||||
driverId: string,
|
||||
membershipFeeRepo: IMembershipFeeRepository,
|
||||
): Promise<MemberPayment[]> {
|
||||
const fee = await membershipFeeRepo.findByLeagueId(leagueId);
|
||||
if (!fee) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
|
||||
const entities = await repo.find({ where: { feeId: fee.id, driverId } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async create(payment: MemberPayment): Promise<MemberPayment> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(payment));
|
||||
return payment;
|
||||
}
|
||||
|
||||
async update(payment: MemberPayment): Promise<MemberPayment> {
|
||||
const repo = this.dataSource.getRepository(PaymentsMemberPaymentOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(payment));
|
||||
return payment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import { TypeOrmPaymentRepository } from './TypeOrmPaymentRepository';
|
||||
import { PaymentsPaymentOrmMapper } from '../mappers/PaymentsPaymentOrmMapper';
|
||||
|
||||
describe('TypeOrmPaymentRepository', () => {
|
||||
it('constructor requires injected mapper (no internal mapper instantiation)', () => {
|
||||
const dataSource = {} as unknown as DataSource;
|
||||
const mapper = {} as unknown as PaymentsPaymentOrmMapper;
|
||||
|
||||
const repo = new TypeOrmPaymentRepository(dataSource, mapper);
|
||||
|
||||
expect(repo).toBeInstanceOf(TypeOrmPaymentRepository);
|
||||
expect((repo as unknown as { mapper: unknown }).mapper).toBe(mapper);
|
||||
});
|
||||
|
||||
it('works with mocked TypeORM DataSource (no DB required)', async () => {
|
||||
const findOne = async () => null;
|
||||
|
||||
const dataSource = {
|
||||
getRepository: () => ({ findOne }),
|
||||
} as unknown as DataSource;
|
||||
|
||||
const mapper = {
|
||||
toDomain: () => {
|
||||
throw new Error('should-not-be-called');
|
||||
},
|
||||
} as unknown as PaymentsPaymentOrmMapper;
|
||||
|
||||
const repo = new TypeOrmPaymentRepository(dataSource, mapper);
|
||||
|
||||
await expect(repo.findById('payment-1')).resolves.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
|
||||
import type { Payment, PaymentType } from '@core/payments/domain/entities/Payment';
|
||||
|
||||
import { PaymentsPaymentOrmEntity } from '../entities/PaymentsPaymentOrmEntity';
|
||||
import { PaymentsPaymentOrmMapper } from '../mappers/PaymentsPaymentOrmMapper';
|
||||
|
||||
export class TypeOrmPaymentRepository implements IPaymentRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsPaymentOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<Payment | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<Payment[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
const entities = await repo.find({ where: { leagueId } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async findByPayerId(payerId: string): Promise<Payment[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
const entities = await repo.find({ where: { payerId } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async findByType(type: PaymentType): Promise<Payment[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
const entities = await repo.find({ where: { type } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async findByFilters(filters: { leagueId?: string; payerId?: string; type?: PaymentType }): Promise<Payment[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
|
||||
const where: {
|
||||
leagueId?: string;
|
||||
payerId?: string;
|
||||
type?: PaymentType;
|
||||
} = {};
|
||||
|
||||
if (filters.leagueId !== undefined) where.leagueId = filters.leagueId;
|
||||
if (filters.payerId !== undefined) where.payerId = filters.payerId;
|
||||
if (filters.type !== undefined) where.type = filters.type;
|
||||
|
||||
const entities = await repo.find({ where });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async create(payment: Payment): Promise<Payment> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(payment));
|
||||
return payment;
|
||||
}
|
||||
|
||||
async update(payment: Payment): Promise<Payment> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPaymentOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(payment));
|
||||
return payment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import type { IPrizeRepository } from '@core/payments/domain/repositories/IPrizeRepository';
|
||||
import type { Prize } from '@core/payments/domain/entities/Prize';
|
||||
|
||||
import { PaymentsPrizeOrmEntity } from '../entities/PaymentsPrizeOrmEntity';
|
||||
import { PaymentsPrizeOrmMapper } from '../mappers/PaymentsPrizeOrmMapper';
|
||||
|
||||
export class TypeOrmPrizeRepository implements IPrizeRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsPrizeOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<Prize | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<Prize[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
const entities = await repo.find({ where: { leagueId } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async findByLeagueIdAndSeasonId(leagueId: string, seasonId: string): Promise<Prize[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
const entities = await repo.find({ where: { leagueId, seasonId } });
|
||||
return entities.map((e) => this.mapper.toDomain(e));
|
||||
}
|
||||
|
||||
async findByPosition(leagueId: string, seasonId: string, position: number): Promise<Prize | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
const entity = await repo.findOne({ where: { leagueId, seasonId, position } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async create(prize: Prize): Promise<Prize> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(prize));
|
||||
return prize;
|
||||
}
|
||||
|
||||
async update(prize: Prize): Promise<Prize> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(prize));
|
||||
return prize;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
const repo = this.dataSource.getRepository(PaymentsPrizeOrmEntity);
|
||||
await repo.delete({ id });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import { TypeOrmWalletRepository } from './TypeOrmWalletRepository';
|
||||
import { PaymentsWalletOrmMapper } from '../mappers/PaymentsWalletOrmMapper';
|
||||
|
||||
describe('TypeOrmWalletRepository', () => {
|
||||
it('constructor requires injected mapper (no internal mapper instantiation)', () => {
|
||||
const dataSource = {} as unknown as DataSource;
|
||||
const mapper = {} as unknown as PaymentsWalletOrmMapper;
|
||||
|
||||
const repo = new TypeOrmWalletRepository(dataSource, mapper);
|
||||
|
||||
expect(repo).toBeInstanceOf(TypeOrmWalletRepository);
|
||||
expect((repo as unknown as { mapper: unknown }).mapper).toBe(mapper);
|
||||
});
|
||||
|
||||
it('works with mocked TypeORM DataSource (no DB required)', async () => {
|
||||
const findOne = async () => null;
|
||||
|
||||
const dataSource = {
|
||||
getRepository: () => ({ findOne }),
|
||||
} as unknown as DataSource;
|
||||
|
||||
const mapper = {
|
||||
toDomain: () => {
|
||||
throw new Error('should-not-be-called');
|
||||
},
|
||||
} as unknown as PaymentsWalletOrmMapper;
|
||||
|
||||
const repo = new TypeOrmWalletRepository(dataSource, mapper);
|
||||
|
||||
await expect(repo.findById('wallet-1')).resolves.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
import type { ITransactionRepository, IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
|
||||
import type { Transaction, Wallet } from '@core/payments/domain/entities/Wallet';
|
||||
|
||||
import { PaymentsTransactionOrmEntity } from '../entities/PaymentsTransactionOrmEntity';
|
||||
import { PaymentsWalletOrmEntity } from '../entities/PaymentsWalletOrmEntity';
|
||||
import { PaymentsWalletOrmMapper } from '../mappers/PaymentsWalletOrmMapper';
|
||||
|
||||
export class TypeOrmWalletRepository implements IWalletRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsWalletOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<Wallet | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsWalletOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async findByLeagueId(leagueId: string): Promise<Wallet | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsWalletOrmEntity);
|
||||
const entity = await repo.findOne({ where: { leagueId } });
|
||||
return entity ? this.mapper.toDomain(entity) : null;
|
||||
}
|
||||
|
||||
async create(wallet: Wallet): Promise<Wallet> {
|
||||
const repo = this.dataSource.getRepository(PaymentsWalletOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(wallet));
|
||||
return wallet;
|
||||
}
|
||||
|
||||
async update(wallet: Wallet): Promise<Wallet> {
|
||||
const repo = this.dataSource.getRepository(PaymentsWalletOrmEntity);
|
||||
await repo.save(this.mapper.toOrmEntity(wallet));
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeOrmTransactionRepository implements ITransactionRepository {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly mapper: PaymentsWalletOrmMapper,
|
||||
) {}
|
||||
|
||||
async findById(id: string): Promise<Transaction | null> {
|
||||
const repo = this.dataSource.getRepository(PaymentsTransactionOrmEntity);
|
||||
const entity = await repo.findOne({ where: { id } });
|
||||
return entity ? this.mapper.toDomainTransaction(entity) : null;
|
||||
}
|
||||
|
||||
async findByWalletId(walletId: string): Promise<Transaction[]> {
|
||||
const repo = this.dataSource.getRepository(PaymentsTransactionOrmEntity);
|
||||
const entities = await repo.find({ where: { walletId } });
|
||||
return entities.map((e) => this.mapper.toDomainTransaction(e));
|
||||
}
|
||||
|
||||
async create(transaction: Transaction): Promise<Transaction> {
|
||||
const repo = this.dataSource.getRepository(PaymentsTransactionOrmEntity);
|
||||
await repo.save(this.mapper.toOrmTransaction(transaction));
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { TypeOrmPaymentsSchemaError } from '../errors/TypeOrmPaymentsSchemaError';
|
||||
|
||||
export function assertNonEmptyString(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
): asserts value is string {
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_string' });
|
||||
}
|
||||
|
||||
if (value.trim().length === 0) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'empty_string' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertNumber(entityName: string, fieldName: string, value: unknown): asserts value is number {
|
||||
if (typeof value !== 'number' || Number.isNaN(value)) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_number' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertInteger(entityName: string, fieldName: string, value: unknown): asserts value is number {
|
||||
if (typeof value !== 'number' || !Number.isInteger(value)) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_integer' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertBoolean(entityName: string, fieldName: string, value: unknown): asserts value is boolean {
|
||||
if (typeof value !== 'boolean') {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_boolean' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertDate(entityName: string, fieldName: string, value: unknown): asserts value is Date {
|
||||
if (!(value instanceof Date)) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_date' });
|
||||
}
|
||||
if (Number.isNaN(value.getTime())) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'invalid_date' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertEnumValue<TAllowed extends string>(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
allowed: readonly TAllowed[],
|
||||
): asserts value is TAllowed {
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_string' });
|
||||
}
|
||||
|
||||
if (!allowed.includes(value as TAllowed)) {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'invalid_enum_value' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertOptionalStringOrNull(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
): asserts value is string | null | undefined {
|
||||
if (value === null || value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeOrmPaymentsSchemaError({ entityName, fieldName, reason: 'not_string' });
|
||||
}
|
||||
}
|
||||
|
||||
export function assertOptionalDate(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
): asserts value is Date | undefined | null {
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertDate(entityName, fieldName, value);
|
||||
}
|
||||
|
||||
export function assertOptionalNumber(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
): asserts value is number | undefined | null {
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertNumber(entityName, fieldName, value);
|
||||
}
|
||||
|
||||
export function assertOptionalBoolean(
|
||||
entityName: string,
|
||||
fieldName: string,
|
||||
value: unknown,
|
||||
): asserts value is boolean | undefined | null {
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertBoolean(entityName, fieldName, value);
|
||||
}
|
||||
|
||||
export const TypeOrmPaymentsSchemaGuards = {
|
||||
assertNonEmptyString,
|
||||
assertNumber,
|
||||
assertInteger,
|
||||
assertBoolean,
|
||||
assertDate,
|
||||
assertEnumValue,
|
||||
assertOptionalStringOrNull,
|
||||
assertOptionalDate,
|
||||
assertOptionalNumber,
|
||||
assertOptionalBoolean,
|
||||
} as const;
|
||||
Reference in New Issue
Block a user