feat(api): 建立 transactions 的 Server Actions,实装高精度字符串校验层
This commit is contained in:
parent
7bc234b9f6
commit
9c234009d4
50
src/actions/transaction.ts
Normal file
50
src/actions/transaction.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import { db } from '@/db';
|
||||||
|
import { transactions, transactionTypeEnum } from '@/db/schema';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { eq, desc } from 'drizzle-orm';
|
||||||
|
|
||||||
|
const createTransactionSchema = z.object({
|
||||||
|
assetId: z.string().uuid(),
|
||||||
|
txType: z.enum(['BUY', 'SELL', 'DIVIDEND', 'AIRDROP', 'FEE']),
|
||||||
|
quantity: z.string().regex(/^-?\d+(\.\d+)?$/, '数量必须是数字字符串'),
|
||||||
|
price: z.string().regex(/^-?\d+(\.\d+)?$/, '价格必须是数字字符串'),
|
||||||
|
fee: z.string().regex(/^-?\d+(\.\d+)?$/, '手续费必须是数字字符串').default('0'),
|
||||||
|
txCurrency: z.string().min(1),
|
||||||
|
exchangeRate: z.string().regex(/^-?\d+(\.\d+)?$/, '汇率必须是数字字符串').default('1'),
|
||||||
|
executedAt: z.coerce.date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function createTransaction(params: z.infer<typeof createTransactionSchema>) {
|
||||||
|
const validation = createTransactionSchema.safeParse(params);
|
||||||
|
if (!validation.success) {
|
||||||
|
return { success: false, error: validation.error.issues[0].message };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [transaction] = await db.insert(transactions).values(validation.data).returning();
|
||||||
|
return { success: true, data: transaction };
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (
|
||||||
|
error &&
|
||||||
|
typeof error === 'object' &&
|
||||||
|
'code' in error &&
|
||||||
|
(error as { code: string }).code === '23503'
|
||||||
|
) {
|
||||||
|
return { success: false, error: '资产不存在' };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTransactions(assetId?: string) {
|
||||||
|
if (assetId) {
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(transactions)
|
||||||
|
.where(eq(transactions.assetId, assetId))
|
||||||
|
.orderBy(desc(transactions.executedAt));
|
||||||
|
}
|
||||||
|
return db.select().from(transactions).orderBy(desc(transactions.executedAt));
|
||||||
|
}
|
||||||
@ -33,7 +33,7 @@ export const transactionTypeEnum = pgEnum("transaction_type_enum", [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const transactions = pgTable("transactions", {
|
export const transactions = pgTable("transactions", {
|
||||||
id: uuid("id").primaryKey(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
assetId: uuid("asset_id")
|
assetId: uuid("asset_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => assets.id),
|
.references(() => assets.id),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user