-
Notifications
You must be signed in to change notification settings - Fork 7
Subscribe #121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Subscribe #121
Changes from all commits
756ff23
281039d
e21bfb0
19cc8ee
23c78cc
572135f
422f8d0
eff2051
ec8d96c
a0dde86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,4 +6,4 @@ node_modules | |
| *.iml | ||
| *.code-workspace | ||
| .DS_Store | ||
| sakila.db | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ | |
| "scripts": { | ||
| "build": "rimraf dist && tsc", | ||
| "test": "jest --runInBand --coverage", | ||
| "testOnly": "jest --runInBand", | ||
| "coveralls": "cat ./coverage/lcov.info | coveralls", | ||
| "lint": "eslint src", | ||
| "format": "prettier --write \"src/**/*.ts\"", | ||
|
|
@@ -79,6 +80,7 @@ | |
| "graphql": "15.1.0", | ||
| "graphql-middleware": "4.0.2", | ||
| "graphql-scalars": "1.1.5", | ||
| "graphql-subscriptions": "^1.1.0", | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: This should be in |
||
| "graphql-tag": "2.10.3", | ||
| "husky": "4.2.5", | ||
| "jest": "26.0.1", | ||
|
|
@@ -95,4 +97,4 @@ | |
| "peerDependencies": { | ||
| "graphql": "^14.0.0 || ^15.0.0" | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import { createSqlmancerClient } from '../../' | ||
| import { SqlmancerClient } from './sqlmancer' | ||
| import { PubSub } from 'graphql-subscriptions' | ||
|
|
||
| export const client = createSqlmancerClient<SqlmancerClient>(__dirname + '/schema.ts', require('./knex')) | ||
| export const client = createSqlmancerClient<SqlmancerClient>(__dirname + '/schema.ts', require('./knex'), new PubSub()) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| /* eslint-disable jest/require-top-level-describe */ | ||
| /* eslint-disable no-useless-escape */ | ||
| import { graphql, validateSchema } from 'graphql' | ||
| import { schema, client } from './schema' | ||
| import { graphql, validateSchema, subscribe, parse, ExecutionResult } from 'graphql' | ||
| import { schema, client, pubSub } from './schema' | ||
|
|
||
| const describeMaybeSkip = process.env.DB && !process.env.DB.split(' ').includes('postgres') ? describe.skip : describe | ||
|
|
||
|
|
@@ -394,4 +394,62 @@ describeMaybeSkip('integration (postgres)', () => { | |
| expect(errors).toBeUndefined() | ||
| expect(data?.films.some((f: any) => f.sequel && f.sequel.id)).toBe(true) | ||
| }) | ||
|
|
||
| test('subscriptions', async () => { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: This test can be removed. This test is extraneous because it's not testing anything specific to the library. |
||
| const document = parse(` | ||
| subscription { | ||
| create | ||
| } | ||
| `) | ||
|
|
||
| const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document) | ||
| expect(sub.next).toBeDefined() | ||
|
|
||
| const next = sub.next() // grab the promise | ||
| pubSub.publish('CREATE_ONE', { create: 'FLUM!' }) //publish | ||
| const { | ||
| value: { errors, data }, | ||
| } = await next // await the promise | ||
|
|
||
| expect(errors).toBeUndefined() | ||
| expect(data).toBeDefined() | ||
| expect(data.create).toBe('FLUM!') | ||
| }) | ||
|
|
||
| // this skipped test is returning "GraphQLError: Cannot return null for non-nullable field Subscription.create" at `expect(subErrors).toBeUndefined()` | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: This comment is no longer necessary. |
||
| test('subscription triggered by mutation', async () => { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: This probably needs to be converted to a unit test for now. Like I said before, we should probably start with unit tests to directly exercise any methods that are being added. The unit tests include a harness that lets you roll back any changes when doing mutations so that the tests don't have to worry about side-effects. We should probably add something similar to the integration tests. Right now I don't have any mutations included in the integration tests for this reason. |
||
| const document = parse(` | ||
| subscription { | ||
| create | ||
| } | ||
| `) | ||
|
|
||
| const query = `mutation { | ||
| deleteCustomer(id: 1009) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: Why are we deleting a customer here? |
||
|
|
||
| createCustomer (input: { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. praise: Thanks for modifying this to exercise the |
||
| id: 1009 | ||
| firstName: "Morty" | ||
| lastName: "Blinkers" | ||
| email: "[email protected]" | ||
| }) { | ||
| id | ||
| } | ||
| }` | ||
|
|
||
| const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document) | ||
| expect(sub.next).toBeDefined() | ||
|
|
||
| const next = sub.next() | ||
|
|
||
| const { data, errors } = await graphql(schema, query) | ||
| expect(errors).toBeUndefined() | ||
| expect(data).toBeDefined() | ||
|
|
||
| const { | ||
| value: { errors: subErrors, data: subData }, | ||
| } = await next | ||
| expect(subErrors).toBeUndefined() | ||
| expect(subData).toBeDefined() | ||
| }, 10000) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -38,7 +38,8 @@ export type GenericSqlmancerClient = Knex & { | |||||||||
|
|
||||||||||
| export function createSqlmancerClient<T extends GenericSqlmancerClient = GenericSqlmancerClient>( | ||||||||||
| glob: string, | ||||||||||
| knex: Knex | ||||||||||
| knex: Knex, | ||||||||||
| pubSub?: any | ||||||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
In TypeScript, classes represent both types and values. |
||||||||||
| ): T { | ||||||||||
| const typeDefs = getTypeDefsFromGlob(glob) | ||||||||||
|
|
||||||||||
|
|
@@ -51,7 +52,7 @@ export function createSqlmancerClient<T extends GenericSqlmancerClient = Generic | |||||||||
|
|
||||||||||
| return Object.assign(knex, { | ||||||||||
| models: _.mapValues(models, (model: Model) => { | ||||||||||
| const options = { knex, dialect } | ||||||||||
| const options = { knex, dialect, pubSub } | ||||||||||
| const { builders, readOnly } = model | ||||||||||
| return { | ||||||||||
| findById: (id: ID) => new builders.findById(options, id), | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,16 @@ export class CreateOneBuilder<TCreateFields extends Record<string, any>> extends | |
| this._data = data | ||
| } | ||
|
|
||
| /** | ||
| * Publishes and event notifying subscriber of Change | ||
| */ | ||
| public publish(): this { | ||
| if (this._options.pubSub) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Add tests to cover both branches of this You can view test coverage issues by clicking on the "Details" link under the failing Coveralls check Click on the "CHANGED" tab to view changed files Files with less coverage are shown in red Click the file link for a detailed view with problem areas highlighted The current test only exercises this method when |
||
| this._options.pubSub.publish('CREATE_ONE', { create: 'TEST' }) | ||
| } | ||
| return this | ||
| } | ||
|
|
||
| /** | ||
| * Executes the query and returns a Promise that will resolve to the ID of the created row. | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,7 @@ export type Association = { | |
| export type BuilderOptions = { | ||
| knex: Knex | ||
| dialect: Dialect | ||
| pubSub?: any | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see previous comment |
||
| } | ||
|
|
||
| export type QueryBuilderContext = { | ||
|
|
||




There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
sakila.dbis created and modified while running the SQLite integration tests. We don't want to check it by accident, so this should be left as-is.