Skip to content

Commit

Permalink
feat: Middlewares addition
Browse files Browse the repository at this point in the history
Add middlewares decorator
Add middlewares test
  • Loading branch information
petarvujovic98 committed Oct 13, 2022
1 parent fd6db41 commit a860555
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 1 deletion.
17 changes: 17 additions & 0 deletions lib/near-bindgen.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions lib/near-bindgen.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions src/near-bindgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,50 @@ export function call({
};
}

/**
* The interface that a middleware has to implement in order to be used as a middleware function/class.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
interface Middleware<Arguments extends Array<any>> {
/**
* The method that gets called with the same arguments that are passed to the function it is wrapping.
*
* @param args - Arguments that will be passed to the function - immutable.
*/
call(...args: Arguments): void;
}

/**
* Tells the SDK to apply an array of passed in middleware to the function execution.
*
* @param middlewares - The middlewares to be executed.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function middleware<Arguments extends Array<any>>(
...middlewares: Middleware<Arguments>[]
): DecoratorFunction {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return function <AnyFunction extends (...args: Arguments) => any>(
_target: object,
_key: string | symbol,
descriptor: TypedPropertyDescriptor<AnyFunction>
): void {
const originalMethod = descriptor.value;

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
descriptor.value = function (...args: Arguments): ReturnType<AnyFunction> {
try {
middlewares.forEach((middleware) => middleware.call(...args));
} catch (error) {
throw new Error(error);
}

return originalMethod.apply(this, args);
};
};
}

/**
* Extends this class with the methods needed to make the contract storable/serializable and readable/deserializable to and from the blockchain.
* Also tells the SDK to capture and expose all view, call and initialize functions.
Expand Down
84 changes: 84 additions & 0 deletions tests/__tests__/test-middlewares.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Worker } from "near-workspaces";
import test from "ava";

test.beforeEach(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the contract.
const middlewares = await root.devDeploy("build/middlewares.wasm");

// Create the init args.
const args = JSON.stringify({ randomData: "anything" });
// Capture the result of the init function call.
const result = await middlewares.callRaw(middlewares, "init", args);

// Extract the logs.
const { logs } = result.result.receipts_outcome[0].outcome;
// Create the expected logs.
const expectedLogs = [`Log from middleware: ${args}`];

// Check for correct logs.
t.deepEqual(logs, expectedLogs);

// Create test users
const ali = await root.createSubAccount("ali");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = { root, middlewares, ali };
});

test.afterEach.always(async (t) => {
await t.context.worker.tearDown().catch((error) => {
console.log("Failed to tear down the worker:", error);
});
});

test("The middleware logs with call functions", async (t) => {
const { ali, middlewares } = t.context.accounts;

// Create the arguments which will be passed to the function.
const args = JSON.stringify({ id: "1", text: "hello" });
// Call the function.
const result = await ali.callRaw(middlewares, "add", args);
// Extract the logs.
const { logs } = result.result.receipts_outcome[0].outcome;
// Create the expected logs.
const expectedLogs = [`Log from middleware: ${args}`];

t.deepEqual(logs, expectedLogs);
});

test("The middleware logs with view functions", async (t) => {
const { ali, middlewares } = t.context.accounts;

// Create the arguments which will be passed to the function.
const args = JSON.stringify({ id: "1", accountId: "hello" });
// Call the function.
const result = await ali.callRaw(middlewares, "get", args);
// Extract the logs.
const { logs } = result.result.receipts_outcome[0].outcome;
// Create the expected logs.
const expectedLogs = [`Log from middleware: ${args}`];

t.deepEqual(logs, expectedLogs);
});

test("The middleware logs with private functions", async (t) => {
const { ali, middlewares } = t.context.accounts;

// Create the arguments which will be passed to the function.
const args = { id: "test", accountId: "tset" };
// Call the function.
const result = await ali.callRaw(middlewares, "get_private", "");
// Extract the logs.
const { logs } = result.result.receipts_outcome[0].outcome;
// Create the expected logs.
const expectedLogs = [`Log from middleware: ${args}`];

t.deepEqual(logs, expectedLogs);
});
4 changes: 3 additions & 1 deletion tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"build:private": "near-sdk-js build src/decorators/private.ts build/private.wasm",
"build:bigint-serialization": "near-sdk-js build src/bigint-serialization.ts build/bigint-serialization.wasm",
"build:date-serialization": "near-sdk-js build src/date-serialization.ts build/date-serialization.wasm",
"build:middlewares": "near-sdk-js build src/middlewares.ts build/middlewares.wasm",
"test": "ava",
"test:context-api": "ava __tests__/test_context_api.ava.js",
"test:math-api": "ava __tests__/test_math_api.ava.js",
Expand All @@ -49,7 +50,8 @@
"test:private": "ava __tests__/decorators/private.ava.js",
"test:bigint-serialization": "ava __tests__/test-bigint-serialization.ava.js",
"test:date-serialization": "ava __tests__/test-date-serialization.ava.js",
"test:serialization": "ava __tests__/test-serialization.ava.js"
"test:serialization": "ava __tests__/test-serialization.ava.js",
"test:middlewares": "ava __tests__/test-middlewares.ava.js"
},
"author": "Near Inc <hello@nearprotocol.com>",
"license": "Apache-2.0",
Expand Down
45 changes: 45 additions & 0 deletions tests/src/middlewares.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NearBindgen, near, call, view } from "near-sdk-js";
import { initialize, middleware } from "../../lib/near-bindgen";

@NearBindgen({ requireInit: true })
export class Contract {
@initialize({})
@middleware({
call: (args) => near.log(`Log from middleware: ${args}`),
})
// eslint-disable-next-line @typescript-eslint/no-empty-function
init({ randomData: _ }: { randomData: string }) {}

@call({})
@middleware({
call: (args) => near.log(`Log from middleware: ${args}`),
})
// eslint-disable-next-line @typescript-eslint/no-empty-function
add({ id: _, text: _t }: { id: string; text: string }) {}

@view({})
@middleware({
call: (args) => near.log(`Log from middleware: ${args}`),
})
get({ id, accountId }: { id: string; accountId: string }): {
id: string;
accountId: string;
} {
return { id: accountId, accountId: id };
}

@view({})
get_private(): { id: string; accountId: string } {
return this.getFromPrivate({ id: "test", accountId: "tset" });
}

@middleware({
call: (args) => near.log(`Log from middleware: ${args}`),
})
getFromPrivate({ id, accountId }: { id: string; accountId: string }): {
id: string;
accountId: string;
} {
return { id, accountId };
}
}

0 comments on commit a860555

Please sign in to comment.