🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

@chiselstrike/api

Package Overview
Dependencies
Maintainers
3
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chiselstrike/api - npm Package Compare versions

Comparing version

to
0.7.0

131

lib/chisel.d.ts
/// <reference lib="dom" />
declare type column = [string, string];
declare class Base {
columns: column[];
limit?: number;
constructor(columns: column[]);
declare enum OpType {
BaseEntity = "BaseEntity",
Take = "Take",
ColumnsSelect = "ColumnsSelect",
RestrictionFilter = "RestrictionFilter",
PredicateFilter = "PredicateFilter"
}
declare class BackingStore extends Base {
name: string;
readonly kind = "BackingStore";
constructor(columns: column[], name: string);
/**
* Base class for various Operators applicable on `ChiselCursor`. Each operator
* should extend this class and pass on its `type` identifier from the `OpType`
* enum.
*/
declare abstract class Operator {
readonly type: OpType;
readonly inner: Operator | undefined;
constructor(type: OpType, inner: Operator | undefined);
/** Applies specified Operator `op` on each element of passed iterable
* `iter` creating a new iterable.
*/
abstract apply(iter: AsyncIterable<Record<string, unknown>>): AsyncIterable<Record<string, unknown>>;
}
declare class Join extends Base {
left: Inner;
right: Inner;
readonly kind = "Join";
constructor(columns: column[], left: Inner, right: Inner);
}
declare class Filter extends Base {
restrictions: Record<string, unknown>;
inner: Inner;
readonly kind = "Filter";
constructor(columns: column[], restrictions: Record<string, unknown>, inner: Inner);
}
declare type Inner = BackingStore | Join | Filter;
/** ChiselCursor is a lazy iterator that will be used by ChiselStrike to construct an optimized query. */
export declare class ChiselCursor<T> {
private type;
private baseConstructor;
private inner;
constructor(type: {
constructor(baseConstructor: {
new (): T;
} | undefined, inner: Inner);
}, inner: Operator);
/** Force ChiselStrike to fetch just the `...columns` that are part of the colums list. */
select(...columns: (keyof T)[]): ChiselCursor<Pick<T, (keyof T)>>;
/** Restricts this cursor to contain only at most `limit_` elements */
take(limit_: number): ChiselCursor<T>;
/** Restricts this cursor to contain just the objects that match the `Partial` object `restrictions`. */
/** Restricts this cursor to contain only at most `count` elements */
take(count: number): ChiselCursor<T>;
/**
* Restricts this cursor to contain only elements that match the given @predicate.
*/
filter(predicate: (arg: T) => boolean): ChiselCursor<T>;
/**
* Restricts this cursor to contain just the objects that match the `Partial`
* object `restrictions`.
*/
filter(restrictions: Partial<T>): ChiselCursor<T>;
/** Joins two ChiselCursors, by matching on the properties of the elements in their cursors. */
join<U>(right: ChiselCursor<U>): ChiselCursor<T & U>;
/** Executes the function `func` for each element of this cursor. */

@@ -49,20 +51,19 @@ forEach(func: (arg: T) => void): Promise<void>;

/** ChiselCursor implements asyncIterator, meaning you can use it in any asynchronous context. */
[Symbol.asyncIterator](): {
next(): Promise<{
value: T;
done: false;
} | {
done: true;
}>;
return(): {
value: T;
done: false;
} | {
done: true;
};
};
[Symbol.asyncIterator](): AsyncGenerator<Awaited<T>, void, unknown>;
/** Performs recursive descent via Operator.inner examining the whole operator
* chain. If PredicateFilter is encountered, a backend query is generated and all consecutive
* operations are applied on the resulting async iterable in TypeScript. In such a
* case, the function returns the resulting AsyncIterable.
* If no PredicateFilter is found, undefined is returned.
*/
private makeTransformedQueryIter;
private makeQueryIter;
/** Recursively examines operator chain searching for ColumnsSelect operator.
* Returns true if found, false otherwise.
*/
private containsSelect;
}
export declare function chiselIterator<T>(type: {
new (): T;
}, c?: column[]): ChiselCursor<T>;
}): ChiselCursor<T>;
/** ChiselEntity is a class that ChiselStrike user-defined entities are expected to extend.

@@ -79,3 +80,4 @@ *

*
* @param properties The properties of the created entity.
* @param properties The properties of the created entity. If more than one property
* is passed, the expected order of assignment is the same as Object.assign.
*

@@ -94,5 +96,10 @@ * @example

*
* // Create an entity from different JSON objects:
* const otherUserJson = JSON.parse('{"username": "alice"}, {"email": "alice@example.com"}');
* const yetAnotherUser = User.build(userJson);
*
* // now optionally save them to the backend
* await user.save();
* await anotherUser.save();
* await yetAnotherUser.save();
* ```

@@ -103,3 +110,3 @@ * @returns The persisted entity with given properties and the `id` property set.

new (): T;
}, properties: Record<string, unknown>): T;
}, ...properties: Record<string, unknown>[]): T;
/** saves the current object into the backend */

