Created
March 14, 2024 13:11
-
-
Save doeixd/ab3d8179e838d0c144892e2cd777990b to your computer and use it in GitHub Desktop.
DCI TS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { A } from "solid-start"; | |
import Counter from "~/components/Counter"; | |
import capitalize from "lodash.capitalize" | |
import { match, P } from "ts-pattern"; | |
import { Err, Ok, Result, Option, Some, None } from "ts-results" | |
import type { Appearances, SubcaptionName, CaptionOverallScore, SubcaptionInitials, CaptionName, DciSeason, Competition } from "~/utils/api_types"; | |
import { Convert } from "~/utils/api_types"; | |
// import type Result from "ts-results" | |
export default function Home() { | |
return ( | |
<main class="text-center mx-auto text-gray-700 p-4"> | |
<h1 class="max-6-xs text-6xl text-sky-700 font-thin uppercase my-16"> | |
Hello world! | |
</h1> | |
</main> | |
); | |
} | |
type year = `20` | |
type tens_year_digits = `0` | `1` | `2` | |
type digits = `0` | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | `9` | |
type season_year = `${year}${tens_year_digits}${digits}` | |
type final_season_year = Exclude<season_year, '2000' | '2001' | '2002' | '2003' | '2004' | '2024' | '2025' | '2026' | '2027' | '2028' | '2029'> | |
type classes = `World` | `Open` | |
type seasons = classes | `Both` | |
class DCI_API { | |
base_url: "https://api.dci.org/v1"; | |
cache: Map<string, string> | |
constructor() { | |
this.base_url = 'https://api.dci.org/v1' | |
this.cache = new Map(); | |
this.get_season(); | |
// @ts-expect-error | |
if (!window?.dci_api) window.dci_api = this | |
} | |
async get<T = unknown>(path: string, searchParams = {}, {fetchOptions, parser}: {fetchOptions?: RequestInit | undefined, parser?: Fn<T>}): Promise<Result<T, Error>> { | |
let ret_val; | |
let key = path + JSON.stringify(searchParams) | |
const url = `${this.base_url}${path}` | |
const params = (Object.entries(searchParams).reduce((acc, cur) => { | |
let [param_name, param_value] = cur | |
param_name = param_name.replace('className', 'class') | |
param_value = | |
/world|open/i.test(param_value as string) | |
? capitalize((param_value as string).replace(/world|open/i, '$&+Class')) | |
: param_value | |
acc.append(param_name, `${param_value}`) | |
return acc | |
}, new URLSearchParams())).toString() | |
if (this.cache.has(key)) { | |
let val = this.cache.get(key) as T | |
return Ok(val) | |
} else { | |
return await _fetch(`${url}${params && `?${params}`}`, fetchOptions, parser) | |
} | |
} | |
get_season(className: seasons = 'Both', year: final_season_year = new Date().getFullYear().toString() as final_season_year) { | |
const season_url = `${this.base_url}/performances/corps-results` | |
const inner_get_season = | |
async (season: seasons = className, season_year: final_season_year = year) => { | |
return await this.get<DciSeason>(season_url, { className: season, season: season_year }, { parser: Convert.toDciSeason }) | |
} | |
let exp: AsyncFn<DciSeason> = async function() { | |
return match(className) | |
.with('Both', async () => { | |
let response = await Promise.all([inner_get_season('World'), inner_get_season('Open')]) | |
let transformed_response = response.map((o) => { | |
let val = o.expect('Unable to fetch season') | |
let ret = Object.entries(val) | |
return ret | |
}) | |
let season = Object.fromEntries(transformed_response) as DciSeason | |
return Promise.resolve(season) | |
}) | |
.otherwise(async () => { | |
let result = (await inner_get_season()).expect('Unable to fetch season') | |
return Promise.resolve(result) | |
}) | |
} | |
return aiife<DciSeason>(exp) | |
} | |
} | |
class Season { | |
className: seasons; | |
year: final_season_year; | |
data: any; | |
cache: Map<string, any>; | |
constructor(className: seasons = 'Both', year: final_season_year = new Date().getFullYear().toString() as final_season_year, data: any) { | |
this.className = className; | |
this.year = year; | |
this.data = data; | |
this.cache = new Map<string, any>(); | |
} | |
get_latest_scores(useCache = true) { | |
let result = []; | |
if (this.cache.has('latest_scores') && useCache) { return this.cache.get('latest_scores') } | |
for (let corps of Object.keys(this.data)) { | |
for (let comp of this.data[corps]) { | |
} | |
} | |
return this.cache.get('latest_scores') | |
} | |
get_rankings() { | |
} | |
} | |
interface Judge { | |
first_name: string; | |
last_name: string; | |
} | |
interface AllData { | |
data: Season, | |
} | |
interface Caption { | |
name: string; | |
initials: string; | |
} | |
interface SubcaptionScore { | |
} | |
interface JudgeScoreEntry { | |
judge: Judge, | |
number: number; | |
score: CaptionScore; | |
subcaption_score: CaptionScore; | |
} | |
interface ScoreRecord { | |
active: boolean; | |
isOtherType: boolean; | |
competitionGuid: string; | |
subtotalRank: number; | |
subtotalScore: number; | |
rank: number; | |
totalScore: number; | |
orgGroupIdentifier: string; | |
round: string | |
divisionName: string; | |
categories: []; | |
} | |
interface CaptionScore { | |
caption: string | Caption; | |
score: string; | |
rank: number; | |
} | |
interface Corps { | |
name: string; | |
id: string; | |
} | |
class URLBuilder { | |
base_url: string; | |
paths: object; | |
searchParams: object; | |
constructor(base_url: string, paths: object, searchParams: object) { | |
this.base_url = base_url; | |
this.paths = paths; | |
this.searchParams = searchParams; | |
return new Proxy(this, { | |
}) | |
} | |
// URLBuilder('dci.api').seasons.addParams({}) | |
addParam() { } | |
toString() { } | |
} | |
/// season = api.get_season('world', '2023') | |
/// season.get | |
// api.corps('Phantom Regiment').get_season(); | |
// api.corps('Phantom Regiment').get_competitions(); | |
// api.corps('Phantom Regiment').get_season().get_rankings(); | |
// api.get_season().competitions() | |
// api.season('World').rankings('Visual') | |
// api.season('World').get_rankings('Visual') | |
// api.competitions('asdfasdf').ranking() | |
async function _fetch<ReturnedType = unknown>(path: RequestInfo | URL, options?: RequestInit, parser?: Fn<ReturnedType>) { | |
return async_try<ReturnedType>(async () => await fetch(path, options) | |
.then(i => { | |
if (parser) return parser(i.text()) as ReturnedType | |
return i.json() as ReturnedType | |
}) | |
) | |
} | |
async function _make_fetcher<ReturnedType = unknown>(path: RequestInfo | URL, options?: RequestInit) { | |
type ReturnedParamObj = { | |
searchParams?: string | URLSearchParams | |
body?: unknown | |
} | |
return async (args: ReturnedParamObj) => { | |
let searchParams = args?.searchParams?.toString?.() || '' | |
let body = args?.body && JSON.stringify(args?.body) | |
let new_path = path + (searchParams && (`?` + searchParams)) | |
let new_options = Object.assign({}, options, body && { body }) | |
return await _fetch(new_path, new_options) | |
} | |
} | |
type CallbackParams<T> = T extends (...args: infer P) => any ? P : never; | |
type CallbackReturnType<T> = T extends (...args: any) => infer R ? R : never; | |
type AsyncCallbackReturnType<T> = Awaited<T extends (...args: any) => infer R ? R : never>; | |
type AsyncFn<Returns = Promise<unknown>> = | |
(...args: any[]) => Promise<Returns>; | |
type Fn<Returns = unknown> = | |
(...args: any[]) => Returns; | |
async function async_try<ReturnsOk, ReturnsError = Error>(fn: AsyncFn<ReturnsOk>): Promise<Result<AsyncCallbackReturnType<typeof fn>, ReturnsError>> { | |
try { | |
return Ok(await fn()) | |
} catch (err) { | |
return Err(err as ReturnsError); | |
} | |
} | |
function _try<ReturnsOk, ReturnsError = Error>(fn: Fn<ReturnsOk>): Result<CallbackReturnType<typeof fn>, ReturnsError> { | |
try { | |
return Ok(fn()) | |
} catch (err) { | |
return Err(err as ReturnsError); | |
} | |
} | |
const astr = async (): Promise<'hello'> => 'hello' | |
const str = async (): Promise<'hello'> => 'hello' | |
const test = await async_try(astr) | |
const test2 = await async_try(str) | |
function o<T>(value: T): Option<T> { | |
if (value) return Some(value) | |
return None | |
} | |
let test0 = o('happy') | |
const api = new DCI_API(); | |
let res = api.get_season() | |
let env: any; | |
const get_cache = async <Return, KeyType = string>(key: KeyType) => { | |
const data = await env.dci.get(key, { type: "json" }) | |
return data as Return | |
} | |
const set_cache = async (key: string, data: string | object) => { | |
if (typeof data === 'object' && data !== null) data = JSON.stringify(data) | |
if (typeof data === 'string' || (data as any) instanceof String) await env.dci.put(key, data) | |
return await get_cache(key) | |
} | |
async function save ({type, key, value}: {type: string, key: string, value: unknown}, metadata?: unknown) { | |
await env.dci.put(key, value, { | |
metadata: { type, metadata } | |
}) | |
} | |
async function list (prefix:string, limit?: number, cursor?: any) { | |
return await env.dci.list({prefix, limit, cursor}) | |
} | |
const Relation = { | |
create: async function ( | |
{from_key, to_key, from_name, to_name}: {from_key:string, to_key:string, from_name:string, to_name:string, from_type?: string, to_type?: string}, | |
data = {from: from_key, to: to_key, from_name, to_name, from_type: from_key.split('::')[0], to_type: to_key.split('::')[0]}, | |
metadata = {from: from_key, to: to_key, from_name, to_name} | |
) { | |
const from = `relation::from:${from_key}->to:${to_key}|using:${from_name}` | |
const to = `relation::to:${from_key}->from:${to_key}|using:${to_name}` | |
await save({type: "relation", key: from, value: data}, metadata) | |
await save({type: "relation", key: to, value: data}, metadata) | |
const from_type = `relationType::from:${data.from_type}->to:${data.to_type}|using:${from_name}|from_key:${from_key}->to_key:${to_key}` | |
const to_type = `relationType::to:${data.to_type}<-from:${data.from_type}|using:${to_name}|to_key:${to_key}<-from_key:${from_key}` | |
await save({type: "relationType", key: from_type, value: data}, data) | |
await save({type: "relationType", key: to_type, value: data}, data) | |
const arrow_from_name = `relationArrow::${from_name}:from_type:${data.from_type}->to_type:${data.to_type}|from_key:${from_key}->to_key:${to_key}` | |
const arrow_to_name = `relationArrow::${to_name}:to_type:${data.to_type}<-from_type:${data.from_type}|to_key:${to_key}<-from_key:${from_key}` | |
await save({type: "relationArrow", key: arrow_from_name, value: data}, metadata) | |
await save({type: "relationArrow", key: arrow_to_name, value: data}, metadata) | |
}, | |
find: async function (args: { from_type?: string, to_type?: string, from_key?: string, to_key?: string, using?: string, where?: Fn } ) { | |
const call = (data: any) => { | |
if (args?.where) { | |
return args.where(data) | |
} | |
return data | |
} | |
if (args?.from_key) { | |
const type_from_key = args.from_key.split('::')[0] | |
if (args?.to_key) { | |
if (args?.using) { | |
return call(await get_cache(`relation::from:${args.from_key}->to:${args.to_key}|using:${args.using}`)) | |
} | |
return call(await list(`relation::from:${args.from_key}->to:${args.to_key}`)) | |
} | |
if (args?.to_type) { | |
if (args?.using) { | |
return call(await list(`relationArrow::${args.using}:from_type:${type_from_key}->to_type:${args.to_type}|from_key:${args.from_key}`)) | |
} | |
return call(await list(`relation::from:${args.from_key}->to:${args.to_type}`)) | |
} | |
} | |
if(args?.from_type) { | |
if (args?.to_key) { | |
const type_from_key = args.to_key.split('::')[0] | |
if (args?.using) { | |
return call(await list(`relationType::to:${args.to_type}<-from:${args.from_type}|using:${args.using}|to_key:${type_from_key}`)) | |
} | |
return call(await list(`relation::to:${args.to_key}->from:${args.from_type}`)) | |
} | |
if (args?.to_type) { | |
if (args?.using) { | |
return call(await list(`relationArrow::${args.using}:from_type:${args.from_type}->to_type:${args.to_type}`)) | |
} | |
return call(await list(`relationType::from:${args.from_type}->to:${args.to_type}`)) | |
} | |
} | |
} | |
} | |
function makeType(type: string, fn = (i: unknown) => i) { | |
let prefix = type | |
return { | |
save: async function (key: string | string[], value: object) { | |
key = [key].flat() | |
let made_key = [prefix, ...key].join('::') | |
await save({ type, key: made_key, value }) | |
return [made_key, fn(value)] | |
}, | |
get: async function (key: string | string[], as = 'json') { | |
key = [key].flat() | |
let made_key = [prefix, ...key].join('::') | |
return fn(await env.dci.get(made_key, { type: as })) | |
}, | |
list: async function ({ suffix, limit, cursor }: { suffix: string; limit?: number; cursor: any }) { | |
return await env.dci.list({ prefix: [prefix, suffix].join('::'), limit, cursor }) | |
}, | |
} | |
} | |
class KVType<SaveType = object> { | |
type: string | |
prefix: string | |
initial_key: string[] | string | undefined; | |
key: string | undefined; | |
constructor(name: string, key?: string | string[]) { | |
key &&= [key].flat() | |
key &&= [name + ':', ...key].join(':') | |
this.prefix = name | |
this.type = name | |
this.initial_key = key | |
this.key = key | |
} | |
async save<R = any>(key: string | string[], value: SaveType, fn = (i: unknown) => i): Promise<any> { | |
let data; | |
if (!value && this.key) { | |
data = key | |
key = this.key | |
} else { | |
data = value | |
} | |
let made_key = _key(key,this.prefix) | |
await save({ type: this.type, key: made_key, value: data}) | |
return [made_key, fn(data)] | |
} | |
async get(key: string | string[], as = 'json', fn = (i: unknown) => i) { | |
key = [key].flat() | |
let made_key = [this.prefix, ...key].join('::') | |
return fn(await env.dci.get(made_key, { type: as })) | |
} | |
async list ({ suffix, limit, cursor }: { suffix: string; limit?: number; cursor: any }) { | |
return await env.dci.list({ prefix: [this.prefix, suffix].join('::'), limit, cursor }) | |
} | |
async relate (args: {using: string; to_type?: string; to_key?: string, to_name?: string, from_key?: string}) { | |
if (this?.key) { | |
if (args?.to_key) { | |
await Relation.create({ | |
from_key: this.key, | |
to_key: args.to_key, | |
from_name: args.using, | |
to_name: args?.to_name || args.using | |
}) | |
} | |
} | |
if(args?.to_key && args?.from_key && this?.prefix) { | |
await Relation.create({ | |
from_key: _key(args.from_key, this?.prefix), | |
to_key: args?.to_key, | |
from_name: args.using, | |
to_name: args?.to_name || args.using | |
}) | |
} | |
} | |
} | |
Relation.find({ | |
from_key: "Corps:SCV", | |
to_type: "Competition", | |
using: "Performed-in", | |
where: (key) => key == "SCV" | |
}) | |
function _key(key: string | string[], prefix?: string): string { | |
key = [key].flat(); | |
key.join(':') | |
prefix = prefix ? prefix + '::' : '' | |
return prefix + key | |
} | |
// class Corps { | |
// name: string; | |
// id: string; | |
// constructor(corps_obj) { | |
// this.name = corps_obj.groupName | |
// this.id = corps_obj.orgGroupIdentifier | |
// save({ type: 'Corps', name, id }) | |
// } | |
// } | |
interface Show extends Competition { | |
id: string, | |
year: string, | |
} | |
let SeasonKV = new KVType<{id: string}>('Season') | |
let CorpsKV = new KVType<Corps>('Corps') | |
let AppearanceKV = new KVType<Appearances>('Appearance') | |
let ShowKV = new KVType<Show>('Show') | |
let CaptionKV = new KVType<{name: CaptionName}>('Caption') | |
let SubcaptionKV = new KVType<{name: SubcaptionName, initials: Lowercase<SubcaptionInitials> }>('Caption') | |
interface CorpsOverallScore { | |
total: number; | |
subtotal: number; | |
rank: number; | |
subtotal_rank: number; | |
corps: string; | |
corpsID: string; | |
show: string; | |
} | |
let CorpsOverallScoreKV = new KVType<CorpsOverallScore>('ShowOverallScore') | |
interface CaptionScoreKV extends CaptionScore { | |
corps: string; | |
show: string; | |
season: string; | |
} | |
let CaptionScoreKV = new KVType<CaptionScoreKV>('CaptionScore') | |
interface JudgesScoreKV extends CaptionScore { | |
corps: string | |
show: string; | |
season: string; | |
judge: string; | |
judge_number: number; | |
breakdown: SubcaptionOverallScoreLowercase[]; | |
caption: CaptionName; | |
subcaption: SubcaptionName; | |
} | |
let JudgesScoreKV = new KVType<JudgesScoreKV>('JudgesScore') | |
let JudgeKV = new KVType<{ | |
first_name: string, | |
last_name: string, | |
full_name: string, | |
}>('Judge') | |
interface SubcaptionOverallScoreLowercase extends Omit<CaptionOverallScore, 'initials'> { | |
initials: Lowercase<SubcaptionInitials>; | |
} | |
interface SubcaptionScoreBreakdown extends Omit<Caption, 'initials'> { | |
initials: Lowercase<SubcaptionInitials> | undefined; | |
corps: string; | |
judge_name?: string; | |
judge_number: number; | |
show: string; | |
subcaption: SubcaptionName; | |
season: string; | |
score: string; | |
rank: number; | |
} | |
let SubcaptionScoreBreakdownKV = new KVType<SubcaptionScoreBreakdown>('SubcaptionScoreBreakdown') | |
let Show = makeType('Show') | |
async function ingest() { | |
const season = api.get_season() | |
const recaps = {} | |
for (let corps_name of Object.keys(season)) { | |
const corps_season = season[corps_name] | |
const [corps_key] = await CorpsKV.save(corps_name, {name: corps_name, id: corps_season[0].orgGroupIdentifier}) | |
for (let appearance of corps_season) { | |
const season_year = appearance.competition.seasonName | |
const [season_key] = await SeasonKV.save(season_year, {id: season_year}) | |
const [appearance_key] = await AppearanceKV.save([season_year, appearance.competitionGUID, appearance.orgGroupIdentifier], appearance) | |
await Relation.create({ | |
from_key: season_key, | |
to_key: appearance_key, | |
from_name: 'had_appearance', | |
to_name: 'apart_of_season' | |
}) | |
const [show_key] = await ShowKV.save([appearance.competitionGUID, season_year], { id: appearance.competitionGUID, year: season_year, ...appearance.competition }) | |
await Relation.create({from_key: show_key, to_key: appearance_key, from_name: 'apart_of_appearance', to_name: 'apart_of_show'}) | |
await Relation.create({from_key: show_key, to_key: season_key, from_name: 'apart_of_season', to_name: 'apart_of_season'}) | |
await Relation.create({ | |
from_key: corps_key, | |
to_key: show_key, | |
from_name: 'appeared_at', | |
to_name: 'appeared_at' | |
}) | |
const [corps_overall_score_key] = await CorpsOverallScoreKV.save([appearance.orgGroupIdentifier, appearance.competitionGUID], { | |
total: appearance.totalScore, | |
subtotal: appearance.subtotalScore, | |
rank: appearance.rank, | |
subtotal_rank: appearance.subtotalRank, | |
corps: corps_name, | |
corpsID: appearance.orgGroupIdentifier, | |
show: appearance.competitionGUID | |
}) | |
await Relation.create({ | |
from_key: corps_key, | |
to_key: corps_overall_score_key, | |
from_name: 'received_score', | |
to_name: 'received_score' | |
}) | |
for (let caption_score of appearance.categories) { | |
const [caption_key] = await CaptionKV.save(caption_score.name, {name: caption_score.name}) | |
const [caption_score_key] = await CaptionScoreKV.save([corps_name, appearance.competitionGUID, caption_score.name, season_year], { | |
caption: caption_score.name, | |
score: caption_score.score, | |
rank: caption_score.rank, | |
corps: corps_name, | |
show: appearance.competitionGUID, | |
season: season_year, | |
}) | |
await Relation.create({from_key: caption_key, to_key: caption_score_key, from_name: 'score', to_name: 'belongs_to_caption'}) | |
await Relation.create({from_key: caption_score_key, to_key: corps_key, from_name: 'belongs_to', to_name: 'received_score'}) | |
if (caption_score.captions) { | |
for (let judges_score of caption_score.captions) { | |
let judge = (judges_score.judgeFirstName || 'unknown') +' ' + (judges_score.judgeLastName || 'unknown') | |
const [judge_key] = await JudgeKV.save(judge, { | |
full_name: judge, | |
first_name: judges_score.judgeFirstName || 'unknown', | |
last_name: judges_score.judgeLastName || 'unknown', | |
}) | |
const [subcaption_key] = await SubcaptionKV.save(judges_score.name, {name: judges_score.name, initials: judges_score.initials.toLowerCase() as Lowercase<SubcaptionInitials>}) | |
await Relation.create({ | |
from_key: show_key, | |
to_key: judge_key, | |
from_name: 'judged_at', | |
to_name: 'judged_at' | |
}) | |
await Relation.create({ | |
from_key: judge_key, | |
to_key: corps_key, | |
from_name: 'judged', | |
to_name: 'was_judged_by', | |
}) | |
await Relation.create({ | |
from_key: judge_key, | |
to_key: corps_key, | |
from_name: 'judged', | |
to_name: 'was_judged_by', | |
}) | |
await Relation.create({ | |
from_key: judge_key, | |
to_key: subcaption_key, | |
from_name: 'judged_subcaption', | |
to_name: 'judged_subcaption', | |
}) | |
const breakdown_keys: string[] = [] | |
const breakdown: SubcaptionOverallScoreLowercase[] = []; | |
for (let subcaption_score_breakdown of judges_score.subcaptions) { | |
let build: unknown = {...subcaption_score_breakdown} | |
Object.defineProperty(build, 'initials', subcaption_score_breakdown?.initials?.toLowerCase?.() as Lowercase<SubcaptionInitials> ?? '') | |
build = build as SubcaptionOverallScoreLowercase | |
breakdown.push(build as SubcaptionOverallScoreLowercase) | |
const [subcaption_score_breakdown_key] = await SubcaptionScoreBreakdownKV.save( | |
[corps_name, appearance.competitionGUID, caption_score.name, judges_score.initials, subcaption_score_breakdown.initials ?? 'unknown' , season_year ], | |
{ | |
initials: subcaption_score_breakdown?.initials ? (subcaption_score_breakdown.initials?.toLowerCase() as Lowercase<SubcaptionInitials>) : undefined, | |
corps: corps_name, | |
judge_name: judge, | |
judge_number: judges_score.judge, | |
show: appearance.competitionGUID, | |
subcaption: judges_score.name, | |
season: season_year, | |
score: subcaption_score_breakdown.score, | |
rank: subcaption_score_breakdown.rank, | |
name: subcaption_score_breakdown.name | |
} | |
) | |
breakdown_keys.push(subcaption_score_breakdown_key) | |
} | |
const [judges_score_key] = await JudgesScoreKV.save([corps_name, appearance.competitionGUID, caption_score.name, judges_score.initials, judge, season_year], { | |
judge, | |
judge_number: judges_score.judge, | |
score: judges_score.score, | |
caption: caption_score.name, | |
subcaption: judges_score.name, | |
corps: corps_name, | |
season: season_year, | |
breakdown, | |
rank: judges_score.rank, | |
show: appearance.competitionGUID, | |
}) | |
await Relation.create({ | |
from_key: judges_score_key, | |
to_key: corps_key, | |
from_name: 'for_corps', | |
to_name: 'received_score', | |
}) | |
await Relation.create({ | |
from_key: judges_score_key, | |
to_key: caption_score_key, | |
from_name: 'contributed_to', | |
to_name: 'contributed_to', | |
}) | |
await Relation.create({ | |
from_key: caption_score_key, | |
to_key: corps_overall_score_key, | |
from_name: 'contributed_to', | |
to_name: 'contributed_to', | |
}) | |
for (let breakdown_key of breakdown_keys) { | |
await Relation.create({ | |
from_key: breakdown_key, | |
to_key: judges_score_key, | |
from_name: 'apart_of_judges_breakdown', | |
to_name: 'apart_of_breakdown', | |
}) | |
await Relation.create({ | |
from_key: breakdown_key, | |
to_key: subcaption_key, | |
from_name: 'breakdown_for', | |
to_name: 'breakdown_for', | |
}) | |
} | |
} | |
} | |
} | |
// let corps_score = { | |
// show: 'adfasfd' | |
// corps: 'SCV', | |
// date: '' | |
// total: 100, | |
// subtotal: 100, | |
// captions: { | |
// visual: { | |
// total: 55, | |
// subcaptions: { | |
// }, | |
// } | |
// } | |
// judges: { | |
// }, | |
// } | |
} | |
} | |
} | |
function aiife<ReturnedType>(fn: AsyncFn<ReturnedType>) { | |
let result; | |
((async function (){ | |
result = await fn() | |
})()) | |
return result as ReturnedType | |
} | |
function destr<OutputType>(obj: object, ...keys:any[]) { | |
return Object.entries(obj).reduce((acc, [key, value]) => { | |
// @ts-expect-error | |
if (keys.includes(key)) acc[key] = value | |
return acc | |
}, {}) as OutputType | |
} | |
async function wait(ms, fn) { | |
return new Promise((resolve)=>{ | |
setTimeout(() => resolve(fn().then(l => l)), ms) | |
}) | |
} | |
async function retry (fn, {sleep = 150, totalTimes = 20, times = totalTimes}) { | |
console.log({times}) | |
if (times > 0) { | |
try { | |
result = await fn() | |
} catch (e) { | |
return await wait(sleep || 150, async () => await retry(fn, {times: times - 1, sleep})) | |
} | |
} | |
} | |
async function toError() { | |
throw 'hello' | |
} | |
async function main() { | |
await retry(toError) | |
} | |
main().then(l => l) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment