Skip to content

Commit

Permalink
feat(search*)!: add incremental driver call (#2455)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `DaffSearchDriverInterface#incremental` was added
  • Loading branch information
griest024 committed May 25, 2023
1 parent 52cdbb1 commit d112bcd
Show file tree
Hide file tree
Showing 15 changed files with 273 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,43 @@ describe('@daffodil/search-category/driver/magento | DaffSearchCategoryMagentoDr
});
});
});

describe('incremental | searching for categories', () => {
describe('when the call to the Magento API is successful', () => {
it('should return a collection of category search results', done => {
service.incremental('query').subscribe(result => {
expect(result.collection[DAFF_SEARCH_CATEGORY_RESULT_KIND][0].id).toEqual(mockCategory.uid);
done();
});

const op = controller.expectOne(categorySearch());

op.flushData(mockGetCategoriesResponse);
});
});

describe('when the call to the Magento API is unsuccessful', () => {
it('should throw an Error', done => {
service.incremental('query').pipe(
catchError(err => {
expect(err).toEqual(jasmine.any(Error));
done();
return [];
}),
).subscribe();

const op = controller.expectOne(categorySearch());

op.graphqlErrors([new GraphQLError(
'Can\'t find any categories matching that query.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)]);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,8 @@ export class DaffSearchCategoryMagentoDriver implements DaffSearchCategoryDriver
catchError(err => throwError(() => transformSearchCategoryMagentoError(err))),
);
}

incremental(query: string, options: DaffSearchDriverOptions = {}): Observable<DaffSearchDriverResponse<DaffSearchCategoryResult>> {
return this.search(query, options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,50 @@ describe('@daffodil/search-product/driver/magento | DaffSearchProductMagentoDriv
});
});
});

describe('incremental | searching for products', () => {
describe('when the call to the Magento API is successful', () => {
it('should return a collection of product search results', done => {
service.incremental('query').subscribe(result => {
expect(result.collection[DAFF_SEARCH_PRODUCT_RESULT_KIND][0].id).toEqual(mockSimpleProduct.sku);
expect((<DaffCollectionMetadata>result.metadata).count).toEqual(mockSearchProductsResponse.products.total_count);
done();
});

const searchOp = controller.expectOne(addTypenameToDocument(productSearch()));
const filterOp = controller.expectOne(addTypenameToDocument(MagentoProductGetFilterTypes));

searchOp.flush({
data: mockSearchProductsResponse,
});
filterOp.flush({
data: mockGetFilterTypesResponse,
});
});
});

describe('when the call to the Magento API is unsuccessful', () => {
it('should throw an Error', done => {
service.incremental('query').pipe(
catchError(err => {
expect(err).toEqual(jasmine.any(Error));
done();
return [];
}),
).subscribe();

const op = controller.expectOne(addTypenameToDocument(productSearch()));

op.graphqlErrors([new GraphQLError(
'Can\'t find any products matching that query.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)]);
});
});
});
});
65 changes: 64 additions & 1 deletion libs/search-product/driver/magento/src/product-search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import {
MAGENTO_PRODUCT_CONFIG_TOKEN,
magentoProductCollectionMetadataTransform,
magentoAppliedSortOptionTransform,
DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_FRAGMENTS,
DAFF_PRODUCT_MAGENTO_PRODUCT_TRANSFORM,
DaffMagentoProductTransform,
} from '@daffodil/product/driver/magento';
import { daffSearchTransformResultsToCollection } from '@daffodil/search';
import {
Expand Down Expand Up @@ -54,14 +57,16 @@ export class DaffSearchProductMagentoDriver implements DaffSearchProductDriverIn
constructor(
private apollo: Apollo,
private productFilterRequestsTransformer: MagentoProductAppliedFiltersTransformService,
@Inject(DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_FRAGMENTS) private extraFragments: DocumentNode[],
@Inject(DAFF_PRODUCT_MAGENTO_EXTRA_PRODUCT_PREVIEW_FRAGMENTS) private extraPreviewFragments: DocumentNode[],
private magentoProductsTransformers: DaffMagentoProductsTransformer,
@Inject(MAGENTO_PRODUCT_CONFIG_TOKEN) private config: DaffProductMagentoDriverConfig,
@Inject(DAFF_PRODUCT_MAGENTO_PRODUCT_TRANSFORM) private magentoProductsTransform: DaffMagentoProductTransform,
) {}

readonly kind = DAFF_SEARCH_PRODUCT_RESULT_KIND;

search(query: string, options: DaffSearchProductDriverOptions = {}): Observable<DaffSearchProductDriverResponse> {
private getVariables(options: DaffSearchProductDriverOptions = {}) {
const queryVariables = {
filter: this.productFilterRequestsTransformer.transform(options.filterRequests),
};
Expand All @@ -74,6 +79,64 @@ export class DaffSearchProductMagentoDriver implements DaffSearchProductDriverIn
if (options.appliedSortOption && options.appliedSortDirection) {
queryVariables['sort'] = magentoAppliedSortOptionTransform(options.appliedSortOption, options.appliedSortDirection);
}
return queryVariables;
}

search(query: string, options: DaffSearchProductDriverOptions = {}): Observable<DaffSearchProductDriverResponse> {
const queryVariables = this.getVariables(options);

return combineLatest([
this.apollo.query<MagentoSearchForProductsResponse>({
query: productSearch([
...this.extraPreviewFragments,
...this.extraFragments,
]),
variables: {
...queryVariables,
search: query,
},
}),
this.apollo.query<MagentoProductGetFilterTypesResponse>({
query: MagentoProductGetFilterTypes,
}),
]).pipe(
map(([products, filters]) => ({
products: products.data.products.items,
filters: magentoProductAddMetadataTypesToAggregates(
filters.data.__type.inputFields,
products.data.products.aggregations,
),
sortFields: products.data.products.sort_fields,
pageInfo: products.data.products.page_info,
count: products.data.products.total_count,
})),
map(({ products, filters, sortFields, pageInfo, count }) => ({
products: daffSearchTransformResultsToCollection(daffTransformProductsToSearchResults(
products.map((product) => this.magentoProductsTransform(product, this.config.baseMediaUrl)),
)),
metadata: magentoProductCollectionMetadataTransform(
filters,
pageInfo,
sortFields,
products,
count,
options.appliedSortOption,
options.appliedSortDirection,
),
})),
map(({ products, metadata }) => ({
collection: products,
metadata: {
...metadata,
filters: daffApplyRequestsToFilters(options.filterRequests || [], metadata.filters),
},
})),
catchError(err => throwError(() => transformSearchProductMagentoError(err))),
);
}

incremental(query: string, options: DaffSearchProductDriverOptions = {}): Observable<DaffSearchProductDriverResponse> {
const queryVariables = this.getVariables(options);

return combineLatest([
this.apollo.query<MagentoSearchForProductsResponse>({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ export interface DaffSearchProductDriverInterface<
readonly kind: typeof DAFF_SEARCH_PRODUCT_RESULT_KIND;

search(query: string, options?: DaffSearchProductDriverOptions): Observable<DaffSearchProductDriverResponse<T>>;
incremental(query: string, options?: DaffSearchProductDriverOptions): Observable<DaffSearchProductDriverResponse<T>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ class TestDriver1 implements DaffSearchDriverKindedInterface {
metadata: {},
});
}
incremental(query: string) {
return of({
collection: {},
metadata: {},
});
}
}

@Injectable({
Expand All @@ -36,6 +42,12 @@ class TestDriver2 implements DaffSearchDriverKindedInterface {
metadata: {},
});
}
incremental(query: string) {
return of({
collection: {},
metadata: {},
});
}
}

describe('@daffodil/search/driver/federated | daffProvideSearchFederatedDrivers', () => {
Expand Down
37 changes: 37 additions & 0 deletions libs/search/driver/federated/src/search.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ class TestDriver1 implements DaffSearchDriverKindedInterface {
metadata: {},
});
}

incremental(query: string) {
return of({
collection: {
testIncremental1: [],
},
metadata: {},
});
}
}

@Injectable({
Expand All @@ -45,6 +54,15 @@ class TestDriver2 implements DaffSearchDriverKindedInterface {
metadata: {},
});
}

incremental(query: string) {
return of({
collection: {
testIncremental2: [],
},
metadata: {},
});
}
}

describe('@daffodil/search/driver/federated | DaffSearchFederatedDriver', () => {
Expand Down Expand Up @@ -83,4 +101,23 @@ describe('@daffodil/search/driver/federated | DaffSearchFederatedDriver', () =>
expect(result).toBeObservable(expected);
});
});

describe('incremental | invoking injected drivers', () => {
let result: Observable<DaffSearchDriverResponse>;

beforeEach(() => {
result = service.incremental('query');
});

it('should invoke and collect the result from the injected drivers', () => {
const expected = cold('(a|)', { a: jasmine.objectContaining({
collection: {
testIncremental1: jasmine.truthy(),
testIncremental2: jasmine.truthy(),
},
}) });

expect(result).toBeObservable(expected);
});
});
});
12 changes: 12 additions & 0 deletions libs/search/driver/federated/src/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,16 @@ export class DaffSearchFederatedDriver implements DaffSearchDriverInterface {
})),
);
}

