Skip to content

Commit

Permalink
add message.find() support wechaty/wechaty#1534
Browse files Browse the repository at this point in the history
  • Loading branch information
huan committed Aug 11, 2018
1 parent 2929b9d commit 1175ea9
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
120 changes: 120 additions & 0 deletions src/puppet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import {
} from './schemas/friendship'
import {
MessagePayload,
MessagePayloadFilterFunction,
MessageQueryFilter,
MessageType,
} from './schemas/message'
import {
RoomMemberPayload,
Expand Down Expand Up @@ -112,6 +115,12 @@ class PuppetTest extends Puppet {
public async messageRawPayload (id: string) : Promise<any> { return { id } as any }
public async messageRawPayloadParser (rawPayload: any) : Promise<MessagePayload> { return { rawPayload } as any }

public messageQueryFilterFactory (
query: MessageQueryFilter,
): MessagePayloadFilterFunction {
return super.messageQueryFilterFactory(query)
}

/**
*
* Room Invitation
Expand Down Expand Up @@ -413,3 +422,114 @@ test('setMemory() memory with a name', async t => {
t.doesNotThrow(() => puppet.setMemory(memory), 'should not throw when set a named memory first time ')
t.throws(() => puppet.setMemory(memory), 'should throw when set a named memory second time')
})

test('messageQueryFilterFactory() one condition', async t => {
const EXPECTED_TEXT1 = 'text'
const EXPECTED_TEXT2 = 'regexp'
const EXPECTED_TEXT3 = 'fdsafasdfsdakljhj;lds'

const TEXT_QUERY_TEXT = EXPECTED_TEXT1
const TEXT_QUERY_RE = new RegExp(EXPECTED_TEXT2)

const QUERY_TEXT: MessageQueryFilter = {
text: TEXT_QUERY_TEXT,
}

const QUERY_RE: MessageQueryFilter = {
text: TEXT_QUERY_RE,
}

const PAYLOAD_LIST = [
{
text: EXPECTED_TEXT1,
},
{
text: EXPECTED_TEXT2,
},
{
text: EXPECTED_TEXT3,
},
] as MessagePayload[]

const puppet = new PuppetTest()

let filterFuncText
let resultPayload

filterFuncText = puppet.messageQueryFilterFactory(QUERY_TEXT)
resultPayload = PAYLOAD_LIST.filter(filterFuncText)
t.equal(resultPayload.length, 1, 'should get one result')
t.equal(resultPayload[0].text, EXPECTED_TEXT1, 'should get text1')

filterFuncText = puppet.messageQueryFilterFactory(QUERY_RE)
resultPayload = PAYLOAD_LIST.filter(filterFuncText)
t.equal(resultPayload.length, 1, 'should get one result')
t.equal(resultPayload[0].text, EXPECTED_TEXT2, 'should get text2')
})

test('messageQueryFilterFactory() two condition', async t => {
const EXPECTED_TEXT_DATA = 'data'
const EXPECTED_TEXT_LINK = 'https://google.com'

const EXPECTED_TYPE_URL = MessageType.Url
const EXPECTED_TYPE_TEXT = MessageType.Text

const QUERY_TEXT: MessageQueryFilter = {
text: EXPECTED_TEXT_DATA,
}

const QUERY_TYPE: MessageQueryFilter = {
type: EXPECTED_TYPE_URL,
}

const QUERY_TYPE_TEXT: MessageQueryFilter = {
text: EXPECTED_TEXT_DATA,
type: EXPECTED_TYPE_URL,
}

const PAYLOAD_LIST = [
{
text: EXPECTED_TEXT_DATA,
type: MessageType.Text
},
{
text: EXPECTED_TEXT_DATA,
type: MessageType.Url
},
{
text: EXPECTED_TEXT_LINK,
type: MessageType.Text
},
{
text: EXPECTED_TEXT_LINK,
type: MessageType.Url,
},
] as MessagePayload[]

const puppet = new PuppetTest()

let filterFuncText
let resultPayload

filterFuncText = puppet.messageQueryFilterFactory(QUERY_TEXT)
resultPayload = PAYLOAD_LIST.filter(filterFuncText)
t.equal(resultPayload.length, 2, 'should get two result')
t.equal(resultPayload[0].text, EXPECTED_TEXT_DATA, 'should get text data')
t.equal(resultPayload[0].type, EXPECTED_TYPE_TEXT, 'should get type text')
t.equal(resultPayload[1].text, EXPECTED_TEXT_DATA, 'should get text data')
t.equal(resultPayload[1].type, EXPECTED_TYPE_URL, 'should get type url')

filterFuncText = puppet.messageQueryFilterFactory(QUERY_TYPE)
resultPayload = PAYLOAD_LIST.filter(filterFuncText)
t.equal(resultPayload.length, 2, 'should get two result')
t.equal(resultPayload[0].text, EXPECTED_TEXT_DATA, 'should get text data')
t.equal(resultPayload[0].type, EXPECTED_TYPE_URL, 'should get type url')
t.equal(resultPayload[1].text, EXPECTED_TEXT_LINK, 'should get text link')
t.equal(resultPayload[1].type, EXPECTED_TYPE_URL, 'should get type url ')

filterFuncText = puppet.messageQueryFilterFactory(QUERY_TYPE_TEXT)
resultPayload = PAYLOAD_LIST.filter(filterFuncText)
t.equal(resultPayload.length, 1, 'should get one result')
t.equal(resultPayload[0].text, EXPECTED_TEXT_DATA, 'should get text data')
t.equal(resultPayload[0].type, EXPECTED_TYPE_URL, 'should get type url')
})
75 changes: 75 additions & 0 deletions src/puppet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ import {
} from './schemas/friendship'
import {
MessagePayload,
MessagePayloadFilterFunction,
MessageQueryFilter,
MessageType,
} from './schemas/message'
import {
RoomMemberPayload,
Expand Down Expand Up @@ -811,6 +814,78 @@ export abstract class Puppet extends EventEmitter {
return payload
}

public messageList (): string[] {
log.verbose('Puppet', 'messageList()')
return this.cacheMessagePayload.keys()
}

public async messageSearch (
query?: MessageQueryFilter,
): Promise<string[] /* Message Id List*/> {
log.verbose('Puppet', 'messageSearch(%s)', JSON.stringify(query))

const allMessageIdList: string[] = this.messageList()
log.silly('Puppet', 'messageSearch() allMessageIdList.length=%d', allMessageIdList.length)

if (!query || Object.keys(query).length <= 0) {
return allMessageIdList
}

const messagePayloadList: MessagePayload[] = await Promise.all(
allMessageIdList.map(
id => this.messagePayload(id)
),
)

const filterFunction = this.messageQueryFilterFactory(query)

const messageIdList = messagePayloadList
.filter(filterFunction)
.map(payload => payload.id)

log.silly('Puppet', 'messageSearch() messageIdList filtered. result length=%d', messageIdList.length)

return messageIdList
}

protected messageQueryFilterFactory (
query: MessageQueryFilter,
): MessagePayloadFilterFunction {
log.verbose('Puppet', 'messageQueryFilterFactory(%s)',
JSON.stringify(query),
)

if (Object.keys(query).length < 1) {
throw new Error('query empty')
}

const filterFunctionList: MessagePayloadFilterFunction[] = []

// TypeScript bug: have to set `undefined | string | RegExp` at here, or the later code type check will get error
const filterKeyList = Object.keys(query) as Array<keyof MessageQueryFilter>

for (const filterKey of filterKeyList) {
const filterValue: undefined | string | MessageType | RegExp = query[filterKey]
if (!filterValue) {
throw new Error('filterValue not found for filterKey: ' + filterKey)
}

let filterFunction: MessagePayloadFilterFunction

if (filterValue instanceof RegExp) {
filterFunction = (payload: MessagePayload) => filterValue.test(payload[filterKey] as string)
} else { // if (typeof filterValue === 'string') {
filterFunction = (payload: MessagePayload) => filterValue === payload[filterKey]
}

filterFunctionList.push(filterFunction)
}

const allFilterFunction: MessagePayloadFilterFunction = payload => filterFunctionList.every(func => func(payload))

return allFilterFunction
}

/**
*
* Room Invitation
Expand Down
14 changes: 14 additions & 0 deletions src/schemas/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,17 @@ export type MessagePayload = MessagePayloadBase
MessagePayloadRoom
| MessagePayloadTo
)

export interface MessageQueryFilter {
fromId? : string,
text? : string | RegExp,
roomId? : string
type? : MessageType,
toId? : string,
}

/** @hidden */
export type MessagePayloadFilterFunction = (payload: MessagePayload) => boolean

/** @hidden */
export type MessagePayloadFilterFactory = (query: MessageQueryFilter) => MessagePayloadFilterFunction

0 comments on commit 1175ea9

Please sign in to comment.