-
Notifications
You must be signed in to change notification settings - Fork 157
feat(search-client): Add support for Custom Search Clients #432
Changes from 4 commits
a6ab032
f5651ce
39179bf
ebe4647
7d807e5
346019a
03fa0d2
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 |
---|---|---|
|
@@ -5,7 +5,10 @@ | |
</template> | ||
|
||
<script> | ||
import { createFromAlgoliaCredentials } from '../store'; | ||
import { | ||
createFromAlgoliaCredentials, | ||
createFromAlgoliaClient, | ||
} from '../store'; | ||
import algoliaComponent from '../component'; | ||
|
||
export default { | ||
|
@@ -17,6 +20,9 @@ export default { | |
return this._searchStore; | ||
}, | ||
}, | ||
searchClient: { | ||
type: Object, | ||
}, | ||
apiKey: { | ||
type: String, | ||
default() { | ||
|
@@ -73,14 +79,46 @@ export default { | |
}; | ||
}, | ||
provide() { | ||
if (!this.searchStore) { | ||
this._localSearchStore = createFromAlgoliaCredentials( | ||
this.appId, | ||
this.apiKey, | ||
{ stalledSearchDelay: this.stalledSearchDelay } | ||
); | ||
if (this.searchClient) { | ||
if (!this.indexName) { | ||
throw new Error( | ||
'vue-instantsearch: `indexName` is required with `searchClient`' | ||
); | ||
} | ||
|
||
if (this.searchStore) { | ||
throw new Error('`searchStore` cannot be used with `searchClient`'); | ||
} | ||
|
||
if (this.appId) { | ||
throw new Error( | ||
'vue-instantsearch: `appId` cannot be used with `searchClient`' | ||
); | ||
} | ||
|
||
if (this.apiKey) { | ||
throw new Error( | ||
'vue-instantsearch: `apiKey` cannot be used with `searchClient`' | ||
); | ||
} | ||
|
||
if (typeof this.searchClient.search !== 'function') { | ||
throw new Error( | ||
'vue-instantsearch: `searchClient` must implement a method `search(requests)`' | ||
); | ||
} | ||
|
||
this._localSearchStore = createFromAlgoliaClient(Object.create(this.searchClient)); | ||
} else { | ||
this._localSearchStore = this.searchStore; | ||
if (!this.searchStore) { | ||
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. can be changed to 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. Yep, ESLint is never happy with that ahah. |
||
this._localSearchStore = createFromAlgoliaCredentials( | ||
this.appId, | ||
this.apiKey, | ||
{ stalledSearchDelay: this.stalledSearchDelay } | ||
); | ||
} else { | ||
this._localSearchStore = this.searchStore; | ||
} | ||
} | ||
|
||
if (this.indexName) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Search Client API collision and apiKey 1`] = `"vue-instantsearch: \`apiKey\` cannot be used with \`searchClient\`"`; | ||
|
||
exports[`Search Client API collision and appId 1`] = `"vue-instantsearch: \`appId\` cannot be used with \`searchClient\`"`; | ||
|
||
exports[`Search Client API collision and searchStore 1`] = `"\`searchStore\` cannot be used with \`searchClient\`"`; | ||
|
||
exports[`Search Client API collision without indexName 1`] = `"vue-instantsearch: \`indexName\` is required with \`searchClient\`"`; | ||
|
||
exports[`Search Client Properties throws if no \`search()\` method 1`] = `"vue-instantsearch: \`searchClient\` must implement a method \`search(requests)\`"`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import Vue from 'vue'; | ||
import Index from '../Index.vue'; | ||
|
||
describe('Search Client', () => { | ||
describe('Properties', () => { | ||
it('throws if no `search()` method', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
indexName: 'indexName', | ||
searchClient: {}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
}); | ||
|
||
describe('API collision', () => { | ||
test('and indexName', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
indexName: 'indexName', | ||
searchClient: { | ||
search() { | ||
return Promise.resolve({ results: [{ hits: [] }] }); | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).not.toThrow(); | ||
}); | ||
|
||
test('without indexName', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
searchClient: { | ||
search() { | ||
return Promise.resolve({ results: [{ hits: [] }] }); | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
|
||
test('and appId', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
indexName: 'indexName', | ||
appId: 'appId', | ||
searchClient: { | ||
search() { | ||
return Promise.resolve({ results: [{ hits: [] }] }); | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
|
||
test('and apiKey', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
indexName: 'indexName', | ||
apiKey: 'apiKey', | ||
searchClient: { | ||
search() { | ||
return Promise.resolve({ results: [{ hits: [] }] }); | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
|
||
test('and searchStore', () => { | ||
expect(() => { | ||
const Component = Vue.extend(Index); | ||
|
||
const vm = new Component({ | ||
propsData: { | ||
indexName: 'indexName', | ||
searchStore: {}, | ||
searchClient: { | ||
search() { | ||
return Promise.resolve({ results: [{ hits: [] }] }); | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
vm.$mount(); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,7 +86,11 @@ export class Store { | |
this._helper.on('result', onHelperResult.bind(this)); | ||
this._helper.on('search', onHelperSearch.bind(this)); | ||
|
||
this._helper.getClient().addAlgoliaAgent(`vue-instantsearch ${version}`); | ||
const client = this._helper.getClient(); | ||
|
||
if (typeof client.addAlgoliaAgent === 'function') { | ||
client.addAlgoliaAgent(`vue-instantsearch ${version}`); | ||
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. I wonder if we could add this conditionally in the helper so we can call it without checking here 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. I'm OK with this change. It's yet another helper upgrade though haha. WDYT @bobylito? |
||
} | ||
|
||
this._stalledSearchTimer = null; | ||
this.isSearchStalled = true; | ||
|
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.
Object.create()
is not necessary here. I will remove it.