incremental(query: string, options: DaffSearchDriverOptions = {}): Observable<DaffSearchDriverResponse> {
return combineLatest(this.drivers.reduce<Record<string, Observable<DaffSearchDriverResponse>>>((acc, driver) => {
acc[driver.kind] = driver.incremental(query, options);
return acc;
}, {})).pipe(
map(responses => ({
collection: Object.assign({}, ...Object.values(responses).map(({ collection }) => collection)),
metadata: this.config.preferredDriverKind ? responses[this.config.preferredDriverKind].metadata : {},
})),
);
}
}
24 changes: 24 additions & 0 deletions libs/search/driver/in-memory/src/driver/search.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,28 @@ describe('@daffodil/search/driver/in-memory | DaffInMemorySearchDriver', () => {
req.flush(mockResponse);
});
});

describe('incremental', () => {
let query: string;
let url: string;
let result: ReturnType<DaffInMemorySearchDriver['incremental']>;

beforeEach(() => {
query = 'query';
url = `${service.url}?query=${query}`;
result = service.incremental(query);
});

it('should send a get request and return a collection of search results', done => {
result.subscribe((resp) => {
expect(resp).toEqual(mockResponse);
done();
});

const req = httpMock.expectOne(url);
expect(req.request.method).toBe('GET');

req.flush(mockResponse);
});
});
});
5 changes: 5 additions & 0 deletions libs/search/driver/in-memory/src/driver/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ export class DaffInMemorySearchDriver implements DaffSearchDriverInterface {
// TODO: handle options
return this.http.get<DaffSearchDriverResponse>(`${this.url}?query=${query}`);
}

