oso-cloud
Version:
Oso Cloud Node.js Client SDK
177 lines • 8.88 kB
TypeScript
import { Fact, IntoFact, IntoValue, Oso, Value } from ".";
import { DefaultPolarTypes } from "./helpers";
import { QueryCall as ApiQueryCall, QueryConstraint, ConcreteFact } from "./api";
type AbstractType = "Actor" | "Resource";
type ConcreteType<T extends string> = T extends AbstractType ? never : T;
export type TypedVar<T extends string> = QueryVariable<ConcreteType<T>>;
/**
* Construct a new query variable of a specific type.
*
* @param type The actor/resource type of the variable to be created.
* Note: This must NOT be the "Actor" or "Resource" abstract types.
* To query for many types of results, make one request for each concrete
* type.
* @returns A new variable that can be used with `oso.buildQuery` APIs
*/
export declare function typedVar<T extends string>(type: ConcreteType<T>): QueryVariable<T>;
declare class QueryVariable<T extends string> {
private type;
private id;
constructor(type: T);
getId(): string;
getType(): string;
toString(): string;
}
type QueryValue<V extends Value> = IntoValue<V> | TypedVar<V["type"]>;
type QueryValues<A extends Value[]> = A extends [
infer HD extends Value,
...infer TL extends Value[]
] ? [QueryValue<HD>, ...QueryValues<TL>] : [];
export type QueryArgs<FQ extends Fact> = FQ extends [
infer P extends string,
...infer A extends Value[]
] ? [P, ...QueryValues<A>] : never;
type EvaluateArgItem = TypedVar<string> | [] | [EvaluateArgItem] | [EvaluateArgItem, EvaluateArgItem] | [EvaluateArgItem, EvaluateArgItem, EvaluateArgItem] | [EvaluateArgItem, EvaluateArgItem, EvaluateArgItem, EvaluateArgItem];
type EvaluateArg = undefined | EvaluateArgItem | Map<TypedVar<string>, EvaluateArg>;
type EvaluateTupleResult<A extends EvaluateArgItem[], Depth extends unknown[]> = 10 extends Depth["length"] ? never : A extends [
infer HD extends EvaluateArgItem,
...infer TL extends EvaluateArgItem[]
] ? [
EvaluateResultItem<HD, [unknown, ...Depth]>,
...EvaluateTupleResult<TL, [unknown, ...Depth]>
] : [];
type EvaluateResultItem<A extends EvaluateArgItem, Depth extends unknown[] = []> = A extends TypedVar<string> ? string : A extends EvaluateArgItem[] ? EvaluateTupleResult<A, Depth> : never;
type EvaluateResult<A extends EvaluateArg> = A extends undefined ? boolean : A extends EvaluateArgItem ? EvaluateResultItem<A>[] : A extends Map<TypedVar<string>, infer B extends EvaluateArg> ? Map<string, EvaluateResult<B>> : never;
/**
* Helper class to support building a custom Oso query.
*
* Initialize this with `oso.buildQuery` and chain calls to `and` and `in` to add additional constraints.
*
* After building your query, run it and get the results by calling `evaluate`.
*/
export declare class QueryBuilder<PT extends DefaultPolarTypes> {
private oso;
private predicate;
private calls;
private constraints;
private contextFacts;
constructor(oso: Oso<PT>, predicate: ApiQueryCall, calls?: ApiQueryCall[], constraints?: Map<string, QueryConstraint>, contextFacts?: ConcreteFact[]);
static init<PT extends DefaultPolarTypes>(oso: Oso<PT>, [predicate, ...args]: QueryArgs<PT["fact"] | PT["query"]>): QueryBuilder<PT>;
/**
* Add another condition that must be true of the query results.
* For example:
* ```typescript
* // Query for all the repos on which the given actor can perform the given action,
* // and require the repos to belong to the given folder
* const repo = typedVar("Repo");
* const authorizedReposInFolder = await oso
* .buildQuery(["allow", actor, action, repo])
* .and(["has_relation", repo, "folder", folder])
* .evaluate(repo);
* ```
* @param args The rule or fact constraint to add to the query
* @returns {QueryBuilder}
*/
and([predicate, ...args]: QueryArgs<PT["fact"] | PT["query"]>): QueryBuilder<PT>;
/**
* Constrain a query variable to be one of a set of values.
* For example:
* ```typescript
* const repos = ["acme", "anvil"];
* const repo = typedVar("Repo");
* const action = typedVar("String");
* // Get all the actions the actor can perform on the repos that are in the given set
* const authorizedActions = await oso
* .buildQuery(["allow", actor, action, repo])
* .in(repo, repos)
* .evaluate(action);
* ```
* @param {TypedVar} v The variable to constrain
* @param {string[]} values The set of allowed values for the constrained variable
* @returns {QueryBuilder}
*/
in<T extends string>(v: QueryVariable<T>, values: string[]): QueryBuilder<PT>;
/**
* Add context facts to the query.
* @param {IntoFact[]} contextFacts
* @returns {QueryBuilder}
*/
withContextFacts(contextFacts: IntoFact<PT["fact"]>[]): QueryBuilder<PT>;
/**
* Evaluate the query. The shape of the return value is determined by what you pass in:
* - If you pass no arguments, returns a boolean. For example:
* ```typescript
* // true if the given actor can perform the given action on the given resource
* let allowed = await oso.buildQuery(["allow", actor, action, resource]).evaluate();
* ```
* - If you pass a variable, returns a list of values for that variable. For example:
* ```typescript
* let action = typedVar("String");
* // all the actions the actor can perform on the given resource- eg. ["read", "write"]
* let actions = await oso.buildQuery(["allow", actor, action, resource]).evaluate(action);
* ```
* - If you pass a tuple of variables, returns a list of tuples of values for those variables.
For example:
* ```typescript
* let action = typedVar("String");
* let repo = typedVar("Repo");
* // an array of pairs of allowed actions and repo IDs- eg. [["read", "acme"], ["read", "anvil"], ["write", "anvil"]]
* let pairs = await oso.buildQuery(["allow", actor, action, repo]).evaluate([action, repo]);
* ```
* - If you pass a Map mapping one input variable (call it K) to another
* (call it V), returns a Map of unique values of K to the unique values of
* V for each value of K. For example:
* ```typescript
* let action = typedVar("String");
* let repo = typedVar("Repo");
* let map = await oso.buildQuery(["allow", actor, action, repo]).evaluate(new Map([[repo, action]]));
* // a map of repo IDs to allowed actions- eg. new Map(Object.entries({ "acme": ["read"], "anvil": ["read", "write"]}))
* ```
*
* @param arg See above
* @returns See above
*/
evaluate<Arg extends EvaluateArg = undefined>(arg?: Arg): Promise<EvaluateResult<Arg>>;
/**
* Fetches a complete SQL query that can be run against your database, selecting
* a row for each authorized combination of the query variables in `columnNamesToQueryVars`
* (ie. combinations of variables that satisfy the Oso query).
*
* See https://www.osohq.com/docs/app-integration/client-apis/node for examples and limitations.
*
* @param {Record<string, TypedVar<string>>?} columnNamesToQueryVars
* A mapping of the desired column names to the query variables whose values
* will be selected into those columns in the returned SQL query.
*
* If you pass an empty object or omit this parameter entirely, the returned SQL query
* will select a single row with a boolean column called `result`.
*
* @returns {Promise<string>} SQL query containing the desired columns
* @throws {TypeError} when columnNamesToQueryVars is empty or contains duplicate values
* @throws {Error}
*/
evaluateLocalSelect(columnNamesToQueryVars?: Record<string, TypedVar<string>>): Promise<string>;
/**
* Fetches a SQL fragment, which you can embed into the `WHERE` clause of a
* SQL query against your database to filter out unauthorized rows (ie. rows
* that don't satisfy the Oso query).
*
* See https://www.osohq.com/docs/app-integration/client-apis/node for examples and limitations.
*
* @param {string} columnName the name of the SQL column to filter
* @param {TypedVar<string>} queryVar the variable corresponding to the column to filter
* @returns {Promise<string>} SQL fragment, suitable for embedding in a `WHERE` clause
* @throws {Error}
*/
evaluateLocalFilter(columnName: string, queryVar: TypedVar<string>): Promise<string>;
private asQuery;
/**
* The query API expects all call args to be variable names. This method helps
* in this process by converting concrete arguments to temporary variables and
* returning the variable names.
*/
private pushArg;
private clone;
}
export {};
//# sourceMappingURL=query.d.ts.map