Skip to content
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

Allow multiple searches in the state #93

Merged
merged 12 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions libs/search/src/lib/elasticsearch/elasticsearch.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ElasticsearchService, initialState } from '@lib/search'
import {
DEFAULT_SEARCH_KEY,
ElasticsearchService,
initialState,
} from '@lib/search'

const initialStateSearch = initialState[DEFAULT_SEARCH_KEY]

describe('ElasticsearchService', () => {
let service: ElasticsearchService
Expand All @@ -15,7 +21,7 @@ describe('ElasticsearchService', () => {
describe('#Sort', () => {
it('One sort and default direction', () => {
const body = service.buildPayload({
...initialState,
...initialStateSearch,
params: {
filters: {
any: '',
Expand All @@ -28,7 +34,7 @@ describe('ElasticsearchService', () => {

it('One sort and DESC direction', () => {
const body = service.buildPayload({
...initialState,
...initialStateSearch,
params: {
filters: {
any: '',
Expand All @@ -41,7 +47,7 @@ describe('ElasticsearchService', () => {

it('Multiple sorts', () => {
const body = service.buildPayload({
...initialState,
...initialStateSearch,
params: {
filters: {
any: '',
Expand Down
16 changes: 11 additions & 5 deletions libs/search/src/lib/elasticsearch/elasticsearch.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'
import { SortParams } from '@lib/common'
import { NameList, SearchParams } from 'elasticsearch'
import { SearchState } from '../state/reducer'
import { SearchState, SearchStateSearch } from '../state/reducer'
import { ElasticsearchMetadataModels, ElasticSearchSources } from './constant'

@Injectable({
Expand All @@ -10,13 +10,16 @@ import { ElasticsearchMetadataModels, ElasticSearchSources } from './constant'
export class ElasticsearchService {
constructor() {}

search(state: SearchState, model: ElasticsearchMetadataModels): SearchParams {
search(
state: SearchStateSearch,
model: ElasticsearchMetadataModels
): SearchParams {
const payload = this.buildPayload(state)
payload._source = ElasticSearchSources[model]
return payload
}

buildPayload(state: SearchState): SearchParams {
buildPayload(state: SearchStateSearch): SearchParams {
const { size, sortBy, from } = state.params
const sort: SortParams = sortBy
? sortBy.split(',').map((s) => {
Expand All @@ -38,7 +41,10 @@ export class ElasticsearchService {
return payload
}

buildMoreOnAggregationPayload(state: SearchState, key: string): SearchParams {
buildMoreOnAggregationPayload(
state: SearchStateSearch,
key: string
): SearchParams {
const payload = {
aggregations: { [key]: state.config.aggregations[key] },
size: 0,
Expand All @@ -47,7 +53,7 @@ export class ElasticsearchService {
return payload
}

partialBuildQuery(state: SearchState) {
partialBuildQuery(state: SearchStateSearch) {
const filters = state.params.filters
const { any, ...searchFilters } = filters
const queryFilters = this.facetsToLuceneQuery(searchFilters)
Expand Down
123 changes: 87 additions & 36 deletions libs/search/src/lib/state/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,103 +27,154 @@ export const UPDATE_REQUEST_AGGREGATION_TERM =
'[Search] Update request aggregation term'
export const PATCH_RESULTS_AGGREGATIONS = '[Search] Patch Results Aggregations'

export class SetFilters implements Action {
export const DEFAULT_SEARCH_KEY = 'default'

abstract class AbstractAction {
id?: string
protected constructor(id?: string) {
this.id = id || DEFAULT_SEARCH_KEY
}
}

export class SetFilters extends AbstractAction implements Action {
readonly type = SET_FILTERS

constructor(public payload: SearchFilters) {}
constructor(public payload: SearchFilters, id?: string) {
super(id)
}
}

export class UpdateFilters implements Action {
export class UpdateFilters extends AbstractAction implements Action {
readonly type = UPDATE_FILTERS

constructor(public payload: SearchFilters) {}
constructor(public payload: SearchFilters, id?: string) {
super(id)
}
}

export class SetSearch implements Action {
export class SetSearch extends AbstractAction implements Action {
readonly type = SET_SEARCH

constructor(public payload: SearchStateParams) {}
constructor(public payload: SearchStateParams, id?: string) {
super(id)
}
}

export class SetSortBy implements Action {
export class SetSortBy extends AbstractAction implements Action {
readonly type = SET_SORT_BY
constructor(public sortBy: string) {}
constructor(public sortBy: string, id?: string) {
super(id)
}
}

export class SetPagination implements Action {
export class SetPagination extends AbstractAction implements Action {
readonly type = SET_PAGINATION
constructor(public from: number, public size: number) {}
constructor(public from: number, public size: number, id?: string) {
super(id)
}
}

export class Paginate implements Action {
export class Paginate extends AbstractAction implements Action {
readonly type = PAGINATE
constructor(public delta: number) {}
constructor(public delta: number, id?: string) {
super(id)
}
}

export class Scroll implements Action {
export class Scroll extends AbstractAction implements Action {
readonly type = SCROLL
constructor() {}
constructor(id?: string) {
super(id)
}
}

export class SetResultsLayout implements Action {
export class SetResultsLayout extends AbstractAction implements Action {
readonly type = SET_RESULTS_LAYOUT

constructor(public resultsLayout: string) {}
constructor(public resultsLayout: string, id?: string) {
super(id)
}
}

export class AddResults implements Action {
export class AddResults extends AbstractAction implements Action {
readonly type = ADD_RESULTS

constructor(public payload: RecordSummary[]) {}
constructor(public payload: RecordSummary[], id?: string) {
super(id)
}
}

export class ClearResults implements Action {
export class ClearResults extends AbstractAction implements Action {
readonly type = CLEAR_RESULTS

constructor() {}
constructor(id?: string) {
super(id)
}
}

export class RequestMoreResults implements Action {
export class RequestMoreResults extends AbstractAction implements Action {
readonly type = REQUEST_MORE_RESULTS

constructor() {}
constructor(id?: string) {
super(id)
}
}

export class SetResultsAggregations implements Action {
export class SetResultsAggregations extends AbstractAction implements Action {
readonly type = SET_RESULTS_AGGREGATIONS

constructor(public payload: any) {}
constructor(public payload: any, id?: string) {
super(id)
}
}

export class SetResultsHits implements Action {
export class SetResultsHits extends AbstractAction implements Action {
readonly type = SET_RESULTS_HITS
constructor(public payload: any) {}
constructor(public payload: any, id?: string) {
super(id)
}
}

export class SetConfigAggregations implements Action {
export class SetConfigAggregations extends AbstractAction implements Action {
readonly type = SET_CONFIG_AGGREGATIONS
constructor(public payload: any) {}
constructor(public payload: any, id?: string) {
super(id)
}
}

export class RequestMoreOnAggregation implements Action {
export class RequestMoreOnAggregation extends AbstractAction implements Action {
readonly type = REQUEST_MORE_ON_AGGREGATION
constructor(public key: string, public increment: number) {}
constructor(public key: string, public increment: number, id?: string) {
super(id)
}
}

export class SetIncludeOnAggregation implements Action {
export class SetIncludeOnAggregation extends AbstractAction implements Action {
readonly type = SET_INCLUDE_ON_AGGREGATION
constructor(public key: string, public include: string) {}
constructor(public key: string, public include: string, id?: string) {
super(id)
}
}

export class UpdateRequestAggregationTerm implements Action {
export class UpdateRequestAggregationTerm
extends AbstractAction
implements Action {
readonly type = UPDATE_REQUEST_AGGREGATION_TERM
constructor(public key: string, public patch: EsRequestAggTermPatch) {}
constructor(
public key: string,
public patch: EsRequestAggTermPatch,
id?: string
) {
super(id)
}
}

export class PatchResultsAggregations implements Action {
export class PatchResultsAggregations extends AbstractAction implements Action {
readonly type = PATCH_RESULTS_AGGREGATIONS

constructor(public key: string, public payload: any) {}
constructor(public key: string, public payload: any, id?: string) {
super(id)
}
}

export type SearchActions =
Expand Down
37 changes: 28 additions & 9 deletions libs/search/src/lib/state/effects.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { TestBed } from '@angular/core/testing'
import { AuthService } from '@lib/auth'
import { SearchApiService } from '@lib/gn-api'
import { ElasticsearchMapper } from '../elasticsearch/elasticsearch.mapper'
import {
ElasticsearchMapper,
DEFAULT_SEARCH_KEY,
Scroll,
SetIncludeOnAggregation,
UpdateRequestAggregationTerm,
} from '@lib/search'
} from './actions'
import { EffectsModule } from '@ngrx/effects'
import { provideMockActions } from '@ngrx/effects/testing'
import { StoreModule } from '@ngrx/store'
Expand All @@ -29,10 +30,17 @@ import { SearchEffects } from './effects'
import { ES_FIXTURE_AGGS_REQUEST } from '../elasticsearch/fixtures/aggregations-request'
import { initialState, reducer, SEARCH_FEATURE_KEY } from './reducer'

const initialStateSearchMock = initialState[DEFAULT_SEARCH_KEY]
const initialStateMock = {
...initialState,
config: {
aggregations: ES_FIXTURE_AGGS_REQUEST,
[DEFAULT_SEARCH_KEY]: {
...initialStateSearchMock,
config: {
aggregations: ES_FIXTURE_AGGS_REQUEST,
},
},
main: {
...initialStateSearchMock,
},
}

Expand Down Expand Up @@ -118,11 +126,11 @@ describe('Effects', () => {
})
it('clear results list on setSearch action', () => {
actions$ = hot('-a---', {
a: new SetSearch({ filters: { any: 'abcd' } }),
a: new SetSearch({ filters: { any: 'abcd' } }, 'main'),
})
const expected = hot('-(bc)', {
b: new ClearResults(),
c: new RequestMoreResults(),
b: new ClearResults('main'),
c: new RequestMoreResults('main'),
})

expect(effects.clearResults$).toBeObservable(expected)
Expand All @@ -131,9 +139,9 @@ describe('Effects', () => {

describe('scroll$', () => {
it('clear results list on sortBy action', () => {
actions$ = hot('-a---', { a: new Scroll() })
actions$ = hot('-a---', { a: new Scroll('main') })
const expected = hot('-(b)', {
b: new RequestMoreResults(),
b: new RequestMoreResults('main'),
})
expect(effects.scroll$).toBeObservable(expected)
})
Expand All @@ -150,6 +158,17 @@ describe('Effects', () => {

expect(effects.loadResults$).toBeObservable(expected)
})

it('propagate action search id', () => {
actions$ = hot('-a-', { a: new RequestMoreResults('main') })
const expected = hot('-(bcd)-', {
b: new AddResults([], 'main'),
c: new SetResultsAggregations({ abc: {} }, 'main'),
d: new SetResultsHits(undefined, 'main'),
})

expect(effects.loadResults$).toBeObservable(expected)
})
})

describe('loadMoreOnAggregation$', () => {
Expand Down
Loading