diff --git a/lib/pubsub/getFilteredSubs-test.ts b/lib/pubsub/getFilteredSubs-test.ts index 689f447a..231c25b9 100644 --- a/lib/pubsub/getFilteredSubs-test.ts +++ b/lib/pubsub/getFilteredSubs-test.ts @@ -7,22 +7,27 @@ import { collapseKeys, getFilteredSubs } from './getFilteredSubs' describe('collapseKeys', () => { it('makes the deep objects into dots', () => { assert.deepEqual(collapseKeys({}), {}) - assert.deepEqual(collapseKeys({ a: 4, b: { c: 5, d: 'hi', e: { f: false } } }), { - a: 4, - 'b.c': 5, - 'b.d': 'hi', - 'b.e.f': false, - }) - assert.deepEqual(collapseKeys({ a: [1, 2, 3, { b: 4, c: [], d: null, e: undefined }] }), { - 'a.0': 1, - 'a.1': 2, - 'a.2': 3, - 'a.3.b': 4, - }) + assert.deepEqual( + collapseKeys({ a: 4, b: { c: 5, d: 'hi', e: { f: false } } }), + { + a: 4, + 'b.c': 5, + 'b.d': 'hi', + 'b.e.f': false, + }, + ) + assert.deepEqual( + collapseKeys({ a: [1, 2, 3, { b: 4, c: [], d: null, e: undefined }] }), + { + 'a.0': 1, + 'a.1': 2, + 'a.2': 3, + 'a.3.b': 4, + }, + ) }) }) - // since we're not resetting the db every time we need to change this let count = 1 const makeTopic = () => `topic-${count++}` @@ -53,7 +58,13 @@ describe('getFilteredSubs', () => { } await server.models.subscription.put(subscription) - assert.containSubset(await getFilteredSubs({ server, event: { topic, payload: { language: 'en' } } }), [{ topic, id: '1' }]) + assert.containSubset( + await getFilteredSubs({ + server, + event: { topic, payload: { language: 'en' } }, + }), + [{ topic, id: '1' }], + ) }) it('can match on payload', async () => { @@ -74,8 +85,60 @@ describe('getFilteredSubs', () => { await server.models.subscription.put(subscription) - assert.containSubset(await getFilteredSubs({ server, event: { topic, payload: { language: 'en' } } }), [{ topic, id: '2' }]) - assert.deepEqual(await getFilteredSubs({ server, event: { topic, payload: { language: 'en-gb' } } }), []) + assert.containSubset( + await getFilteredSubs({ + server, + event: { topic, payload: { language: 'en' } }, + }), + [{ topic, id: '2' }], + ) + assert.deepEqual( + await getFilteredSubs({ + server, + event: { topic, payload: { language: 'en-gb' } }, + }), + [], + ) + }) + + it('can match on nested payload', async () => { + const topic = makeTopic() + const server = await mockServerContext() + const subscription = { + id: '2', + topic, + filter: { meta: { user: 'foo' }, message: { content: 'hi' } }, + subscriptionId: '2', + subscription: {} as any, + connectionId: 'abcd', + connectionInitPayload: {}, + requestContext: {} as any, + ttl: Math.floor(Date.now() / 1000) + 100000, + createdAt: Date.now(), + } + + await server.models.subscription.put(subscription) + + assert.containSubset( + await getFilteredSubs({ + server, + event: { + topic, + payload: { meta: { user: 'foo' }, message: { content: 'hi' } }, + }, + }), + [{ topic, id: '2' }], + ) + assert.deepEqual( + await getFilteredSubs({ + server, + event: { + topic, + payload: { meta: { user: 'lol' }, message: { content: 'bye' } }, + }, + }), + [], + ) }) it('can match on no payload', async () => { diff --git a/lib/pubsub/getFilteredSubs.ts b/lib/pubsub/getFilteredSubs.ts index ccf7c0aa..7e701392 100644 --- a/lib/pubsub/getFilteredSubs.ts +++ b/lib/pubsub/getFilteredSubs.ts @@ -2,7 +2,13 @@ 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, +}: { + server: Omit + event: { topic: string, payload?: Record } +}): Promise => { if (!event.payload || Object.keys(event.payload).length === 0) { server.log('getFilteredSubs', { event }) @@ -18,18 +24,35 @@ export const getFilteredSubs = async ({ server, event }: { server: Omit `#${aliasNumber + index}`) + .join('.') + key.split('.').forEach((keyPart, index) => { + expressionAttributeNames[`#${aliasNumber + index}`] = keyPart + attributeCounter += index + }) expressionAttributeValues[`:${aliasNumber}`] = value - filterExpressions.push(`(#filter.#${aliasNumber} = :${aliasNumber} OR attribute_not_exists(#filter.#${aliasNumber}))`) + + filterExpressions.push( + `(#filter.${keyPartsAttributeName} = :${aliasNumber} OR attribute_not_exists(#filter.${keyPartsAttributeName}))`, + ) } - server.log('getFilteredSubs', { event, expressionAttributeNames, expressionAttributeValues, filterExpressions }) + server.log('getFilteredSubs', { + event, + expressionAttributeNames, + expressionAttributeValues, + filterExpressions, + }) const iterator = server.models.subscription.query({ IndexName: 'TopicIndex', @@ -54,7 +77,11 @@ export const collapseKeys = ( ): Record => { const record = {} for (const [k1, v1] of Object.entries(obj)) { - if (typeof v1 === 'string' || typeof v1 === 'number' || typeof v1 === 'boolean') { + if ( + typeof v1 === 'string' || + typeof v1 === 'number' || + typeof v1 === 'boolean' + ) { record[k1] = v1 continue }