Skip to content

Commit

Permalink
Merge branch 'main' into DPLT-980_wildcard_tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gabehamilton committed Jun 26, 2023
2 parents 3eb0009 + 3ab0a84 commit f0ab72d
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 27 deletions.
7 changes: 3 additions & 4 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@
"typescript": "4.9.5",
"graphiql": "^2.4.1",
"react-bootstrap-icons": "^1.10.3",
"buffer": "^6.0.3"
},
"devDependencies": {
"raw-loader": "^4.0.2"
"buffer": "^6.0.3",
"raw-loader": "^4.0.2",
"regenerator-runtime": "^0.13.11"
}
}
2 changes: 1 addition & 1 deletion frontend/src/components/Editor/ResizableLayoutEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const ResizableEditor = ({

// Render logic based on fileName
const editorComponents = {
GraphiQL: () => <GraphqlPlayground accountId={accountId} />,
GraphiQL: () => <GraphqlPlayground />,
"indexingLogic.js": () =>
diffView ? (
<DiffEditorComponent
Expand Down
90 changes: 84 additions & 6 deletions frontend/src/components/Playground/graphiql.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useContext, useState } from "react";
import GraphiQL from "graphiql";
import { sessionStorage } from "near-social-bridge";
import "graphiql/graphiql.min.css";
import { IndexerDetailsContext } from '../../contexts/IndexerDetailsContext';

import { useExporterPlugin } from '@graphiql/plugin-code-exporter';
import { useExplorerPlugin } from '@graphiql/plugin-explorer';
import '@graphiql/plugin-explorer/dist/style.css';
import "graphiql/graphiql.min.css";
import '@graphiql/plugin-code-exporter/dist/style.css';
import '@graphiql/plugin-explorer/dist/style.css';

const HASURA_ENDPOINT =
process.env.NEXT_PUBLIC_HASURA_ENDPOINT ||
Expand All @@ -25,23 +25,101 @@ const graphQLFetcher = async (graphQLParams, accountId) => {
return await response.json();
};

const extractQueryName = query => {
const match = query.match(/^[^{(]+\s([^{\s(]+)/);
return match ? match[1] : null;
};

const extractTableName = query => {
const match = query.match(/query\s*\w*\s*{\s*([^({\s]+)/);
return match ? match[1].trim() : null;
};

const bosQuerySnippet = (accountId) => {
return {
name: `BOS Widget`,
language: `JavaScript`,
codeMirrorMode: `jsx`,
options: [],
generate: arg => {
const { operationDataList } = arg;
const { query } = operationDataList[0];
const queryName = extractQueryName(query)
const tableName = extractTableName(query)
const formattedQuery = query.replace(/\n/g, `\n` + ` `.repeat(2));
return `
const QUERYAPI_ENDPOINT = \`${HASURA_ENDPOINT}\`;
State.init({
data: []
});
const query = \`${formattedQuery}\`
function fetchGraphQL(operationsDoc, operationName, variables) {
return asyncFetch(
QUERYAPI_ENDPOINT,
{
method: "POST",
headers: { "x-hasura-role": \`${accountId?.replaceAll(".", "_")}\` },
body: JSON.stringify({
query: operationsDoc,
variables: variables,
operationName: operationName,
}),
}
);
}
fetchGraphQL(query, "${queryName}", {}).then((result) => {
if (result.status === 200) {
if (result.body.data) {
const data = result.body.data.${tableName};
State.update({ data })
console.log(data);
}
}
});
const renderData = (a) => {
return (
<div key={JSON.stringify(a)}>
{JSON.stringify(a)}
</div>
);
};
const renderedData = state.data.map(renderData);
return (
{renderedData}
);`;
}
}
};

export const GraphqlPlayground = () => {
const { indexerDetails } = useContext(IndexerDetailsContext);
const snippets = [bosQuerySnippet(indexerDetails.accountId)];
const [query, setQuery] = useState("");

const explorerPlugin = useExplorerPlugin({
query,
onEdit: setQuery,
});
const exporterPlugin = useExporterPlugin({
query,
snippets,
codeMirrorTheme: 'graphiql',
});

return (
<div style={{ width: "100%", height: "75vh" }}>
<GraphiQL
fetcher={(params) => graphQLFetcher(params, indexerDetails.accountId)}
query={query}
onEditQuery={setQuery}
plugins={[explorerPlugin]}
fetcher={(params) => graphQLFetcher(params, indexerDetails.accountId)}
defaultQuery=""
storage={sessionStorage}
theme="dark"
plugins={[explorerPlugin, exporterPlugin]}
/>
</div>
);
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/components/Playground/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { GraphqlPlayground } from "./graphiql";
import dynamic from 'next/dynamic';

const DynamicGraphiQLPlayground= dynamic(
() => import('./graphiql.jsx').then(mod => mod.GraphqlPlayground),
{ ssr: false } // This will load the component only on client side
);

function GraphqlPlayground({ }) {
return (
<div style={{display: "block", width:"100%"}}>
<DynamicGraphiQLPlayground />
</div>
);
}

export default GraphqlPlayground;
1 change: 1 addition & 0 deletions frontend/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
NearSocialBridgeProvider,
} from "near-social-bridge";
import { IndexerDetailsProvider } from '../contexts/IndexerDetailsContext';
import 'regenerator-runtime/runtime';
overrideLocalStorage();

export default function App({ Component, pageProps }: AppProps) {
Expand Down
3 changes: 3 additions & 0 deletions frontend/widgets/src/QueryApi.IndexerStatus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ const indexerStateDoc = `
status
function_name
current_block_height
current_historical_block_height
}
indexer_state_aggregate(where: {function_name: {_eq: "${accountId}/${indexer_name}"}}) {
aggregate {
Expand Down Expand Up @@ -262,6 +263,7 @@ return (
<tr>
<th>Function Name</th>
<th>Current Block Height</th>
<th>Current Historical Block Height</th>
<th>Status</th>
</tr>
</thead>
Expand All @@ -270,6 +272,7 @@ return (
<tr>
<TableElement>{x.function_name}</TableElement>
<TableElement>{x.current_block_height}</TableElement>
<TableElement>{x.current_historical_block_height}</TableElement>
<TableElement>{x.status}</TableElement>
</tr>
))}
Expand Down
49 changes: 49 additions & 0 deletions indexer-js-queue-handler/__snapshots__/indexer.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,55 @@ exports[`Indexer unit tests Indexer.runFunctions() logs provisioning failures 1`
]
`;

exports[`Indexer unit tests Indexer.runFunctions() sets the current historical block height 1`] = `
[
[
"mock-hasura-endpoint/v1/graphql",
{
"body": "{"query":"mutation writeLog($function_name: String!, $block_height: numeric!, $message: String!){\\n insert_indexer_log_entries_one(object: {function_name: $function_name, block_height: $block_height, message: $message}) {id}\\n }","variables":{"function_name":"buildnear.testnet/test","block_height":456,"message":"Running function:buildnear.testnet/test:, lag in ms is: :NaN"}}",
"headers": {
"Content-Type": "application/json",
"X-Hasura-Role": "append",
},
"method": "POST",
},
],
[
"mock-hasura-endpoint/v1/graphql",
{
"body": "{"query":"\\n mutation SetStatus($function_name: String, $status: String) {\\n insert_indexer_state_one(object: {function_name: $function_name, status: $status, current_block_height: 0 }, on_conflict: { constraint: indexer_state_pkey, update_columns: status }) {\\n function_name\\n status\\n }\\n }\\n ","variables":{"function_name":"buildnear.testnet/test","status":"RUNNING"}}",
"headers": {
"Content-Type": "application/json",
"X-Hasura-Role": "append",
},
"method": "POST",
},
],
[
"mock-hasura-endpoint/v1/graphql",
{
"body": "{"query":"mutation writeLog($function_name: String!, $block_height: numeric!, $message: String!){\\n insert_indexer_log_entries_one(object: {function_name: $function_name, block_height: $block_height, message: $message}) {id}\\n }","variables":{"function_name":"buildnear.testnet/test","block_height":456,"message":"hey"}}",
"headers": {
"Content-Type": "application/json",
"X-Hasura-Role": "append",
},
"method": "POST",
},
],
[
"mock-hasura-endpoint/v1/graphql",
{
"body": "{"query":"\\n mutation WriteBlock($function_name: String!, $block_height: numeric!) {\\n insert_indexer_state(\\n objects: {current_historical_block_height: $block_height, current_block_height: 0, function_name: $function_name}\\n on_conflict: {constraint: indexer_state_pkey, update_columns: current_historical_block_height}\\n ) {\\n returning {\\n current_block_height\\n current_historical_block_height\\n function_name\\n }\\n }\\n }\\n ","variables":{"function_name":"buildnear.testnet/test","block_height":456}}",
"headers": {
"Content-Type": "application/json",
"X-Hasura-Role": "append",
},
"method": "POST",
},
],
]
`;

exports[`Indexer unit tests Indexer.runFunctions() should execute all functions against the current block 1`] = `
[
[
Expand Down
3 changes: 2 additions & 1 deletion indexer-js-queue-handler/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ export const consumer = async (event) => {
for (const record of event.Records) {
const jsonBody = JSON.parse(record.body);
const block_height = jsonBody.block_height;
const is_historical = jsonBody.is_historical;
const functions = {};

const function_config = jsonBody.indexer_function;
const function_name = function_config.account_id + '/' + function_config.function_name;
functions[function_name] = function_config;

const mutations = await indexer.runFunctions(block_height, functions, {imperative: true, provision: true});
const mutations = await indexer.runFunctions(block_height, functions, is_historical, {imperative: true, provision: true});
}
};
25 changes: 20 additions & 5 deletions indexer-js-queue-handler/indexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default class Indexer {
};
}

async runFunctions(block_height, functions, options = { imperative: false, provision: false }) {
async runFunctions(block_height, functions, is_historical, options = { imperative: false, provision: false }) {
const blockWithHelpers = Block.fromStreamerMessage(await this.fetchStreamerMessage(block_height));

let lag = Date.now() - Math.floor(blockWithHelpers.header().timestampNanosec / 1000000);
Expand Down Expand Up @@ -101,7 +101,7 @@ export default class Indexer {
}
}

simultaneousPromises.push(this.writeFunctionState(function_name, block_height));
simultaneousPromises.push(this.writeFunctionState(function_name, block_height, is_historical));
} catch (e) {
console.error(`${function_name}: Failed to run function`, e);
this.deps.awsXray.resolveSegment().addError(e);
Expand Down Expand Up @@ -307,10 +307,10 @@ export default class Indexer {
});
}

async writeFunctionState(function_name, block_height) {
async writeFunctionState(function_name, block_height, is_historical) {
const activeFunctionSubsegment = this.deps.awsXray.resolveSegment();
const subsegment = activeFunctionSubsegment.addNewSubsegment(`writeFunctionState`);
const mutation =
const real_time_mutation =
`mutation WriteBlock($function_name: String!, $block_height: numeric!) {
insert_indexer_state(
objects: {current_block_height: $block_height, function_name: $function_name}
Expand All @@ -322,18 +322,33 @@ export default class Indexer {
}
}
}`;
const historical_mutation = `
mutation WriteBlock($function_name: String!, $block_height: numeric!) {
insert_indexer_state(
objects: {current_historical_block_height: $block_height, current_block_height: 0, function_name: $function_name}
on_conflict: {constraint: indexer_state_pkey, update_columns: current_historical_block_height}
) {
returning {
current_block_height
current_historical_block_height
function_name
}
}
}
`;
const variables = {
function_name,
block_height,
};
return this.runGraphQLQuery(mutation, variables, function_name, block_height, this.DEFAULT_HASURA_ROLE)
return this.runGraphQLQuery(is_historical ? historical_mutation : real_time_mutation, variables, function_name, block_height, this.DEFAULT_HASURA_ROLE)
.catch((e) => {
console.error(`${function_name}: Error writing function state`, e);
})
.finally(() => {
subsegment.close();
});
}

async runGraphQLQuery(operation, variables, function_name, block_height, hasuraRoleName, logError = true) {
const response = await this.deps.fetch(`${process.env.HASURA_ENDPOINT}/v1/graphql`, {
method: 'POST',
Expand Down
Loading

0 comments on commit f0ab72d

Please sign in to comment.