@@ -123,2 +130,20 @@ save(): Promise<void>;

}, restrictions: Partial<T>): Promise<T | null>;
/**
* Deletes all entities that match the `restrictions` object.
*
* @example
* ```typescript
* export class User extends ChiselEntity {
* username: string,
* email: string,
* }
* const user = User.build({ username: "alice", email: "alice@example.com" });
* await user.save();
*
* await User.delete({ email: "alice@example.com"})
* ```
*/
static delete<T extends ChiselEntity>(this: {
new (): T;
}, restrictions: Partial<T>): Promise<void>;
}

@@ -129,6 +154,18 @@ export declare class OAuthUser extends ChiselEntity {

export declare function buildReadableStreamForBody(rid: number): ReadableStream<string>;
/**
* Gets a secret from the environment
*
* To allow a secret to be used, the server has to be run with * --allow-env <YOUR_SECRET>
*
* In development mode, all of your environment variables are accessible
*/
declare type JSONValue = string | number | boolean | null | {
[x: string]: JSONValue;
} | Array<JSONValue>;
export declare function getSecret(key: string): JSONValue | undefined;
export declare function responseFromJson(body: unknown, status?: number): Response;
export declare function labels(..._val: string[]): <T>(_target: T, _propertyName: string) => void;
export declare function unique(): void;
/** Returns the currently logged-in user or null if no one is logged in. */
export declare function loggedInUser(): Promise<OAuthUser | null>;
export {};
// SPDX-FileCopyrightText: © 2021 ChiselStrike <info@chiselstrike.com>
/// <reference path="lib.deno_core.d.ts" />
class Base {
columns;
limit;
constructor(columns) {
this.columns = columns;
/// <reference types="./lib.deno_core.d.ts" />
/// <reference lib="dom" />
var OpType;
(function (OpType) {
OpType["BaseEntity"] = "BaseEntity";
OpType["Take"] = "Take";
OpType["ColumnsSelect"] = "ColumnsSelect";
OpType["RestrictionFilter"] = "RestrictionFilter";
OpType["PredicateFilter"] = "PredicateFilter";
})(OpType || (OpType = {}));
/**
* Base class for various Operators applicable on `ChiselCursor`. Each operator
* should extend this class and pass on its `type` identifier from the `OpType`
* enum.
*/
class Operator {
type;
inner;
constructor(type, inner) {
this.type = type;
this.inner = inner;
}
}
// This represents a selection of some columns of a table in a DB.
class BackingStore extends Base {
/**
* Specifies Entity whose elements are to be fetched.
*/
class BaseEntity extends Operator {
name;
// The kind member is use to implement fully covered switch statements.
kind = "BackingStore";
constructor(columns, name) {
super(columns);
constructor(name) {
super(OpType.BaseEntity, undefined);
this.name = name;
}
apply(_iter) {
throw new Error("can't apply BaseEntity operator on an iterable");
}
}
// This represents an inner join between two chiselIterators.
// FIXME: Add support for ON.
class Join extends Base {
left;
right;
kind = "Join";
constructor(columns, left, right) {
super(columns);
this.left = left;
this.right = right;
/**
* Take operator takes first `count` elements from a collection.
* The rest is ignored.
*/
class Take extends Operator {
count;
constructor(count, inner) {
super(OpType.Take, inner);
this.count = count;
}
apply(iter) {
const count = this.count;
return {
[Symbol.asyncIterator]: async function* () {
if (count == 0) {
return;
}
let i = 0;
for await (const e of iter) {
yield e;
if (++i >= count) {
break;
}
}
},
};
}
}
class Filter extends Base {
/**
* Forces fetch of just the `columns` (fields) of a given entity.
*/
class ColumnsSelect extends Operator {
columns;
constructor(columns, inner) {
super(OpType.ColumnsSelect, inner);
this.columns = columns;
}
apply(iter) {
const columns = this.columns;
return {
[Symbol.asyncIterator]: async function* () {
for await (const arg of iter) {
const newObj = {};
for (const key of columns) {
if (arg[key] !== undefined) {
newObj[key] = arg[key];
}
}
yield newObj;
}
},
};
}
}
/**
* PredicateFilter operator applies @predicate on each element and keeps
* only those for which the @predicate returns true.
*/
class PredicateFilter extends Operator {
predicate;
constructor(predicate, inner) {
super(OpType.PredicateFilter, inner);
this.predicate = predicate;
}
apply(iter) {
const predicate = this.predicate;
return {
[Symbol.asyncIterator]: async function* () {
for await (const arg of iter) {
if (predicate(arg)) {
yield arg;
}
}
},
};
}
}
/**
* RestrictionFilter operator applies `restrictions` on each element
* and keeps only those where field value of a field, specified
* by restriction key, equals to restriction value.
*/
class RestrictionFilter extends Operator {
restrictions;
inner;
kind = "Filter";
constructor(columns, restrictions, inner) {
super(columns);
constructor(restrictions, inner) {
super(OpType.RestrictionFilter, inner);
this.restrictions = restrictions;
this.inner = inner;
}
apply(iter) {
const restrictions = Object.entries(this.restrictions);
return {
[Symbol.asyncIterator]: async function* () {
for await (const arg of iter) {
verifyMatch: {
for (const [key, value] of restrictions) {
if (arg[key] != value) {
break verifyMatch;
}
}
yield arg;
}
}
},
};
}
}
/** ChiselCursor is a lazy iterator that will be used by ChiselStrike to construct an optimized query. */
export class ChiselCursor {
type;
baseConstructor;
inner;
constructor(type, inner) {
this.type = type;
constructor(baseConstructor, inner) {
this.baseConstructor = baseConstructor;
this.inner = inner;

@@ -52,63 +154,16 @@ }

select(...columns) {
const names = columns;
const cs = this.inner.columns.filter((c) => names.includes(c[0]));
switch (this.inner.kind) {
case "BackingStore": {
const b = new BackingStore(cs, this.inner.name);
return new ChiselCursor(undefined, b);
}
case "Join": {
const i = new Join(cs, this.inner.left, this.inner.right);
return new ChiselCursor(undefined, i);
}
case "Filter": {
const i = new Filter(cs, this.inner.restrictions, this.inner.inner);
return new ChiselCursor(undefined, i);
}
}
return new ChiselCursor(this.baseConstructor, new ColumnsSelect(columns, this.inner));
}
/** Restricts this cursor to contain only at most `limit_` elements */
take(limit_) {
const limit = (this.inner.limit == null)
? limit_
: Math.min(limit_, this.inner.limit);
// shallow copy okay because this is an array of strings
const cs = [...this.inner.columns];
// FIXME: refactor to use the same path as select
switch (this.inner.kind) {
case "BackingStore": {
const i = new BackingStore(cs, this.inner.name);
i.limit = limit;
return new ChiselCursor(this.type, i);
}
case "Join": {
const i = new Join(cs, this.inner.left, this.inner.right);
i.limit = limit;
return new ChiselCursor(this.type, i);
}
case "Filter": {
const i = new Filter(cs, this.inner.restrictions, this.inner.inner);
i.limit = limit;
return new ChiselCursor(this.type, i);
}
}
/** Restricts this cursor to contain only at most `count` elements */
take(count) {
return new ChiselCursor(this.baseConstructor, new Take(count, this.inner));
}
/** Restricts this cursor to contain just the objects that match the `Partial` object `restrictions`. */
filter(restrictions) {
const i = new Filter(this.inner.columns, restrictions, this.inner);
return new ChiselCursor(this.type, i);
}
/** Joins two ChiselCursors, by matching on the properties of the elements in their cursors. */
join(right) {
const s = new Set();
const columns = [];
for (const c of this.inner.columns.concat(right.inner.columns)) {
if (s.has(c[0])) {
continue;
}
s.add(c[0]);
columns.push(c);
// Common implementation for filter overloads.
filter(arg1) {
if (typeof arg1 == "function") {
return new ChiselCursor(this.baseConstructor, new PredicateFilter(arg1, this.inner));
}
const i = new Join(columns, this.inner, right.inner);
return new ChiselCursor(undefined, i);
else {
return new ChiselCursor(this.baseConstructor, new RestrictionFilter(arg1, this.inner));
}
}

@@ -126,3 +181,3 @@ /** Executes the function `func` for each element of this cursor. */

async toArray() {
const arr = new Array();
const arr = [];
for await (const t of this) {

@@ -134,35 +189,80 @@ arr.push(t);

/** ChiselCursor implements asyncIterator, meaning you can use it in any asynchronous context. */
[Symbol.asyncIterator]() {
const rid = Deno.core.opSync("chisel_relational_query_create", this.inner);
const ctor = this.type;
async *[Symbol.asyncIterator]() {
let iter = this.makeTransformedQueryIter(this.inner);
if (iter === undefined) {
iter = this.makeQueryIter(this.inner);
}
for await (const it of iter) {
yield it;
}
}
/** Performs recursive descent via Operator.inner examining the whole operator
* chain. If PredicateFilter is encountered, a backend query is generated and all consecutive
* operations are applied on the resulting async iterable in TypeScript. In such a
* case, the function returns the resulting AsyncIterable.
* If no PredicateFilter is found, undefined is returned.
*/
makeTransformedQueryIter(op) {
if (op.type == OpType.BaseEntity) {
return undefined;
}
else if (op.inner === undefined) {
throw new Error("internal error: expected inner operator, got undefined");
}
let iter = this.makeTransformedQueryIter(op.inner);
if (iter !== undefined) {
return op.apply(iter);
}
else if (op.type == OpType.PredicateFilter) {
iter = this.makeQueryIter(op.inner);
return op.apply(iter);
}
else {
return undefined;
}
}
makeQueryIter(op) {
const ctor = this.containsSelect(op) ? undefined : this.baseConstructor;
return {
async next() {
const properties = await Deno.core.opAsync("chisel_relational_query_next", rid);
if (properties) {
if (ctor) {
const result = new ctor();
Object.assign(result, properties);
return { value: result, done: false };
[Symbol.asyncIterator]: async function* () {
const rid = Deno.core.opSync("chisel_relational_query_create", op);
try {
while (true) {
const properties = await Deno.core.opAsync("chisel_relational_query_next", rid);
if (properties == undefined) {
break;
}
if (ctor !== undefined) {
const result = new ctor();
Object.assign(result, properties);
yield result;
}
else {
yield properties;
}
}
else {
return { value: properties, done: false };
}
}
else {
finally {
Deno.core.opSync("op_close", rid);
return { done: true };
}
},
return() {
Deno.core.opSync("op_close", rid);
return { done: true };
},
};
}
/** Recursively examines operator chain searching for ColumnsSelect operator.
* Returns true if found, false otherwise.
*/
containsSelect(op) {
if (op.type == OpType.ColumnsSelect) {
return true;
}
else if (op.inner === undefined) {
return false;
}
else {
return this.containsSelect(op.inner);
}
}
}
export function chiselIterator(type, c) {
const columns = (c != undefined)
? c
: Deno.core.opSync("chisel_introspect", { "name": type.name });
const b = new BackingStore(columns, type.name);
export function chiselIterator(type) {
const b = new BaseEntity(type.name);
return new ChiselCursor(type, b);

@@ -181,3 +281,4 @@ }

*
* @param properties The properties of the created entity.
* @param properties The properties of the created entity. If more than one property
* is passed, the expected order of assignment is the same as Object.assign.
*

@@ -196,11 +297,16 @@ * @example

*
* // Create an entity from different JSON objects:
* const otherUserJson = JSON.parse('{"username": "alice"}, {"email": "alice@example.com"}');
* const yetAnotherUser = User.build(userJson);
*
* // now optionally save them to the backend
* await user.save();
* await anotherUser.save();
* await yetAnotherUser.save();
* ```
* @returns The persisted entity with given properties and the `id` property set.
*/
static build(properties) {
static build(...properties) {
const result = new this();
Object.assign(result, properties);
Object.assign(result, ...properties);
return result;

@@ -251,2 +357,23 @@ }

}
/**
* Deletes all entities that match the `restrictions` object.
*
* @example
* ```typescript
* export class User extends ChiselEntity {
* username: string,
* email: string,
* }
* const user = User.build({ username: "alice", email: "alice@example.com" });
* await user.save();
*
* await User.delete({ email: "alice@example.com"})
* ```
*/
static async delete(restrictions) {
await Deno.core.opAsync("chisel_entity_delete", {
type_name: this.name,
restrictions: restrictions,
});
}
}

@@ -273,4 +400,16 @@ export class OAuthUser extends ChiselEntity {

}
export function getSecret(key) {
const secret = Deno.core.opSync("chisel_get_secret", key);
if (secret === undefined || secret === null) {
return undefined;
}
return secret;
}
export function responseFromJson(body, status = 200) {
return new Response(JSON.stringify(body), {
// https://fetch.spec.whatwg.org/#null-body-status
const isNullBody = (status) => {
return status == 101 || status == 204 || status == 205 || status == 304;
};
const json = isNullBody(status) ? null : JSON.stringify(body);
return new Response(json, {
status: status,

@@ -287,2 +426,5 @@ headers: [

}
export function unique() {
// chisel-decorator, no content
}
/** Returns the currently logged-in user or null if no one is logged in. */

@@ -289,0 +431,0 @@ export async function loggedInUser() {

@@ -1,2 +0,2 @@

// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.

@@ -3,0 +3,0 @@ // deno-lint-ignore-file no-explicit-any

{
"name": "@chiselstrike/api",
"version": "0.6.5",
"main": "lib/chisel.js",
"types": "lib/chisel.d.ts",
"author": "Pekka Enberg <penberg@chiselstrike.com>",
"license": "Proprietary",
"prepare": "npm run build",
"scripts": {
"name": "@chiselstrike/api",
"version": "0.7.0",
"main": "lib/chisel.js",
"types": "lib/chisel.d.ts",
"author": "Pekka Enberg <penberg@chiselstrike.com>",
"license": "Proprietary",
"prepare": "npm run build",
"build": "rimraf ./lib && tsc --noResolve && cp -La ../../api/src/lib.deno_core.d.ts lib/"
},
"dependencies": {
"typescript": "^4.5.4"
},
"devDependencies": {
"rimraf": "^3.0.2"
},
"files": [
"/lib"
]
"scripts": {
"prepare": "npm run build",
"build": "rimraf ./lib && tsc --noResolve && cp -La ../../api/src/lib.deno_core.d.ts lib/"
},
"dependencies": {
"typescript": "^4.5.4"
},
"devDependencies": {
"rimraf": "^3.0.2"
},
"files": [
"/lib"
]
}