@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
79 lines (77 loc) • 2.93 kB
JavaScript
import { useBus } from "../../bus/lib/use-bus.js";
import "../../bus/index.js";
import { getSchema } from "../../utils/get-schema.js";
import { getPayload } from "../../websocket/utils/items.js";
import { getQuery } from "./schema/parse-query.js";
import { EventEmitter, on } from "events";
//#region src/services/graphql/subscription.ts
const messages = createPubSub(new EventEmitter());
function bindPubSub() {
useBus().subscribe("websocket.event", (message) => {
messages.publish(`${message["collection"]}_mutated`, message);
});
}
function createSubscriptionGenerator(gql, event) {
return async function* (_x, _y, _z, request) {
const fields = await parseFields(gql, request);
const args = parseArguments(request);
for await (const payload of messages.subscribe(event)) {
const eventData = payload;
if ("event" in args && eventData["action"] !== args["event"]) continue;
const schema = await getSchema();
const subscription = {
collection: eventData["collection"],
event: eventData["action"],
query: { fields }
};
if (eventData["action"] === "delete") for (const key of eventData.keys) yield { [event]: {
key,
data: null,
event: eventData["action"]
} };
if (eventData["action"] === "create") try {
subscription.item = eventData["key"];
const result = await getPayload(subscription, gql.accountability, schema, eventData);
yield { [event]: {
key: eventData["key"],
data: result["data"],
event: eventData["action"]
} };
} catch {}
if (eventData["action"] === "update") for (const key of eventData["keys"]) try {
subscription.item = key;
const result = await getPayload(subscription, gql.accountability, schema, eventData);
yield { [event]: {
key,
data: result["data"],
event: eventData["action"]
} };
} catch {}
}
};
}
function createPubSub(emitter) {
return {
publish: (event, payload) => void emitter.emit(event, payload),
subscribe: async function* (event) {
const asyncIterator = on(emitter, event);
for await (const [value] of asyncIterator) yield value;
}
};
}
async function parseFields(gql, request) {
const dataSelections = (request.fieldNodes[0]?.selectionSet?.selections ?? []).reduce((result, selection) => {
if (selection.kind === "Field" && selection.name.value === "data" && selection.selectionSet?.kind === "SelectionSet") return selection.selectionSet.selections;
return result;
}, []);
const { fields } = await getQuery({}, gql.schema, dataSelections, request.variableValues, gql.accountability);
return fields ?? [];
}
function parseArguments(request) {
return (request.fieldNodes[0]?.arguments ?? []).reduce((result, current) => {
if ("value" in current.value && typeof current.value.value === "string") result[current.name.value] = current.value.value;
return result;
}, {});
}
//#endregion
export { bindPubSub, createSubscriptionGenerator };