diff --git a/docs/interfaces/SubscriptionServer.md b/docs/interfaces/SubscriptionServer.md index f8fb4cc0..7f2e95a4 100644 --- a/docs/interfaces/SubscriptionServer.md +++ b/docs/interfaces/SubscriptionServer.md @@ -15,11 +15,11 @@ ### complete -• **complete**: (`event`: { `payload?`: `Record`<`string`, `any`\> ; `topic`: `string` }) => `Promise`<`void`\> +• **complete**: (`event`: { `payload?`: `Record`<`string`, `any`\> ; `topic`: `string` }, `excludeKeys?`: `string`[]) => `Promise`<`void`\> #### Type declaration -▸ (`event`): `Promise`<`void`\> +▸ (`event`, `excludeKeys`): `Promise`<`void`\> Send a complete message and end all relevant subscriptions. This might take some time depending on how many subscriptions there are. @@ -32,6 +32,7 @@ The payload if present will be used to match against any filters the subscriptio | `event` | `Object` | | `event.payload?` | `Record`<`string`, `any`\> | | `event.topic` | `string` | +| `excludeKeys?` | `string`[] | ##### Returns @@ -41,11 +42,11 @@ ___ ### publish -• **publish**: (`event`: { `payload`: `Record`<`string`, `any`\> ; `topic`: `string` }) => `Promise`<`void`\> +• **publish**: (`event`: { `payload`: `Record`<`string`, `any`\> ; `topic`: `string` }, `excludeKeys?`: `string`[]) => `Promise`<`void`\> #### Type declaration -▸ (`event`): `Promise`<`void`\> +▸ (`event`, `excludeKeys`): `Promise`<`void`\> Publish an event to all relevant subscriptions. This might take some time depending on how many subscriptions there are. @@ -58,6 +59,7 @@ The payload if present will be used to match against any filters the subscriptio | `event` | `Object` | | `event.payload` | `Record`<`string`, `any`\> | | `event.topic` | `string` | +| `excludeKeys?` | `string`[] | ##### Returns diff --git a/lib/pubsub/complete.ts b/lib/pubsub/complete.ts index 827f055a..d67a1af4 100644 --- a/lib/pubsub/complete.ts +++ b/lib/pubsub/complete.ts @@ -9,9 +9,9 @@ import { getResolverAndArgs } from '../utils/getResolverAndArgs' import { isArray } from '../utils/isArray' import { getFilteredSubs } from './getFilteredSubs' -export const complete = (serverPromise: Promise | ServerClosure): SubscriptionServer['complete'] => async event => { +export const complete = (serverPromise: Promise | ServerClosure): SubscriptionServer['complete'] => async (event, excludeKeys) => { const server = await serverPromise - const subscriptions = await getFilteredSubs({ server, event }) + const subscriptions = await getFilteredSubs({ server, event, excludeKeys }) server.log('pubsub:complete', { event, subscriptions }) const iters = subscriptions.map(async (sub) => { diff --git a/lib/pubsub/getFilteredSubs-test.ts b/lib/pubsub/getFilteredSubs-test.ts index 82077247..ae9fe5db 100644 --- a/lib/pubsub/getFilteredSubs-test.ts +++ b/lib/pubsub/getFilteredSubs-test.ts @@ -21,6 +21,21 @@ describe('collapseKeys', () => { 'a.3.b': 4, }) }) + + it('excludes excluded keys', () => { + assert.deepEqual(collapseKeys({ a: 4, b: { c: 5, d: 'hi', e: { f: false } } }, ['a', 'b.d']), { + 'b.c': 5, + 'b.e.f': false, + }) + assert.deepEqual(collapseKeys({ a: [1, 2, 3, { b: 4, c: [], d: null, e: undefined }], f: { g: [{ h: 5 }, { i: 6 }], j: [7, 8, 9] } }, ['f.g', 'f.j.1']), { + 'a.0': 1, + 'a.1': 2, + 'a.2': 3, + 'a.3.b': 4, + 'f.j.0': 7, + 'f.j.2': 9, + }) + }) }) diff --git a/lib/pubsub/getFilteredSubs.ts b/lib/pubsub/getFilteredSubs.ts index ccf7c0aa..2a1a3cc6 100644 --- a/lib/pubsub/getFilteredSubs.ts +++ b/lib/pubsub/getFilteredSubs.ts @@ -2,9 +2,9 @@ import { collect } from 'streaming-iterables' import { ServerClosure, Subscription } from '../types' -export const getFilteredSubs = async ({ server, event }: { server: Omit, event: { topic: string, payload?: Record } }): Promise => { +export const getFilteredSubs = async ({ server, event, excludeKeys = [] }: { server: Omit, event: { topic: string, payload?: Record }, excludeKeys?: string[] }): Promise => { if (!event.payload || Object.keys(event.payload).length === 0) { - server.log('getFilteredSubs', { event }) + server.log('getFilteredSubs', { event, excludeKeys }) const iterator = server.models.subscription.query({ IndexName: 'TopicIndex', @@ -15,7 +15,7 @@ export const getFilteredSubs = async ({ server, event }: { server: Omit, + excludeKeys: string[] = [], + parent: string[] = [], ): Record => { const record = {} for (const [k1, v1] of Object.entries(obj)) { + const path = [...parent, k1] + const key = path.join('.') + if (excludeKeys.includes(key)) { + continue + } if (typeof v1 === 'string' || typeof v1 === 'number' || typeof v1 === 'boolean') { - record[k1] = v1 + record[key] = v1 continue } - if (v1 && typeof v1 === 'object') { - const next = {} - - for (const [k2, v2] of Object.entries(v1)) { - next[`${k1}.${k2}`] = v2 - } - - for (const [k1, v1] of Object.entries(collapseKeys(next))) { - record[k1] = v1 + for (const [k2, v2] of Object.entries(collapseKeys(v1, excludeKeys, path))) { + record[k2] = v2 } + continue } } return record diff --git a/lib/pubsub/publish.ts b/lib/pubsub/publish.ts index c21fc439..7fb5b980 100644 --- a/lib/pubsub/publish.ts +++ b/lib/pubsub/publish.ts @@ -5,10 +5,10 @@ import { postToConnection } from '../utils/postToConnection' import { buildContext } from '../utils/buildContext' import { getFilteredSubs } from './getFilteredSubs' -export const publish = (serverPromise: Promise | ServerClosure): SubscriptionServer['publish'] => async event => { +export const publish = (serverPromise: Promise | ServerClosure): SubscriptionServer['publish'] => async (event, excludeKeys) => { const server = await serverPromise - server.log('pubsub:publish', { event }) - const subscriptions = await getFilteredSubs({ server, event }) + server.log('pubsub:publish', { event, excludeKeys }) + const subscriptions = await getFilteredSubs({ server, event, excludeKeys }) server.log('pubsub:publish', { subscriptions: subscriptions.map(({ connectionId, filter, subscription }) => ({ connectionId, filter, subscription }) ) }) const iters = subscriptions.map(async (sub) => { diff --git a/lib/types.ts b/lib/types.ts index e26c6123..7b289a8d 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -106,13 +106,13 @@ export interface SubscriptionServer { * * The payload if present will be used to match against any filters the subscriptions might have. */ - publish: (event: { topic: string, payload: Record}) => Promise + publish: (event: { topic: string, payload: Record}, excludeKeys?: string[]) => Promise /** * Send a complete message and end all relevant subscriptions. This might take some time depending on how many subscriptions there are. * * The payload if present will be used to match against any filters the subscriptions might have. */ - complete: (event: { topic: string, payload?: Record }) => Promise + complete: (event: { topic: string, payload?: Record }, excludeKeys?: string[]) => Promise } /**