@wundergraph/cosmo-shared
Version:
Shared code between WunderGraph Cosmo packages
235 lines • 10.7 kB
JavaScript
import { Kind } from 'graphql';
import { ArgumentConfiguration, ArgumentSource, AuthorizationConfiguration, DataSourceCustomEvents, EngineEventConfiguration, EntityInterfaceConfiguration, EventType, FieldConfiguration, FieldCoordinates, FieldSetCondition, KafkaEventConfiguration, NatsEventConfiguration, NatsStreamConfiguration, RedisEventConfiguration, RequiredField, Scopes, SubscriptionFieldCondition, SubscriptionFilterCondition, TypeField, } from '@wundergraph/cosmo-connect/dist/node/v1/node_pb';
import { PROVIDER_TYPE_KAFKA, PROVIDER_TYPE_NATS, PROVIDER_TYPE_REDIS, } from '@wundergraph/composition';
function generateFieldSetConditions(requiredField) {
if (!requiredField.conditions) {
return;
}
const conditions = [];
for (const fieldSetCondition of requiredField.conditions) {
const fieldCoordinatesPath = [];
for (const path of fieldSetCondition.fieldCoordinatesPath) {
const fieldCoordinates = path.split('.');
if (fieldCoordinates.length !== 2) {
throw new Error(`fatal: malformed conditional field coordinates "${path}" for field set "${requiredField.selectionSet}".`);
}
fieldCoordinatesPath.push(new FieldCoordinates({
fieldName: fieldCoordinates[1],
typeName: fieldCoordinates[0],
}));
}
conditions.push(new FieldSetCondition({
fieldCoordinatesPath,
fieldPath: fieldSetCondition.fieldPath,
}));
}
return conditions;
}
export function addRequiredFields(requiredFields, target, typeName) {
if (!requiredFields) {
return;
}
for (const requiredField of requiredFields) {
const conditions = generateFieldSetConditions(requiredField);
target.push(new RequiredField({
typeName,
fieldName: requiredField.fieldName,
selectionSet: requiredField.selectionSet,
...(requiredField.disableEntityResolver ? { disableEntityResolver: true } : {}),
...(conditions ? { conditions } : {}),
}));
}
}
function eventType(type) {
switch (type) {
case 'publish': {
return EventType.PUBLISH;
}
case 'request': {
return EventType.REQUEST;
}
case 'subscribe': {
return EventType.SUBSCRIBE;
}
}
}
export function configurationDatasToDataSourceConfiguration(dataByTypeName) {
const output = {
rootNodes: [],
childNodes: [],
keys: [],
provides: [],
events: new DataSourceCustomEvents({ nats: [], kafka: [], redis: [] }),
requires: [],
entityInterfaces: [],
interfaceObjects: [],
};
for (const data of dataByTypeName.values()) {
const typeName = data.typeName;
const fieldNames = [...data.fieldNames];
const typeField = new TypeField({ fieldNames, typeName });
if (data.externalFieldNames && data.externalFieldNames.size > 0) {
typeField.externalFieldNames = [...data.externalFieldNames];
}
if (data.requireFetchReasonsFieldNames && data.requireFetchReasonsFieldNames.length > 0) {
typeField.requireFetchReasonsFieldNames = [...data.requireFetchReasonsFieldNames];
}
if (data.isRootNode) {
output.rootNodes.push(typeField);
}
else {
output.childNodes.push(typeField);
}
if (data.entityInterfaceConcreteTypeNames) {
const entityInterfaceConfiguration = new EntityInterfaceConfiguration({
interfaceTypeName: typeName,
concreteTypeNames: [...data.entityInterfaceConcreteTypeNames],
});
data.isInterfaceObject
? output.interfaceObjects.push(entityInterfaceConfiguration)
: output.entityInterfaces.push(entityInterfaceConfiguration);
}
addRequiredFields(data.keys, output.keys, typeName);
addRequiredFields(data.provides, output.provides, typeName);
addRequiredFields(data.requires, output.requires, typeName);
const natsEventConfigurations = [];
const kafkaEventConfigurations = [];
const redisEventConfigurations = [];
for (const event of data.events ?? []) {
switch (event.providerType) {
case PROVIDER_TYPE_KAFKA: {
kafkaEventConfigurations.push(new KafkaEventConfiguration({
engineEventConfiguration: new EngineEventConfiguration({
fieldName: event.fieldName,
providerId: event.providerId,
type: eventType(event.type),
typeName,
}),
topics: event.topics,
}));
break;
}
case PROVIDER_TYPE_NATS: {
natsEventConfigurations.push(new NatsEventConfiguration({
engineEventConfiguration: new EngineEventConfiguration({
fieldName: event.fieldName,
providerId: event.providerId,
type: eventType(event.type),
typeName,
}),
subjects: event.subjects,
...(event.streamConfiguration
? {
streamConfiguration: new NatsStreamConfiguration({
consumerInactiveThreshold: event.streamConfiguration.consumerInactiveThreshold,
consumerName: event.streamConfiguration.consumerName,
streamName: event.streamConfiguration.streamName,
}),
}
: {}),
}));
break;
}
case PROVIDER_TYPE_REDIS: {
redisEventConfigurations.push(new RedisEventConfiguration({
engineEventConfiguration: new EngineEventConfiguration({
fieldName: event.fieldName,
providerId: event.providerId,
type: eventType(event.type),
typeName,
}),
channels: event.channels,
}));
break;
}
default: {
throw new Error(`Fatal: Unknown event provider.`);
}
}
}
output.events.nats.push(...natsEventConfigurations);
output.events.kafka.push(...kafkaEventConfigurations);
output.events.redis.push(...redisEventConfigurations);
}
return output;
}
export function generateFieldConfigurations(fieldConfigurations) {
const output = [];
for (const compositionFieldConfiguration of fieldConfigurations) {
const argumentConfigurations = compositionFieldConfiguration.argumentNames.map((argumentName) => new ArgumentConfiguration({
name: argumentName,
sourceType: ArgumentSource.FIELD_ARGUMENT,
}));
const fieldConfiguration = new FieldConfiguration({
argumentsConfiguration: argumentConfigurations,
fieldName: compositionFieldConfiguration.fieldName,
typeName: compositionFieldConfiguration.typeName,
});
const requiredOrScopes = compositionFieldConfiguration.requiredScopes?.map((andScopes) => new Scopes({ requiredAndScopes: andScopes })) || [];
const requiredOrScopesByOr = compositionFieldConfiguration.requiredScopesByOR?.map((andScopes) => new Scopes({ requiredAndScopes: andScopes })) || [];
const hasRequiredOrScopes = requiredOrScopes.length > 0;
if (compositionFieldConfiguration.requiresAuthentication || hasRequiredOrScopes) {
fieldConfiguration.authorizationConfiguration = new AuthorizationConfiguration({
requiresAuthentication: compositionFieldConfiguration.requiresAuthentication || hasRequiredOrScopes,
requiredOrScopes,
requiredOrScopesByOr,
});
}
if (compositionFieldConfiguration.subscriptionFilterCondition) {
const subscriptionFilterCondition = new SubscriptionFilterCondition();
generateSubscriptionFilterCondition(subscriptionFilterCondition, compositionFieldConfiguration.subscriptionFilterCondition);
fieldConfiguration.subscriptionFilterCondition = subscriptionFilterCondition;
}
output.push(fieldConfiguration);
}
return output;
}
const resolveNamedTypeName = (type) => {
switch (type.kind) {
case Kind.NON_NULL_TYPE: {
return resolveNamedTypeName(type.type);
}
case Kind.LIST_TYPE: {
return resolveNamedTypeName(type.type);
}
default: {
return type.name.value;
}
}
};
export function generateSubscriptionFilterCondition(protoMessage, condition) {
if (condition.and !== undefined) {
const protoAndConditions = [];
for (const andCondition of condition.and) {
const protoAndCondition = new SubscriptionFilterCondition();
generateSubscriptionFilterCondition(protoAndCondition, andCondition);
protoAndConditions.push(protoAndCondition);
}
protoMessage.and = protoAndConditions;
return;
}
if (condition.in !== undefined) {
protoMessage.in = new SubscriptionFieldCondition({
fieldPath: condition.in.fieldPath,
json: JSON.stringify(condition.in.values),
});
return;
}
if (condition.not !== undefined) {
protoMessage.not = new SubscriptionFilterCondition();
generateSubscriptionFilterCondition(protoMessage.not, condition.not);
return;
}
if (condition.or !== undefined) {
const protoOrConditions = [];
for (const orCondition of condition.or) {
const protoOrCondition = new SubscriptionFilterCondition();
generateSubscriptionFilterCondition(protoOrCondition, orCondition);
protoOrConditions.push(protoOrCondition);
}
protoMessage.or = protoOrConditions;
return;
}
throw new Error('Fatal: Incoming SubscriptionCondition object was malformed.');
}
//# sourceMappingURL=graphql-configuration.js.map