Skip to content

Commit

Permalink
update currency code (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
domechn authored Dec 9, 2023
1 parent 8a52c3b commit 6a5d526
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 187 deletions.
18 changes: 15 additions & 3 deletions src/components/comparison/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useContext, useEffect, useMemo, useState } from "react";
import "./index.css";
import { CoinData, CurrencyRateDetail } from "@/middlelayers/types";
import { queryAllDataDates, queryCoinDataByUUID } from "@/middlelayers/charts";
Expand All @@ -18,6 +18,7 @@ import {
SelectTrigger,
SelectValue,
} from "../ui/select";
import { LoadingContext } from '@/App'

type ComparisonData = {
name: string;
Expand All @@ -28,6 +29,7 @@ type ComparisonData = {
type QuickCompareType = "7D" | "1M" | "1Q" | "1Y";

const App = ({ currency }: { currency: CurrencyRateDetail }) => {
const { setLoading } = useContext(LoadingContext);
const [baseId, setBaseId] = useState<string>("");
const [dateOptions, setDateOptions] = useState<
{
Expand Down Expand Up @@ -56,6 +58,16 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => {

const [showDetail, setShowDetail] = useState<boolean>(true);

useEffect(() => {
// it is a hack
setLoading(true)
// sleep 150ms

setTimeout(() => {
setLoading(false)
}, 150)
},[])

useEffect(() => {
loadAllSelectDates().then((data) => {
const options = _(data)
Expand Down Expand Up @@ -87,14 +99,14 @@ const App = ({ currency }: { currency: CurrencyRateDetail }) => {
if (!baseId) {
return;
}
loadDataByUUID(baseId).then((data) => setBaseData(data));
loadDataByUUID(baseId).then((data) => setBaseData(data))
}, [baseId]);

useEffect(() => {
if (!headId) {
return;
}
loadDataByUUID(headId).then((data) => setHeadData(data));
loadDataByUUID(headId).then((data) => setHeadData(data))
}, [headId]);

// update quick compare data ( baseId and headId )
Expand Down
2 changes: 1 addition & 1 deletion src/components/configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
TokenConfig,
} from "@/middlelayers/datafetch/types";
import { CurrencyRateDetail } from "@/middlelayers/types";
import { listAllCurrencyRates } from "@/middlelayers/currency";
import { listAllCurrencyRates } from "@/middlelayers/configuration";
import { Separator } from "@/components/ui/separator";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
Expand Down
2 changes: 1 addition & 1 deletion src/components/index/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import {
getCurrentPreferCurrency,
getQuerySize,
} from "@/middlelayers/configuration";
import { getDefaultCurrencyRate } from "@/middlelayers/currency";
import { getDefaultCurrencyRate } from "@/middlelayers/configuration";
import _ from "lodash";
import { MainNav } from "@/components/index/main-nav";
import Configuration from "@/components/configuration";
Expand Down
2 changes: 1 addition & 1 deletion src/components/refresh-data/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import "./index.css";
import { useContext } from "react";
import { refreshAllData } from "../../middlelayers/charts";
import { updateAllCurrencyRates } from "../../middlelayers/currency";
import { trackEventWithClientID } from "../../utils/app";
import { useToast } from "@/components/ui/use-toast";
import { Button } from "../ui/button";
import { ReloadIcon } from "@radix-ui/react-icons";
import { RefreshButtonLoadingContext } from "../index";
import { CacheCenter } from '@/middlelayers/datafetch/utils/cache'
import { updateAllCurrencyRates } from '@/middlelayers/configuration'

const retries = 3;
const retryInterval = 3000; // 3s
Expand Down
48 changes: 16 additions & 32 deletions src/middlelayers/charts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import _ from 'lodash'
import { generateRandomColors } from '../utils/color'
import { getDatabase, saveCoinsToDatabase } from './database'
import { Asset, AssetAction, AssetChangeData, AssetModel, AssetPriceModel, CoinData, CoinsAmountAndValueChangeData, HistoricalData, LatestAssetsPercentageData, PNLData, TopCoinsPercentageChangeData, TopCoinsRankData, TotalValueData, WalletCoinUSD } from './types'

import { loadPortfolios, queryCoinPrices } from './data'
Expand All @@ -9,24 +8,22 @@ import { calculateTotalValue } from './datafetch/utils/coins'
import { timestampToDate } from '../utils/date'
import { WalletAnalyzer } from './wallet'
import { OthersAnalyzer } from './datafetch/coins/others'
import { ASSET_HANDLER } from './assets'
import { ASSET_HANDLER } from './entities/assets'
import { ASSET_PRICE_HANDLER } from './entities/asset-prices'

const STABLE_COIN = ["USDT", "USDC", "BUSD", "DAI", "TUSD", "PAX"]

export const ASSETS_TABLE_NAME = "assets_v2"
export const ASSETS_PRICE_TABLE_NAME = "asset_prices"

export const WALLET_ANALYZER = new WalletAnalyzer((size) => ASSET_HANDLER.listAssets(size))

export async function refreshAllData() {
const coins = await queryCoinsData()
await saveCoinsToDatabase(coins)
await ASSET_HANDLER.saveCoinsToDatabase(coins)
}

// return all asset actions by analyzing all asset models
export async function loadAllAssetActionsBySymbol(symbol: string): Promise<AssetAction[]> {
const assets = await ASSET_HANDLER.listAssetsBySymbol(symbol)
const updatedPrices = await queryAssetPrices(symbol)
const updatedPrices = await ASSET_PRICE_HANDLER.listPricesBySymbol(symbol)
const revAssets = _(assets).reverse().value()

const actions = _.flatMap(revAssets, (as, i) => {
Expand All @@ -37,10 +34,13 @@ export async function loadAllAssetActionsBySymbol(symbol: string): Promise<Asset
}

export async function updateAssetPrice(uuid: string, assetID: number, symbol: string, price: number, createdAt: string) {
const db = await getDatabase()
await db.execute(`INSERT OR REPLACE INTO ${ASSETS_PRICE_TABLE_NAME} (uuid, assetID, symbol, price, assetCreatedAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?)`, [
uuid, assetID, symbol, price, createdAt, new Date().toISOString()
])
await ASSET_PRICE_HANDLER.createOrUpdate({
uuid,
assetID,
symbol,
price,
assetCreatedAt: createdAt
} as AssetPriceModel)
}

function generateAssetActions(cur: AssetModel[], updatedPrices: AssetPriceModel[], pre?: AssetModel[]): AssetAction[] {
Expand Down Expand Up @@ -152,31 +152,17 @@ export async function queryAssetMaxAmountBySymbol(symbol: string): Promise<numbe

// return all asset prices for all symbols
export function queryAllAssetPrices(): Promise<AssetPriceModel[]> {
return queryAssetPrices()
return ASSET_PRICE_HANDLER.listPrices()
}

export function queryAssetPricesAfterAssetCreatedAt(createdAt?: number): Promise<AssetPriceModel[]> {
const ts = createdAt ? new Date(createdAt).toISOString() : undefined
return queryAssetPrices(undefined, ts)
return ASSET_PRICE_HANDLER.listPricesAfterAssetCreatedAt(ts)
}

export function queryAssetPricesAfterUpdatedAt(updatedAt?: number): Promise<AssetPriceModel[]> {
const ts = updatedAt ? new Date(updatedAt).toISOString() : undefined
return queryAssetPrices(undefined, undefined, ts)
}

async function queryAssetPrices(symbol?: string, assetCreated?: string, updatedAt?: string): Promise<AssetPriceModel[]> {
const db = await getDatabase()
const params = symbol ? [symbol] : []
if (assetCreated) {
params.push(assetCreated)
}
if (updatedAt) {
params.push(updatedAt)
}
const prices = await db.select<AssetPriceModel[]>(`SELECT * FROM ${ASSETS_PRICE_TABLE_NAME} WHERE 1=1 ${symbol ? 'and symbol = ?' : ''} ${assetCreated ? 'and assetCreatedAt > ?' : ''} ${updatedAt ? 'and updatedAt > ?' : ''}`, params)

return prices
return ASSET_PRICE_HANDLER.listPricesAfterUpdatedAt(ts)
}

export async function queryLastAssetsBySymbol(symbol: string): Promise<Asset | undefined> {
Expand Down Expand Up @@ -216,13 +202,11 @@ async function deleteAssetByID(id: number): Promise<void> {
}

async function deleteAssetPriceByUUID(uuid: string): Promise<void> {
const db = await getDatabase()
await db.execute(`DELETE FROM ${ASSETS_PRICE_TABLE_NAME} WHERE uuid = ?`, [uuid])
return ASSET_PRICE_HANDLER.deletePricesByUUID(uuid)
}

async function deleteAssetPriceByID(id: number): Promise<void> {
const db = await getDatabase()
await db.execute(`DELETE FROM ${ASSETS_PRICE_TABLE_NAME} WHERE assetID = ?`, [id])
return ASSET_PRICE_HANDLER.deletePricesByAssetID(id)
}

export async function queryTotalValue(): Promise<TotalValueData> {
Expand Down
20 changes: 16 additions & 4 deletions src/middlelayers/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getDatabase } from './database'
import { GlobalConfig } from './datafetch/types'
import { CloudSyncConfiguration, ConfigurationModel, CurrencyRateDetail } from './types'
import yaml from 'yaml'
import { getCurrencyRate, getDefaultCurrencyRate } from './currency'
import { CURRENCY_RATE_HANDLER } from './entities/currency'

const prefix = "!ent:"
const fixId = "1"
Expand Down Expand Up @@ -93,18 +93,30 @@ export async function getQuerySize(): Promise<number> {
return cfg.configs.querySize || 10
}

export async function updateAllCurrencyRates() {
return CURRENCY_RATE_HANDLER.updateAllCurrencyRates()
}

export async function listAllCurrencyRates(){
return CURRENCY_RATE_HANDLER.listCurrencyRates()
}

export function getDefaultCurrencyRate() {
return CURRENCY_RATE_HANDLER.getDefaultCurrencyRate()
}

export async function getCurrentPreferCurrency(): Promise<CurrencyRateDetail> {
const cfg = await getConfiguration()
if (!cfg) {
return getDefaultCurrencyRate()
return CURRENCY_RATE_HANDLER.getDefaultCurrencyRate()
}

const pc: string = cfg.configs.preferCurrency
if (!pc) {
return getDefaultCurrencyRate()
return CURRENCY_RATE_HANDLER.getDefaultCurrencyRate()
}

return getCurrencyRate(pc)
return CURRENCY_RATE_HANDLER.getCurrencyRateByCurrency(pc)
}

export async function getClientIDConfiguration(): Promise<string | undefined> {
Expand Down
10 changes: 5 additions & 5 deletions src/middlelayers/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { OthersAnalyzer } from './datafetch/coins/others'
import { SOLAnalyzer } from './datafetch/coins/sol'
import { ERC20ProAnalyzer } from './datafetch/coins/erc20'
import { CexAnalyzer } from './datafetch/coins/cex/cex'
import { ASSETS_PRICE_TABLE_NAME, ASSETS_TABLE_NAME, queryAllAssetPrices, queryHistoricalData } from './charts'
import { queryAllAssetPrices, queryHistoricalData } from './charts'
import _ from 'lodash'
import { save, open } from "@tauri-apps/api/dialog"
import { writeTextFile, readTextFile } from "@tauri-apps/api/fs"
import { AssetPriceModel, ExportAssetModel, HistoricalData } from './types'
import { saveModelsToDatabase } from './database'
import { exportConfigurationString, importRawConfiguration } from './configuration'
import { ASSET_HANDLER } from './entities/assets'
import { ASSET_PRICE_HANDLER } from './entities/asset-prices'

type ExportData = {
exportAt: string
Expand Down Expand Up @@ -169,7 +170,7 @@ async function saveHistoricalDataAssets(assets: ExportAssetModel[]) {
})
})

await saveModelsToDatabase(ASSETS_TABLE_NAME, assets)
await ASSET_HANDLER.saveAssets(assets)

// import asset prices
const importedAssets = _(await queryHistoricalData(-1, false)).map(d => d.assets).flatten().value()
Expand All @@ -192,6 +193,5 @@ async function saveHistoricalDataAssets(assets: ExportAssetModel[]) {
} as AssetPriceModel
}).compact().value()

await saveModelsToDatabase(ASSETS_PRICE_TABLE_NAME, assetPriceModels)

await ASSET_PRICE_HANDLER.savePrices(assetPriceModels)
}
53 changes: 6 additions & 47 deletions src/middlelayers/database.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import _ from "lodash"
import Database from "tauri-plugin-sql-api"
import { v4 as uuidv4 } from 'uuid'
import { CoinModel } from './datafetch/types'
import { AssetModel, WalletCoinUSD } from './types'
import { ASSETS_TABLE_NAME } from './charts'
import md5 from 'md5'

export const databaseName = "track3.db"

Expand All @@ -18,44 +13,6 @@ export async function getDatabase(): Promise<Database> {
return dbInstance
}

// skip where value is less than 1
export async function saveCoinsToDatabase(coins: WalletCoinUSD[]) {
const db = await getDatabase()

return saveAssetsToDatabase(db, _(coins).map(t => ({
wallet: t.wallet,
symbol: t.symbol,
amount: t.amount,
value: t.usdValue,
})).filter(v => v.value > 1).value())
}

// will auto skip models whose amount is 0
async function saveAssetsToDatabase(db: Database, models: CoinModel[]): Promise<AssetModel[]> {
const now = new Date().toISOString()
// generate uuid v4

const uid = uuidv4()

const getDBModel = (models: CoinModel[]) => {

return _(models).filter(m => m.amount !== 0).map(m => ({
createdAt: now,
uuid: uid,
symbol: m.symbol,
amount: m.amount,
value: m.value,
price: m.value / m.amount,
// md5 of wallet
wallet: md5(m.wallet),
} as AssetModel)).value()

}
const dbModels = getDBModel(models)

return saveToDatabase(db, ASSETS_TABLE_NAME, dbModels)
}

export async function saveModelsToDatabase<T extends object>(table: string, models: T[]) {
const db = await getDatabase()
return saveToDatabase(db, table, models)
Expand All @@ -66,11 +23,13 @@ async function saveToDatabase<T extends object>(db: Database, table: string, mod
return models
}

const first = models[0]
const filteredModes = _(models).map(m => _(m).omitBy(v => _(v).isUndefined()).value()).value()

const first = filteredModes[0]
const keys = Object.keys(first)
const valuesArrayStr = new Array(models.length).fill(`(${keys.map(() => '?').join(',')})`).join(',')
const insertSql = `INSERT INTO ${table} (${keys.join(',')}) VALUES ${valuesArrayStr}`
const values = _(models).map(m => _(keys).map(k => _(m).get(k)).value()).flatten().value()
const valuesArrayStr = new Array(filteredModes.length).fill(`(${keys.map(() => '?').join(',')})`).join(',')
const insertSql = `INSERT OR REPLACE INTO ${table} (${keys.join(',')}) VALUES ${valuesArrayStr}`
const values = _(filteredModes).map(m => _(keys).map(k => _(m).get(k)).value()).flatten().value()
await db.execute(insertSql, values)
return models
}
Expand Down
44 changes: 44 additions & 0 deletions src/middlelayers/entities/asset-prices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { deleteFromDatabase, saveModelsToDatabase, selectFromDatabase } from '../database'
import { AssetPriceModel } from '../types'

class AssetPriceHandler {
private readonly assetTableName = "asset_prices"

async createOrUpdate(model: AssetPriceModel): Promise<void> {
await saveModelsToDatabase(this.assetTableName, [model])
}

async listPrices(): Promise<AssetPriceModel[]> {
return selectFromDatabase<AssetPriceModel>(this.assetTableName, {})
}

async listPricesBySymbol(symbol: string): Promise<AssetPriceModel[]> {
return selectFromDatabase<AssetPriceModel>(this.assetTableName, { symbol })
}

async listPricesAfterAssetCreatedAt(assetCreatedAt?: string): Promise<AssetPriceModel[]> {
const plainWhere = assetCreatedAt ? 'assetCreatedAt > ?' : undefined
const values = assetCreatedAt ? [assetCreatedAt] : undefined
return selectFromDatabase<AssetPriceModel>(this.assetTableName, {}, undefined, undefined, plainWhere, values)
}

async listPricesAfterUpdatedAt(updatedAt?: string): Promise<AssetPriceModel[]> {
const plainWhere = updatedAt ? 'updatedAt > ?' : undefined
const values = updatedAt ? [updatedAt] : undefined
return selectFromDatabase<AssetPriceModel>(this.assetTableName, {}, undefined, undefined, plainWhere, values)
}

async deletePricesByUUID(uuid: string) {
await deleteFromDatabase(this.assetTableName, { uuid })
}

async deletePricesByAssetID(assetID: number) {
await deleteFromDatabase(this.assetTableName, { assetID })
}

async savePrices(models: AssetPriceModel[]) {
return saveModelsToDatabase(this.assetTableName, models)
}
}

export const ASSET_PRICE_HANDLER = new AssetPriceHandler()
Loading

0 comments on commit 6a5d526

Please sign in to comment.