clone:legacy

This commit is contained in:
2025-09-05 11:09:58 +09:00
commit 6103518feb
119 changed files with 41713 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';
import {
IsBoolean,
IsEmpty,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
} from 'class-validator';
export default class TransferQueryDto {
@IsOptional()
@IsString()
@ApiProperty({
nullable: true,
required: false,
})
readonly address?: string;
@IsOptional()
@IsString()
@ApiProperty({
nullable: true,
required: false,
})
readonly reason?: string;
@IsOptional()
@IsNumber()
@ApiProperty({
nullable: true,
required: false,
})
readonly page?: number;
}

View File

@@ -0,0 +1,22 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TranferHistoriesController } from './transferhhistories.controller';
import { TranferHistoriesService } from './transferhistories.service';
describe('TranferHistoriesController', () => {
let controller: TranferHistoriesController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TranferHistoriesController],
providers: [TranferHistoriesService],
}).compile();
controller = module.get<TranferHistoriesController>(
TranferHistoriesController,
);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TranferHistoriesService } from './transferhistories.service';
describe('TranferHistoriesService', () => {
let service: TranferHistoriesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TranferHistoriesService],
}).compile();
service = module.get<TranferHistoriesService>(TranferHistoriesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,51 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
ParseIntPipe,
Query,
} from '@nestjs/common';
import { TranferHistoriesService } from './transferhistories.service';
import TransferQueryDto from './dto/transferhistories.query.dto';
import { ApiOperation } from '@nestjs/swagger';
@Controller('transferlogs')
export class TranferHistoriesController {
constructor(
private readonly tranferHistoriesService: TranferHistoriesService,
) {}
@Get('/listAll')
@ApiOperation({
summary: '로그 전체 ',
description: '트랜젝션 로그 전체 리스트',
})
getListAll() {
return this.tranferHistoriesService.findAll();
}
@Get('/list')
getListPaging(@Query('page', ParseIntPipe) page: number) {
const currentPage = Number.isFinite(page) && page > 0 ? page : 1;
return this.tranferHistoriesService.findPageList(currentPage);
}
@Get('/list/filter')
getListFilterPaging(
@Query('page') page: string,
@Query('address') address: string,
@Query('reason') reason: string,
@Query('timestamp') timestamp: string,
) {
return this.tranferHistoriesService.findListPaging(
page,
address,
reason,
timestamp,
);
}
}

View File

@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TranferHistoriesService } from './transferhistories.service';
import { TranferHistoriesController } from './transferhhistories.controller';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule],
controllers: [TranferHistoriesController],
providers: [TranferHistoriesService],
})
export class TranferHistoriesModule {}

View File

@@ -0,0 +1,90 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma.service';
import TransferQueryDto from './dto/transferhistories.query.dto';
import { ConfigService } from '@nestjs/config';
import { formatUnits } from 'ethers';
import { Prisma } from '@prisma/client';
import {
TRANSFERLOGS_QUERY,
TRANSFERLOGS_UNIONALL_QUERY,
} from './transferhistories.sql';
@Injectable()
export class TranferHistoriesService {
private pageSize: number;
constructor(
private prisma: PrismaService,
private configService: ConfigService,
) {
this.pageSize = Number(this.configService.get<number>('PAGE_SIZE', 50));
}
async findAll() {
return await this.prisma.transferHistories.findMany({
orderBy: { idx: 'desc' },
});
}
async findPageList(page: number) {
return await this.prisma.transferHistories.findMany({
orderBy: { idx: 'desc' },
take: this.pageSize,
skip: ((page ?? 1) - 1) * this.pageSize,
});
}
async findList(body: TransferQueryDto) {
const where: any = {};
if (body.reason) {
where.memo = body.reason;
}
if (body.address) {
where.OR = [
{ from_address: { contains: body.address } },
{ to_address: { contains: body.address } },
];
}
return await this.prisma.transferHistories.findMany({
where,
orderBy: { idx: 'desc' },
});
}
async findListPaging(
page: string,
address: string,
reason: string,
timestamp: string,
) {
const parsed = page ? parseInt(page, 10) : NaN;
const currentPage =
!page || Number.isNaN(parsed) || parsed <= 0 ? 1 : parsed;
const take = this.pageSize;
const skip = (currentPage - 1) * take;
const ts = timestamp ? new Date(timestamp) : undefined;
let rows = [];
if (!address) {
rows = await this.prisma.$queryRaw(
TRANSFERLOGS_QUERY(reason, ts, take, skip),
);
} else {
rows = await this.prisma.$queryRaw(
TRANSFERLOGS_UNIONALL_QUERY(reason, address, ts, take, skip),
);
}
const mapped = rows.map((r) => ({
...r,
amount: parseFloat(formatUnits(r.amount.toFixed(0), 18)).toString(),
}));
return mapped;
}
}

View File

@@ -0,0 +1,89 @@
import { Prisma } from '@prisma/client';
export const TRANSFERLOGS_UNIONALL_QUERY = (
reason: string,
address: string,
ts: Date,
take: number,
skip: number,
) => {
return Prisma.sql`
SELECT
idx,
txhash,
blockNumber,
log_index,
from_address,
to_address,
amount,
memo,
timestamp,
createdAt
FROM (
SELECT
idx,
txhash,
blockNumber,
log_index,
from_address,
to_address,
amount,
memo,
timestamp,
createdAt
FROM TransferHistories
WHERE 1=1
${reason ? Prisma.sql`AND memo = ${reason}` : Prisma.empty}
${address ? Prisma.sql`AND from_address = ${address}` : Prisma.empty}
${ts ? Prisma.sql`AND timestamp >= ${ts}` : Prisma.empty}
UNION ALL
SELECT
idx,
txhash,
blockNumber,
log_index,
from_address,
to_address,
amount,
memo,
timestamp,
createdAt
FROM TransferHistories
WHERE 1=1
${reason ? Prisma.sql`AND memo = ${reason}` : Prisma.empty}
${address ? Prisma.sql`AND to_address = ${address}` : Prisma.empty}
${ts ? Prisma.sql`AND timestamp >= ${ts}` : Prisma.empty}
) AS t
ORDER BY t.idx DESC
LIMIT ${take} OFFSET ${skip}
`;
};
export const TRANSFERLOGS_QUERY = (
reason: string,
ts: Date,
take: number,
skip: number,
) => {
return Prisma.sql`
SELECT
idx,
txhash,
blockNumber,
log_index,
from_address,
to_address,
amount,
memo,
timestamp,
createdAt
FROM TransferHistories
WHERE 1=1
${reason ? Prisma.sql`AND memo = ${reason}` : Prisma.empty}
${ts ? Prisma.sql`AND timestamp >= ${ts}` : Prisma.empty}
ORDER BY idx DESC
LIMIT ${take} OFFSET ${skip}
`;
};