incremental(query: string, options: DaffSearchDriverOptions = {}): Observable<DaffSearchDriverResponse> {
// TODO: handle options
return this.http.get<DaffSearchDriverResponse>(`${this.url}?query=${query}`);
}
}
8 changes: 8 additions & 0 deletions libs/search/driver/src/interfaces/search-service.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ export interface DaffSearchDriverInterface<
> {
/**
* Searches for entities according to the specified query.
* This method provides substantially more information than `incremental`.
* Its intended use is populating a page of search results.
*/
search(query: string, options?: DaffSearchDriverOptions): Observable<DaffSearchDriverResponse<T>>;

/**
* Rapidly searches for entities. This is intended to be called as the user types their search query.
* Less information is requested in comparison to `search`.
*/
incremental(query: string, options?: DaffSearchDriverOptions): Observable<DaffSearchDriverResponse<T>>;
}
7 changes: 7 additions & 0 deletions libs/search/driver/testing/src/drivers/search.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,11 @@ describe('@daffodil/driver/testing | DaffTestingSearchDriver', () => {
expect(service.search('query')).toBeObservable(expected);
});
});

describe('incremental', () => {
it('should return a DaffSearchResultCollection', () => {
const expected = cold('(a|)', { a: jasmine.notEmpty() });
expect(service.incremental('query')).toBeObservable(expected);
});
});
});
8 changes: 8 additions & 0 deletions libs/search/driver/testing/src/drivers/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ export class DaffTestingSearchDriver implements DaffSearchDriverInterface {
metadata: {},
});
}

incremental(query: string, options: DaffSearchDriverOptions = {}): Observable<DaffSearchDriverResponse> {
const limit = options.limit || 5;
return of({
collection: daffSearchTransformResultsToCollection(this.searchResultFactory.createMany(limit)),
metadata: {},
});
}
}
Loading

0 comments on commit d112bcd

Please sign in to comment.