flora-exception
Version:
An exception system for FQL.
266 lines (229 loc) • 6.77 kB
text/typescript
import {query, Select} from "faunadb"
import { FloraException, FloraExceptionI, IsException, GetExceptions } from "./Exception";
import { AddExceptionToStack, Raise, Reraise } from "./Raise";
import { FrontendYield } from "./Yield";
import {generate} from "shortid";
import { generateSlug } from "random-word-slugs";
import { $Number, $String } from "FloraTypes";
const {
Concat,
Map ,
If,
Var,
Lambda,
Format,
ToString,
Let
} = query;
export const FloraLocalState = {
performance : false
};
export const togglePerformance = (b : boolean)=>{
FloraLocalState.performance = b;
}
export interface FxArgI<T=any> {
0 : T,
1 ? : (obj : any)=>boolean
}
type FxArgExtractedT<T> = T extends FxArgI<infer X> ? X : never;
type FxExtractedArgsT<T extends FxArgI[]> = {
[key in keyof T] : FxArgExtractedT<T[key]>
}
const result = "result";
const arg = "arg";
const xarg = "xarg";
/**
* Extracts an arg from a TypePredicate tuple.
* @param arg
* @param loc
* @returns
*/
export const ExtractArg = <A extends FxArgI<any>>(arg : A, loc : string) : FxArgExtractedT<A>=>{
const predicateName = arg[1] ? arg[1].name||"$Unspecified" : "$Unspecified";
const Predicate = arg[1] ? arg[1] : ()=>true
let arg0 = "";
try {
arg0 = `${arg[0].toString().slice(0, 20)}...`;
} catch {
arg0 = "[failedToString]";
}
return Let(
{
[xarg] : arg[0],
[result] : If(
Predicate(Var(xarg)),
Var(xarg),
Raise(FloraException({
name : "TypeException",
msg : Concat(
[
`Argument does not match type ${predicateName}: Value {`,
Format('%@', Var(xarg)),
`} is not of type ${predicateName}`
]
) as unknown as string,
location : loc
}))
)
},
Var(result)
) as FxArgExtractedT<A>
}
/**
* Extracts args for a n array of TypePredicate tuples.
* @param args
* @param loc
* @returns
*/
export const ExtractArgs = <A extends FxArgI[]>(args : A, loc : string) : FxExtractedArgsT<A>=>{
return Map(
args,
Lambda(
arg,
ExtractArg(Var(arg) as unknown as FxArgI<any>, loc)
)
) as unknown as FxExtractedArgsT<A>
}
/**
* Extracts args from an array of type predicate Tuples on the client.
* @param args
* @param loc
* @returns
*/
export const extractArgs = <A extends FxArgI[]>(args : A, loc : string) : FxExtractedArgsT<A>=>{
return args.map((arg)=>{
return ExtractArg(arg, loc)
}) as FxExtractedArgsT<A>
}
export const stableExtractArgs = <A extends FxArgI[]>(args : A) : FxExtractedArgsT<A>=>{
return args.map((arg)=>{
return arg[0]
}) as FxExtractedArgsT<A>
}
export const getInstance = ()=>{
return `${generateSlug(1, {
format : "title",
partsOfSpeech : ["adjective",],
categories : {
adjective : ["personality"]
}
})}${generateSlug(1, {
format : "title",
partsOfSpeech : ["noun",],
categories : {
noun : ["animals"]
}
})}/${generate()}`
}
export const getLocation = (errorStack : string) : [string, string]=>{
const caller = errorStack.split("\n")[2].trim().split(" ")[1];
const _location = `${getInstance()}/${errorStack.split("\n").length}`
const mainLoaction =`${caller} $(${_location}/MAIN)`
const yieldLocation = `${caller} $(${_location}/YIELD(`
return [mainLoaction, yieldLocation]
}
const xargs = "xargs"
export const _Fx = <R extends (obj : any)=>boolean>(
resultQuery : GuardedT<R>,
location : [string, string],
$ReturnType : R,
returnName : string,
) : GuardedT<R>=>{
return Let(
{
[result] : resultQuery
},
If(
$ReturnType(
Var(result)
),
Var(result),
If(
IsException(
Var(result)
),
Var(result),
Raise(
FloraException({
name : "ReturnTypeExcpetion",
msg : Concat(
[
`Return does not match type ${returnName}: Value {`,
Format('%@', Var(result)),
`} is not of type ${returnName}`
]
) as unknown as string,
location : Select(0, location) as unknown as string
})
)
)
)
) as GuardedT<R>
}
export const _FxFunctionName = "_Fx-Flora-Exception";
export const DeployFx = () =>{
}
export const Call_Fx = ()=>{
}
/**
*
* @param args
* @param $ReturnType
* @param expr
* @returns
*/
export const Fx = <A extends FxArgI[], R extends (obj : any)=>boolean>(
args : A,
$ReturnType : R,
expr : (...args : FxExtractedArgsT<A>)=>GuardedT<R>
) : GuardedT<R> =>{
return expr(...stableExtractArgs(args));
/*const errorStack = new Error().stack || "";
const location = getLocation(errorStack);
const predicateName = $ReturnType ? $ReturnType.name||"$Unspecified" : "$Unspecified";
const resultQuery = FrontendYield({
name : Select(1, location) as unknown as string,
args :extractArgs(args, Select(0, location) as unknown as string),
expr : expr
});
return _Fx(
resultQuery,
location,
$ReturnType,
predicateName,
)*/
}
export type GuardedT<T> = T extends (obj: any) => obj is infer G ? G :any;
export type GuardedsT<T extends ((obj : any)=>obj is any)[]> = {
[key in keyof T] : GuardedT<T[key]>
}
const reguardArgs = (args :any[], argTypes : ((obj : any)=>obj is any)[]) : FxArgI[]=>{
return args.map((arg, index)=>{
return [
arg,
argTypes[index] ? argTypes[index] : ()=>true
]
}) as FxArgI[]
}
interface PredicateI<T> {
(obj : any) : obj is T
}
/**
* Factory for a Fx function.
* @param args
* @param $ReturnType
* @param expr
* @returns
*/
export const mFx = <A extends (PredicateI<any>)[], R extends (obj : any)=>boolean>(
$ArgTypes : A,
$ReturnType : R,
expr : (...args : GuardedsT<A>)=>GuardedT<R>
)=>(...args : GuardedsT<A>) : GuardedT<R> =>{
return expr(...args);
/*return Fx(
reguardArgs(args, $ArgTypes),
$ReturnType,
expr as (...args : any[])=>GuardedT<R>
)*/
}