UNPKG

@graphql-mesh/neo4j

Version:
122 lines (121 loc) 4.79 kB
import { GraphQLBigInt } from 'graphql-scalars'; import neo4j from 'neo4j-driver'; import { process } from '@graphql-mesh/cross-helpers'; import { PredefinedProxyOptions } from '@graphql-mesh/store'; import { readFileOrUrl } from '@graphql-mesh/utils'; import { createDefaultExecutor } from '@graphql-tools/delegate'; import { Neo4jGraphQL } from '@neo4j/graphql'; import { toGraphQLTypeDefs } from '@neo4j/introspector'; function getEventEmitterFromPubSub(pubsub) { return { on(event, listener) { pubsub.subscribe(event.toString(), listener); return this; }, once(event, listener) { const id = pubsub.subscribe(event.toString(), data => { listener(data); pubsub.unsubscribe(id); }); return this; }, emit(event, ...args) { pubsub.publish(event.toString(), args[0]); return true; }, addListener(event, listener) { return this.on(event, listener); }, setMaxListeners() { return this; }, }; } export default class Neo4JHandler { constructor({ config, baseDir, pubsub, store, logger, importFn, }) { this.config = config; this.baseDir = baseDir; this.pubsub = pubsub; this.typeDefs = store.proxy('typeDefs', PredefinedProxyOptions.StringWithoutValidation); this.logger = logger; this.importFn = importFn; } getCachedTypeDefs(driver) { return this.typeDefs.getWithSet(async () => { if (this.config.source) { return readFileOrUrl(this.config.source, { cwd: this.baseDir, allowUnknownExtensions: true, importFn: this.importFn, fetch: this.fetchFn, logger: this.logger, }); } else { this.logger.info('Inferring the schema from the database: ', `"${this.config.database || 'neo4j'}"`); let replaceAllPolyfilled = false; if (!String.prototype.replaceAll) { replaceAllPolyfilled = true; // eslint-disable-next-line no-extend-native String.prototype.replaceAll = function (str, newStr) { if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') { return this.replace(str, newStr); } return this.replace(new RegExp(str, 'g'), newStr); }; } const typeDefs = await toGraphQLTypeDefs(() => driver.session({ database: this.config.database, defaultAccessMode: neo4j.session.READ })); if (replaceAllPolyfilled) { // eslint-disable-next-line no-extend-native delete String.prototype.replaceAll; } return typeDefs; } }); } async getMeshSource({ fetchFn }) { this.fetchFn = fetchFn; const driver = neo4j.driver(this.config.endpoint, neo4j.auth.basic(this.config.username, this.config.password), { useBigInt: true, logging: { logger: (level, message) => this.logger[level](message), }, }); const id = this.pubsub.subscribe('destroy', async () => { this.pubsub.unsubscribe(id); this.logger.debug('Closing Neo4j'); await driver.close(); this.logger.debug('Neo4j closed'); }); const typeDefs = await this.getCachedTypeDefs(driver); const events = getEventEmitterFromPubSub(this.pubsub); const neo4jGraphQL = new Neo4jGraphQL({ typeDefs, driver, validate: false, debug: !!process.env.DEBUG, resolvers: { BigInt: GraphQLBigInt, }, features: { subscriptions: { events, publish: eventMeta => this.pubsub.publish(eventMeta.event, eventMeta), }, }, }); const schema = await neo4jGraphQL.getSchema(); const defaultExecutor = createDefaultExecutor(schema); const sessionConfig = { database: this.config.database, }; return { schema: await neo4jGraphQL.getSchema(), executor(executionRequest) { executionRequest.context = executionRequest.context || {}; executionRequest.context.sessionConfig = sessionConfig; return defaultExecutor(executionRequest); }, }; } }