@internetarchive/search-service
Advanced tools
Comparing version 0.0.1-alpha.11 to 0.0.1-alpha.12
export { Metadata } from './src/models/metadata'; | ||
export { File } from './src/models/file'; | ||
export { Item } from './src/models/item'; | ||
export { DateField, NumberField, DurationField, StringField, BooleanField, } from './src/models/metadata-fields/field-types'; | ||
export { NumberParser, StringParser, DateParser, DurationParser, BooleanParser, } from './src/models/metadata-fields/field-parsers'; | ||
export { DateField, DateParser, } from './src/models/metadata-fields/field-types/date'; | ||
export { NumberField, NumberParser, } from './src/models/metadata-fields/field-types/number'; | ||
export { StringField, StringParser, } from './src/models/metadata-fields/field-types/string'; | ||
export { BooleanField, BooleanParser, } from './src/models/metadata-fields/field-types/boolean'; | ||
export { DurationField, DurationParser, } from './src/models/metadata-fields/field-types/duration'; | ||
export { PageProgressionField, PageProgressionParser, PageProgression, } from './src/models/metadata-fields/field-types/page-progression'; | ||
export { MetadataField } from './src/models/metadata-fields/metadata-field'; | ||
@@ -12,5 +16,5 @@ export { SpeechMusicASREntry } from './src/models/speech-music-asr-entry'; | ||
export { SearchResponseParams } from './src/responses/search/search-response-params'; | ||
export { DefaultSearchBackend } from './src/default-search-backend'; | ||
export { DefaultSearchBackend } from './src/search-backend/default-search-backend'; | ||
export { SearchServiceInterface } from './src/search-service-interface'; | ||
export { SearchService } from './src/search-service'; | ||
export { SearchParams } from './src/search-params'; |
export { Metadata } from './src/models/metadata'; | ||
export { File } from './src/models/file'; | ||
export { Item } from './src/models/item'; | ||
export { DateField, NumberField, DurationField, StringField, BooleanField, } from './src/models/metadata-fields/field-types'; | ||
export { NumberParser, StringParser, DateParser, DurationParser, BooleanParser, } from './src/models/metadata-fields/field-parsers'; | ||
export { DateField, DateParser, } from './src/models/metadata-fields/field-types/date'; | ||
export { NumberField, NumberParser, } from './src/models/metadata-fields/field-types/number'; | ||
export { StringField, StringParser, } from './src/models/metadata-fields/field-types/string'; | ||
export { BooleanField, BooleanParser, } from './src/models/metadata-fields/field-types/boolean'; | ||
export { DurationField, DurationParser, } from './src/models/metadata-fields/field-types/duration'; | ||
export { PageProgressionField, PageProgressionParser, PageProgression, } from './src/models/metadata-fields/field-types/page-progression'; | ||
export { MetadataField } from './src/models/metadata-fields/metadata-field'; | ||
@@ -12,5 +16,5 @@ export { SpeechMusicASREntry } from './src/models/speech-music-asr-entry'; | ||
export { SearchResponseParams } from './src/responses/search/search-response-params'; | ||
export { DefaultSearchBackend } from './src/default-search-backend'; | ||
export { DefaultSearchBackend } from './src/search-backend/default-search-backend'; | ||
export { SearchService } from './src/search-service'; | ||
export { SearchParams } from './src/search-params'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import { DurationField, NumberField } from './metadata-fields/field-types'; | ||
import { Duration } from './metadata-fields/field-types/duration'; | ||
/** | ||
@@ -18,8 +18,8 @@ * This represents an Internet Archive File | ||
original?: string; | ||
size?: NumberField; | ||
size?: number; | ||
title?: string; | ||
length?: DurationField; | ||
height?: NumberField; | ||
width?: NumberField; | ||
track?: NumberField; | ||
length?: Duration; | ||
height?: number; | ||
width?: number; | ||
track?: number; | ||
external_identifier?: string; | ||
@@ -26,0 +26,0 @@ creator?: string; |
/* eslint-disable @typescript-eslint/camelcase */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { DurationField, NumberField } from './metadata-fields/field-types'; | ||
import { DurationParser, } from './metadata-fields/field-types/duration'; | ||
import { NumberParser } from './metadata-fields/field-types/number'; | ||
/** | ||
@@ -21,8 +22,18 @@ * This represents an Internet Archive File | ||
this.original = json.original; | ||
this.size = json.size ? new NumberField(json.size) : undefined; | ||
this.title = json.title; | ||
this.length = json.length ? new DurationField(json.length) : undefined; | ||
this.height = json.height ? new NumberField(json.height) : undefined; | ||
this.width = json.width ? new NumberField(json.width) : undefined; | ||
this.track = json.track ? new NumberField(json.track) : undefined; | ||
this.length = json.length | ||
? DurationParser.shared.parseValue(json.length) | ||
: undefined; | ||
this.size = json.size | ||
? NumberParser.shared.parseValue(json.size) | ||
: undefined; | ||
this.height = json.height | ||
? NumberParser.shared.parseValue(json.height) | ||
: undefined; | ||
this.width = json.width | ||
? NumberParser.shared.parseValue(json.width) | ||
: undefined; | ||
this.track = json.track | ||
? NumberParser.shared.parseValue(json.track) | ||
: undefined; | ||
this.external_identifier = json['external-identifier']; | ||
@@ -29,0 +40,0 @@ this.creator = json.creator; |
@@ -1,17 +0,1 @@ | ||
import { MetadataField } from './metadata-field'; | ||
import { Duration, DateParser, DurationParser, NumberParser, StringParser, BooleanParser } from './field-parsers'; | ||
export declare class DateField extends MetadataField<Date, DateParser> { | ||
constructor(rawValue: any); | ||
} | ||
export declare class DurationField extends MetadataField<Duration, DurationParser> { | ||
constructor(rawValue: any); | ||
} | ||
export declare class NumberField extends MetadataField<number, NumberParser> { | ||
constructor(rawValue: any); | ||
} | ||
export declare class StringField extends MetadataField<string, StringParser> { | ||
constructor(rawValue: any); | ||
} | ||
export declare class BooleanField extends MetadataField<boolean, BooleanParser> { | ||
constructor(rawValue: any); | ||
} | ||
export declare type PageProgression = 'rl' | 'lr'; |
@@ -1,36 +0,2 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { MetadataField } from './metadata-field'; | ||
import { DateParser, DurationParser, NumberParser, StringParser, BooleanParser, } from './field-parsers'; | ||
class SharedParsers { | ||
} | ||
SharedParsers.dateParser = new DateParser(); | ||
SharedParsers.durationParser = new DurationParser(); | ||
SharedParsers.numberParser = new NumberParser(); | ||
SharedParsers.stringParser = new StringParser(); | ||
SharedParsers.booleanParser = new BooleanParser(); | ||
export class DateField extends MetadataField { | ||
constructor(rawValue) { | ||
super(SharedParsers.dateParser, rawValue); | ||
} | ||
} | ||
export class DurationField extends MetadataField { | ||
constructor(rawValue) { | ||
super(SharedParsers.durationParser, rawValue); | ||
} | ||
} | ||
export class NumberField extends MetadataField { | ||
constructor(rawValue) { | ||
super(SharedParsers.numberParser, rawValue); | ||
} | ||
} | ||
export class StringField extends MetadataField { | ||
constructor(rawValue) { | ||
super(SharedParsers.stringParser, rawValue); | ||
} | ||
} | ||
export class BooleanField extends MetadataField { | ||
constructor(rawValue) { | ||
super(SharedParsers.booleanParser, rawValue); | ||
} | ||
} | ||
export {}; | ||
//# sourceMappingURL=field-types.js.map |
@@ -1,6 +0,7 @@ | ||
import { FieldParserInterface } from './field-parsers'; | ||
import { FieldParserInterface } from './field-parser-interface'; | ||
/** | ||
* The MetadataField is responsible for three things: | ||
* 1. Take in some raw data (strings, arrays, numbers, etc) | ||
* 2. Normalize the input to an array of the input, ([string, string], [number, number], etc) | ||
* 2. Normalize the input to an array of the input, | ||
* ie. [string, string], [number, number], [Date, Date], etc | ||
* 3. Cast the values to their expected `Type` | ||
@@ -32,3 +33,3 @@ * | ||
*/ | ||
rawValue?: any; | ||
rawValue?: string[] | string; | ||
/** | ||
@@ -35,0 +36,0 @@ * The array of all values for the field. |
/** | ||
* The MetadataField is responsible for three things: | ||
* 1. Take in some raw data (strings, arrays, numbers, etc) | ||
* 2. Normalize the input to an array of the input, ([string, string], [number, number], etc) | ||
* 2. Normalize the input to an array of the input, | ||
* ie. [string, string], [number, number], [Date, Date], etc | ||
* 3. Cast the values to their expected `Type` | ||
@@ -6,0 +7,0 @@ * |
@@ -1,2 +0,7 @@ | ||
import { DateField, StringField, NumberField, DurationField, BooleanField } from './metadata-fields/field-types'; | ||
import { BooleanField } from './metadata-fields/field-types/boolean'; | ||
import { DateField } from './metadata-fields/field-types/date'; | ||
import { DurationField } from './metadata-fields/field-types/duration'; | ||
import { NumberField } from './metadata-fields/field-types/number'; | ||
import { StringField } from './metadata-fields/field-types/string'; | ||
import { PageProgressionField } from './metadata-fields/field-types/page-progression'; | ||
/** | ||
@@ -19,5 +24,7 @@ * Metadata is an expansive model that describes an Item. | ||
*/ | ||
rawMetadata?: any; | ||
identifier: string; | ||
addeddate: DateField; | ||
rawMetadata?: { | ||
[key: string]: any; | ||
}; | ||
identifier?: string; | ||
addeddate?: DateField; | ||
audio_codec?: StringField; | ||
@@ -31,5 +38,5 @@ audio_sample_rate?: NumberField; | ||
description?: StringField; | ||
downloads: NumberField; | ||
downloads?: NumberField; | ||
duration?: DurationField; | ||
indexdate: DateField; | ||
indexdate?: DateField; | ||
language?: StringField; | ||
@@ -42,3 +49,4 @@ length?: DurationField; | ||
num_reviews?: NumberField; | ||
publicdate: DateField; | ||
page_progression?: PageProgressionField; | ||
publicdate?: DateField; | ||
runtime?: DurationField; | ||
@@ -45,0 +53,0 @@ scanner?: StringField; |
/* eslint-disable @typescript-eslint/camelcase */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
/* eslint-disable camelcase */ | ||
import { DateField, StringField, NumberField, DurationField, BooleanField, } from './metadata-fields/field-types'; | ||
import { BooleanField } from './metadata-fields/field-types/boolean'; | ||
import { DateField } from './metadata-fields/field-types/date'; | ||
import { DurationField } from './metadata-fields/field-types/duration'; | ||
import { NumberField } from './metadata-fields/field-types/number'; | ||
import { StringField } from './metadata-fields/field-types/string'; | ||
/** | ||
@@ -19,5 +23,7 @@ * Metadata is an expansive model that describes an Item. | ||
this.identifier = json.identifier; | ||
this.addeddate = new DateField(json.addeddate); | ||
this.publicdate = new DateField(json.publicdate); | ||
this.indexdate = new DateField(json.indexdate); | ||
this.addeddate = json.addeddate ? new DateField(json.addeddate) : undefined; | ||
this.publicdate = json.publicdate | ||
? new DateField(json.publicdate) | ||
: undefined; | ||
this.indexdate = json.indexdate ? new DateField(json.indexdate) : undefined; | ||
this.audio_codec = json.audio_codec | ||
@@ -41,3 +47,5 @@ ? new StringField(json.audio_codec) | ||
: undefined; | ||
this.downloads = new NumberField(json.downloads); | ||
this.downloads = json.downloads | ||
? new NumberField(json.downloads) | ||
: undefined; | ||
this.duration = json.duration | ||
@@ -44,0 +52,0 @@ ? new DurationField(json.duration) |
export declare class Review { | ||
reviewbody?: string; | ||
reviewtitle?: string; | ||
reviewer: string; | ||
reviewdate: Date; | ||
createdate: Date; | ||
stars: number; | ||
reviewer?: string; | ||
reviewdate?: Date; | ||
createdate?: Date; | ||
stars?: number; | ||
constructor(json: any); | ||
} |
@@ -0,1 +1,2 @@ | ||
import { DateParser } from './metadata-fields/field-types/date'; | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
@@ -7,7 +8,7 @@ export class Review { | ||
this.reviewer = json.reviewer; | ||
this.reviewdate = new Date(json.reviewdate); | ||
this.createdate = new Date(json.createdate); | ||
this.stars = parseFloat(json.stars); | ||
this.reviewdate = DateParser.shared.parseValue(json.reviewdate); | ||
this.createdate = DateParser.shared.parseValue(json.createdate); | ||
this.stars = json.stars ? parseFloat(json.stars) : undefined; | ||
} | ||
} | ||
//# sourceMappingURL=review.js.map |
/** | ||
* The Result is a container for a response. | ||
* | ||
* It contains an optional success result which is generic and can be anything depending on | ||
* the context, or an Error or subclass of an error. | ||
* It contains an optional success result which is generic | ||
* and can be anything depending on the context, | ||
* or an Error or subclass of an error. | ||
* | ||
* This allows us to return rich, typed errors instead of | ||
* an untyped Promise rejection. | ||
* | ||
* This is modeled after Swift's Result type: | ||
@@ -8,0 +12,0 @@ * https://developer.apple.com/documentation/swift/result |
/** | ||
* The Result is a container for a response. | ||
* | ||
* It contains an optional success result which is generic and can be anything depending on | ||
* the context, or an Error or subclass of an error. | ||
* It contains an optional success result which is generic | ||
* and can be anything depending on the context, | ||
* or an Error or subclass of an error. | ||
* | ||
* This allows us to return rich, typed errors instead of | ||
* an untyped Promise rejection. | ||
* | ||
* This is modeled after Swift's Result type: | ||
@@ -8,0 +12,0 @@ * https://developer.apple.com/documentation/swift/result |
@@ -6,6 +6,6 @@ export declare class SearchResponseParams { | ||
wt: string; | ||
sort: string; | ||
rows: string; | ||
sort?: string; | ||
rows?: string; | ||
start: number; | ||
constructor(json: any); | ||
} |
@@ -16,3 +16,5 @@ import { SearchResponseHeader } from './search-response-header'; | ||
*/ | ||
rawResponse: any; | ||
rawResponse: { | ||
[key: string]: any; | ||
}; | ||
/** | ||
@@ -19,0 +21,0 @@ * The resonse header |
@@ -0,1 +1,11 @@ | ||
export declare enum SortDirection { | ||
Asc = "asc", | ||
Desc = "desc" | ||
} | ||
export declare class SortParam { | ||
field: string; | ||
direction: SortDirection; | ||
constructor(field: string, direction: SortDirection); | ||
get asString(): string; | ||
} | ||
/** | ||
@@ -5,3 +15,3 @@ * SearchParams provides an encapsulation to all of the search parameters | ||
* | ||
* It also provides an `asUrlSearchParams` helper method for converting the | ||
* It also provides an `asUrlSearchParams` method for converting the | ||
* parameters to an IA-style query string. ie. it converts the `fields` array | ||
@@ -12,7 +22,13 @@ * to `fl[]=identifier&fl[]=collection` and `sort` to `sort[]=date+desc&sort[]=downloads+asc` | ||
query: string; | ||
sort: string[]; | ||
rows: number; | ||
start: number; | ||
fields: string[]; | ||
constructor(query: string, sort?: string[], rows?: number, start?: number, fields?: string[]); | ||
sort?: SortParam[]; | ||
rows?: number; | ||
page?: number; | ||
fields?: string[]; | ||
constructor(options: { | ||
query: string; | ||
sort?: SortParam[]; | ||
rows?: number; | ||
page?: number; | ||
fields?: string[]; | ||
}); | ||
/** | ||
@@ -19,0 +35,0 @@ * Return a URLSearchParams representation of the parameters for use in network requests. |
@@ -0,1 +1,15 @@ | ||
export var SortDirection; | ||
(function (SortDirection) { | ||
SortDirection["Asc"] = "asc"; | ||
SortDirection["Desc"] = "desc"; | ||
})(SortDirection || (SortDirection = {})); | ||
export class SortParam { | ||
constructor(field, direction) { | ||
this.field = field; | ||
this.direction = direction; | ||
} | ||
get asString() { | ||
return `${this.field} ${this.direction}`; | ||
} | ||
} | ||
/** | ||
@@ -5,3 +19,3 @@ * SearchParams provides an encapsulation to all of the search parameters | ||
* | ||
* It also provides an `asUrlSearchParams` helper method for converting the | ||
* It also provides an `asUrlSearchParams` method for converting the | ||
* parameters to an IA-style query string. ie. it converts the `fields` array | ||
@@ -11,8 +25,8 @@ * to `fl[]=identifier&fl[]=collection` and `sort` to `sort[]=date+desc&sort[]=downloads+asc` | ||
export class SearchParams { | ||
constructor(query, sort = [], rows = 25, start = 0, fields = ['identifier']) { | ||
this.query = query; | ||
this.sort = sort; | ||
this.rows = rows; | ||
this.start = start; | ||
this.fields = fields; | ||
constructor(options) { | ||
this.query = options.query; | ||
this.sort = options.sort; | ||
this.rows = options.rows; | ||
this.page = options.page; | ||
this.fields = options.fields; | ||
} | ||
@@ -27,12 +41,17 @@ /** | ||
get asUrlSearchParams() { | ||
var _a, _b; | ||
const params = new URLSearchParams(); | ||
params.append('q', this.query); | ||
params.append('rows', String(this.rows)); | ||
params.append('page', String(this.start)); | ||
params.append('output', 'json'); | ||
this.fields.forEach(field => { | ||
if (this.rows) { | ||
params.append('rows', String(this.rows)); | ||
} | ||
if (this.page) { | ||
params.append('page', String(this.page)); | ||
} | ||
(_a = this.fields) === null || _a === void 0 ? void 0 : _a.forEach(field => { | ||
params.append('fl[]', field); | ||
}); | ||
this.sort.forEach(sort => { | ||
params.append('sort[]', sort); | ||
(_b = this.sort) === null || _b === void 0 ? void 0 : _b.forEach(sort => { | ||
params.append('sort[]', `${sort.asString}`); | ||
}); | ||
@@ -39,0 +58,0 @@ return params; |
@@ -7,4 +7,18 @@ import { MetadataResponse } from './responses/metadata/metadata-response'; | ||
export interface SearchServiceInterface { | ||
/** | ||
* Perform a search for given search params | ||
* | ||
* @param {SearchParams} params | ||
* @returns {Promise<Result<SearchResponse, SearchServiceError>>} | ||
* @memberof SearchServiceInterface | ||
*/ | ||
search(params: SearchParams): Promise<Result<SearchResponse, SearchServiceError>>; | ||
/** | ||
* Fetch metadata for a given identifier | ||
* | ||
* @param {string} identifier | ||
* @returns {Promise<Result<MetadataResponse, SearchServiceError>>} | ||
* @memberof SearchServiceInterface | ||
*/ | ||
fetchMetadata(identifier: string): Promise<Result<MetadataResponse, SearchServiceError>>; | ||
} |
import { SearchResponse } from './responses/search/search-response'; | ||
import { SearchBackendInterface } from './search-backend-interface'; | ||
import { SearchParams } from './search-params'; | ||
@@ -8,2 +7,3 @@ import { MetadataResponse } from './responses/metadata/metadata-response'; | ||
import { SearchServiceInterface } from './search-service-interface'; | ||
import { SearchBackendInterface } from './search-backend/search-backend-interface'; | ||
/** | ||
@@ -10,0 +10,0 @@ * The Search Service is responsible for taking the raw response provided by |
import { SearchResponse } from './responses/search/search-response'; | ||
import { MetadataResponse } from './responses/metadata/metadata-response'; | ||
import { DefaultSearchBackend } from './default-search-backend'; | ||
import { DefaultSearchBackend } from './search-backend/default-search-backend'; | ||
import { Result } from './responses/result'; | ||
@@ -5,0 +5,0 @@ import { SearchServiceError, SearchServiceErrorType, } from './search-service-error'; |
@@ -5,4 +5,4 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { SearchParams } from '../src/search-params'; | ||
import { SearchServiceErrorType, } from '../src/search-service-error'; | ||
import { DefaultSearchBackend } from '../src/default-search-backend'; | ||
import { SearchServiceErrorType } from '../src/search-service-error'; | ||
import { DefaultSearchBackend } from '../src/search-backend/default-search-backend'; | ||
describe('DefaultSearchBackend', () => { | ||
@@ -33,3 +33,3 @@ it('can fetch metadata', async () => { | ||
const backend = new DefaultSearchBackend(); | ||
const params = new SearchParams('foo'); | ||
const params = new SearchParams({ query: 'foo' }); | ||
const result = await backend.performSearch(params); | ||
@@ -36,0 +36,0 @@ expect((_a = result.success) === null || _a === void 0 ? void 0 : _a.foo).to.equal('bar'); |
@@ -0,4 +1,6 @@ | ||
import { SearchResponse } from '../src/responses/search/search-response'; | ||
import { SearchParams } from '../src/search-params'; | ||
export declare class MockResponseGenerator { | ||
generateMockSearchResponse(params: any): any; | ||
generateMockSearchResponse(params: SearchParams): SearchResponse; | ||
generateMockMetadataResponse(identifier: any): any; | ||
} |
@@ -5,4 +5,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
generateMockSearchResponse(params) { | ||
const fieldsAsString = params.fields.join(','); | ||
var _a, _b, _c; | ||
const fieldsAsString = (_a = params.fields) === null || _a === void 0 ? void 0 : _a.join(','); | ||
return { | ||
rawResponse: { | ||
foo: 'bar', | ||
}, | ||
responseHeader: { | ||
@@ -14,7 +18,11 @@ status: 0, | ||
qin: params.query, | ||
fields: fieldsAsString, | ||
fields: fieldsAsString !== null && fieldsAsString !== void 0 ? fieldsAsString : '', | ||
wt: 'json', | ||
sort: params.sort, | ||
rows: params.rows, | ||
start: params.start, | ||
sort: (_b = params.sort) === null || _b === void 0 ? void 0 : _b.reduce((prev, current, index) => { | ||
const isFirst = index === 0; | ||
const commaPrefix = isFirst ? '' : ', '; | ||
return `${prev}${commaPrefix}${current.field} ${current.direction}`; | ||
}, ''), | ||
rows: params.rows ? `${params.rows}` : '', | ||
start: (_c = params.page) !== null && _c !== void 0 ? _c : 0, | ||
}, | ||
@@ -25,3 +33,8 @@ }, | ||
start: 0, | ||
docs: [{ identifier: 'foo' }, { identifier: 'bar' }], | ||
docs: [ | ||
{ | ||
identifier: 'foo', | ||
}, | ||
{ identifier: 'bar' }, | ||
], | ||
}, | ||
@@ -28,0 +41,0 @@ }; |
import { expect } from '@open-wc/testing'; | ||
import { SearchParams } from '../src/search-params'; | ||
import { SearchParams, SortDirection, SortParam } from '../src/search-params'; | ||
describe('SearchParams', () => { | ||
it('can be instantiated with just a query', async () => { | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
expect(params.query).to.equal(query); | ||
@@ -12,3 +12,6 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const params = new SearchParams(query, undefined, undefined, undefined, fields); | ||
const params = new SearchParams({ | ||
query, | ||
fields, | ||
}); | ||
expect(params.fields).to.deep.equal(fields); | ||
@@ -23,6 +26,6 @@ }); | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&rows=25&page=0&output=json&fl%5B%5D=identifier'; | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&output=json'; | ||
expect(queryAsString).to.equal(expected); | ||
@@ -33,6 +36,9 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const params = new SearchParams(query, undefined, undefined, undefined, fields); | ||
const params = new SearchParams({ | ||
query, | ||
fields, | ||
}); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&rows=25&page=0&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar'; | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar'; | ||
expect(queryAsString).to.equal(expected); | ||
@@ -43,7 +49,13 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const sort = ['downloads desc']; | ||
const params = new SearchParams(query, sort, 53, 27, fields); | ||
const sort = [new SortParam('downloads', SortDirection.Desc)]; | ||
const params = new SearchParams({ | ||
query, | ||
sort, | ||
rows: 53, | ||
page: 27, | ||
fields, | ||
}); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&rows=53&page=27&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar&sort%5B%5D=downloads+desc'; | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&output=json&rows=53&page=27&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar&sort%5B%5D=downloads+desc'; | ||
expect(queryAsString).to.equal(expected); | ||
@@ -50,0 +62,0 @@ }); |
@@ -23,3 +23,3 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
const backend = new MockSearchBackend(); | ||
@@ -83,3 +83,3 @@ const service = new SearchService(backend); | ||
expect((_b = metadataResult.error) === null || _b === void 0 ? void 0 : _b.message).to.equal('network error'); | ||
const params = new SearchParams('boop'); | ||
const params = new SearchParams({ query: 'boop' }); | ||
const searchResult = await service.search(params); | ||
@@ -108,3 +108,3 @@ expect(searchResult.error).to.not.equal(undefined); | ||
expect((_b = metadataResult.error) === null || _b === void 0 ? void 0 : _b.message).to.equal('decoding error'); | ||
const params = new SearchParams('boop'); | ||
const params = new SearchParams({ query: 'boop' }); | ||
const searchResult = await service.search(params); | ||
@@ -111,0 +111,0 @@ expect(searchResult.error).to.not.equal(undefined); |
31
index.ts
@@ -7,16 +7,31 @@ export { Metadata } from './src/models/metadata'; | ||
DateField, | ||
DateParser, | ||
} from './src/models/metadata-fields/field-types/date'; | ||
export { | ||
NumberField, | ||
DurationField, | ||
NumberParser, | ||
} from './src/models/metadata-fields/field-types/number'; | ||
export { | ||
StringField, | ||
StringParser, | ||
} from './src/models/metadata-fields/field-types/string'; | ||
export { | ||
BooleanField, | ||
} from './src/models/metadata-fields/field-types'; | ||
BooleanParser, | ||
} from './src/models/metadata-fields/field-types/boolean'; | ||
export { | ||
NumberParser, | ||
StringParser, | ||
DateParser, | ||
DurationField, | ||
DurationParser, | ||
BooleanParser, | ||
} from './src/models/metadata-fields/field-parsers'; | ||
} from './src/models/metadata-fields/field-types/duration'; | ||
export { | ||
PageProgressionField, | ||
PageProgressionParser, | ||
PageProgression, | ||
} from './src/models/metadata-fields/field-types/page-progression'; | ||
export { MetadataField } from './src/models/metadata-fields/metadata-field'; | ||
@@ -31,5 +46,5 @@ | ||
export { DefaultSearchBackend } from './src/default-search-backend'; | ||
export { DefaultSearchBackend } from './src/search-backend/default-search-backend'; | ||
export { SearchServiceInterface } from './src/search-service-interface'; | ||
export { SearchService } from './src/search-service'; | ||
export { SearchParams } from './src/search-params'; |
{ | ||
"name": "@internetarchive/search-service", | ||
"version": "0.0.1-alpha.11", | ||
"version": "0.0.1-alpha.12", | ||
"description": "A search service for the Internet Archive", | ||
@@ -40,2 +40,3 @@ "license": "AGPL-3.0-only", | ||
"lint-staged": "^10.0.0", | ||
"lit-element": "^2.4.0", | ||
"lit-html": "^1.3.0", | ||
@@ -42,0 +43,0 @@ "madge": "^3.12.0", |
@@ -8,3 +8,3 @@ @@ -1,117 +0,0 @@ | ||
```bash | ||
yarn add @internetarchive/ia-search-service | ||
npm install @internetarchive/search-service | ||
``` | ||
@@ -14,65 +14,29 @@ | ||
### 1. Implement a SearchBackend | ||
In order to abstract the network connectivity layer and the environment-specific configuration from the result handling, the consumer should implement a search backend that implements the `SearchBackendInterface`. | ||
There are just two methods, one for fetching search results and the other for fetching metadata. They both return a `Promise` that should contain JSON that matches a `SearchResponse` object or a `MetadataResponse` object. | ||
#### Example Search Backend | ||
### Searching | ||
```ts | ||
// search-backend.ts | ||
import { SearchBackendInterface, SearchResponse, MetadataResponse } from '@internetarchive/ia-search-service'; | ||
import { SearchService } from '@internetarchive/search-service'; | ||
export class SearchBackend implements SearchBackendInterface { | ||
constructor(baseUrl = 'archive.org') { | ||
this.baseUrl = baseUrl; | ||
} | ||
const searchService = SearchService.default; | ||
const params = new SearchParams({ | ||
query: 'collection:books AND title:(little bunny foo foo)', | ||
sort: 'downloads desc', | ||
rows: 25, | ||
start: 0, | ||
fields: ['identifier', 'collection', 'title', 'creator'] | ||
}); | ||
async performSearch(params): Promise<SearchResponse> { | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const url = `https://${this.baseUrl}/advancedsearch.php?${queryAsString}`; | ||
const response = await fetch(url); | ||
const json = await response.json(); | ||
return new Promise(resolve => resolve(json)); | ||
} | ||
async fetchMetadata(identifier): Promise<MetadataResponse> { | ||
const url = `https://${this.baseUrl}/metadata/${identifier}`; | ||
const response = await fetch(url); | ||
const json = await response.json(); | ||
return new Promise(resolve => resolve(json)); | ||
} | ||
const result = await searchService.performSearch(params); | ||
if (result.success) { | ||
const searchResponse = result.success; | ||
searchResponse.response.numFound // => number | ||
searchResponse.response.docs // => Metadata[] array | ||
searchResponse.response.docs[0].identifier // => 'identifier-foo' | ||
} | ||
``` | ||
### 2. Make Search Requests | ||
### Fetch Metadata | ||
Using the backend you created above, instantiate a `SearchService` with it, craft some `SearchParams`, and perform your search: | ||
#### Example | ||
```ts | ||
// search-consumer.ts | ||
import { SearchService, SearchParams, SearchResponse } from '@internetarchive/ia-search-service'; | ||
import { SearchBackend } from './search-backend'; | ||
const metadataResponse: MetadataResponse = await searchService.fetchMetadata('some-identifier'); | ||
... | ||
const searchBackend = new SearchBackend(); | ||
const searchService = new SearchService(searchBackend); | ||
const params = new SearchParams('collection:books AND title:(little bunny foo foo)'); | ||
params.sort = 'downloads desc'; | ||
params.rows = 33; | ||
params.start = 0; | ||
params.fields = ['identifier', 'collection', 'creator', 'downloads']; | ||
const searchResponse: SearchResponse = await searchService.performSearch(params); | ||
searchResponse.response.numFound // => number | ||
searchResponse.response.docs // => Metadata[] array | ||
searchResponse.response.docs[0].identifier // => 'identifier-foo' | ||
const metadataResponse: MetadataResponse = await searchService.fetchMetadata('some-identifier'); | ||
metadataResponse.metadata.identifier // => 'some-identifier' | ||
@@ -97,3 +61,3 @@ metadataResponse.metadata.collection.value // => 'some-collection' | ||
metadata.collection.value // return just the first item of the `values` array, ie. 'my-collection' | ||
metadata.collection.value // returns all values of the array, ie. ['my-collection', 'other-collection'] | ||
metadata.collection.values // returns all values of the array, ie. ['my-collection', 'other-collection'] | ||
metadata.collection.rawValue // return the rawValue. This is useful for inspecting the raw response received. | ||
@@ -110,3 +74,3 @@ | ||
```bash | ||
yarn install | ||
npm install | ||
``` | ||
@@ -116,3 +80,3 @@ | ||
```bash | ||
yarn test | ||
npm run test | ||
``` | ||
@@ -122,3 +86,3 @@ | ||
```bash | ||
yarn lint | ||
npm run formatting | ||
``` |
/* eslint-disable @typescript-eslint/camelcase */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { DurationField, NumberField } from './metadata-fields/field-types'; | ||
import { | ||
Duration, | ||
DurationParser, | ||
} from './metadata-fields/field-types/duration'; | ||
import { NumberParser } from './metadata-fields/field-types/number'; | ||
@@ -31,13 +35,13 @@ /** | ||
size?: NumberField; | ||
size?: number; | ||
title?: string; | ||
length?: DurationField; | ||
length?: Duration; | ||
height?: NumberField; | ||
height?: number; | ||
width?: NumberField; | ||
width?: number; | ||
track?: NumberField; | ||
track?: number; | ||
@@ -60,8 +64,18 @@ external_identifier?: string; | ||
this.original = json.original; | ||
this.size = json.size ? new NumberField(json.size) : undefined; | ||
this.title = json.title; | ||
this.length = json.length ? new DurationField(json.length) : undefined; | ||
this.height = json.height ? new NumberField(json.height) : undefined; | ||
this.width = json.width ? new NumberField(json.width) : undefined; | ||
this.track = json.track ? new NumberField(json.track) : undefined; | ||
this.length = json.length | ||
? DurationParser.shared.parseValue(json.length) | ||
: undefined; | ||
this.size = json.size | ||
? NumberParser.shared.parseValue(json.size) | ||
: undefined; | ||
this.height = json.height | ||
? NumberParser.shared.parseValue(json.height) | ||
: undefined; | ||
this.width = json.width | ||
? NumberParser.shared.parseValue(json.width) | ||
: undefined; | ||
this.track = json.track | ||
? NumberParser.shared.parseValue(json.track) | ||
: undefined; | ||
this.external_identifier = json['external-identifier']; | ||
@@ -68,0 +82,0 @@ this.creator = json.creator; |
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { FieldParserInterface } from './field-parsers'; | ||
import { FieldParserInterface } from './field-parser-interface'; | ||
@@ -7,3 +7,4 @@ /** | ||
* 1. Take in some raw data (strings, arrays, numbers, etc) | ||
* 2. Normalize the input to an array of the input, ([string, string], [number, number], etc) | ||
* 2. Normalize the input to an array of the input, | ||
* ie. [string, string], [number, number], [Date, Date], etc | ||
* 3. Cast the values to their expected `Type` | ||
@@ -38,3 +39,3 @@ * | ||
*/ | ||
rawValue?: any; | ||
rawValue?: string[] | string; | ||
@@ -41,0 +42,0 @@ /** |
/* eslint-disable @typescript-eslint/camelcase */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
/* eslint-disable camelcase */ | ||
import { | ||
DateField, | ||
StringField, | ||
NumberField, | ||
DurationField, | ||
BooleanField, | ||
} from './metadata-fields/field-types'; | ||
import { BooleanField } from './metadata-fields/field-types/boolean'; | ||
import { DateField } from './metadata-fields/field-types/date'; | ||
import { DurationField } from './metadata-fields/field-types/duration'; | ||
import { NumberField } from './metadata-fields/field-types/number'; | ||
import { StringField } from './metadata-fields/field-types/string'; | ||
import { PageProgressionField } from './metadata-fields/field-types/page-progression'; | ||
/** | ||
@@ -29,7 +29,7 @@ * Metadata is an expansive model that describes an Item. | ||
*/ | ||
rawMetadata?: any; | ||
rawMetadata?: { [key: string]: any }; | ||
identifier: string; | ||
identifier?: string; | ||
addeddate: DateField; | ||
addeddate?: DateField; | ||
@@ -52,7 +52,7 @@ audio_codec?: StringField; | ||
downloads: NumberField; | ||
downloads?: NumberField; | ||
duration?: DurationField; | ||
indexdate: DateField; | ||
indexdate?: DateField; | ||
@@ -73,4 +73,6 @@ language?: StringField; | ||
publicdate: DateField; | ||
page_progression?: PageProgressionField; | ||
publicdate?: DateField; | ||
runtime?: DurationField; | ||
@@ -112,5 +114,7 @@ | ||
this.addeddate = new DateField(json.addeddate); | ||
this.publicdate = new DateField(json.publicdate); | ||
this.indexdate = new DateField(json.indexdate); | ||
this.addeddate = json.addeddate ? new DateField(json.addeddate) : undefined; | ||
this.publicdate = json.publicdate | ||
? new DateField(json.publicdate) | ||
: undefined; | ||
this.indexdate = json.indexdate ? new DateField(json.indexdate) : undefined; | ||
@@ -135,3 +139,5 @@ this.audio_codec = json.audio_codec | ||
: undefined; | ||
this.downloads = new NumberField(json.downloads); | ||
this.downloads = json.downloads | ||
? new NumberField(json.downloads) | ||
: undefined; | ||
this.duration = json.duration | ||
@@ -138,0 +144,0 @@ ? new DurationField(json.duration) |
@@ -0,1 +1,3 @@ | ||
import { DateParser } from './metadata-fields/field-types/date'; | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
@@ -7,9 +9,9 @@ export class Review { | ||
reviewer: string; | ||
reviewer?: string; | ||
reviewdate: Date; | ||
reviewdate?: Date; | ||
createdate: Date; | ||
createdate?: Date; | ||
stars: number; | ||
stars?: number; | ||
@@ -20,6 +22,6 @@ constructor(json: any) { | ||
this.reviewer = json.reviewer; | ||
this.reviewdate = new Date(json.reviewdate); | ||
this.createdate = new Date(json.createdate); | ||
this.stars = parseFloat(json.stars); | ||
this.reviewdate = DateParser.shared.parseValue(json.reviewdate); | ||
this.createdate = DateParser.shared.parseValue(json.createdate); | ||
this.stars = json.stars ? parseFloat(json.stars) : undefined; | ||
} | ||
} |
/** | ||
* The Result is a container for a response. | ||
* | ||
* It contains an optional success result which is generic and can be anything depending on | ||
* the context, or an Error or subclass of an error. | ||
* It contains an optional success result which is generic | ||
* and can be anything depending on the context, | ||
* or an Error or subclass of an error. | ||
* | ||
* This allows us to return rich, typed errors instead of | ||
* an untyped Promise rejection. | ||
* | ||
* This is modeled after Swift's Result type: | ||
@@ -8,0 +12,0 @@ * https://developer.apple.com/documentation/swift/result |
@@ -11,5 +11,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
sort: string; | ||
sort?: string; | ||
rows: string; | ||
rows?: string; | ||
@@ -16,0 +16,0 @@ start: number; |
@@ -18,3 +18,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
*/ | ||
rawResponse: any; | ||
rawResponse: { [key: string]: any }; | ||
@@ -21,0 +21,0 @@ /** |
@@ -0,1 +1,20 @@ | ||
export enum SortDirection { | ||
Asc = 'asc', | ||
Desc = 'desc', | ||
} | ||
export class SortParam { | ||
field: string; | ||
direction: SortDirection; | ||
constructor(field: string, direction: SortDirection) { | ||
this.field = field; | ||
this.direction = direction; | ||
} | ||
get asString(): string { | ||
return `${this.field} ${this.direction}`; | ||
} | ||
} | ||
/** | ||
@@ -5,3 +24,3 @@ * SearchParams provides an encapsulation to all of the search parameters | ||
* | ||
* It also provides an `asUrlSearchParams` helper method for converting the | ||
* It also provides an `asUrlSearchParams` method for converting the | ||
* parameters to an IA-style query string. ie. it converts the `fields` array | ||
@@ -13,22 +32,22 @@ * to `fl[]=identifier&fl[]=collection` and `sort` to `sort[]=date+desc&sort[]=downloads+asc` | ||
sort: string[]; | ||
sort?: SortParam[]; | ||
rows: number; | ||
rows?: number; | ||
start: number; | ||
page?: number; | ||
fields: string[]; | ||
fields?: string[]; | ||
constructor( | ||
query: string, | ||
sort: string[] = [], | ||
rows = 25, | ||
start = 0, | ||
fields: string[] = ['identifier'] | ||
) { | ||
this.query = query; | ||
this.sort = sort; | ||
this.rows = rows; | ||
this.start = start; | ||
this.fields = fields; | ||
constructor(options: { | ||
query: string; | ||
sort?: SortParam[]; | ||
rows?: number; | ||
page?: number; | ||
fields?: string[]; | ||
}) { | ||
this.query = options.query; | ||
this.sort = options.sort; | ||
this.rows = options.rows; | ||
this.page = options.page; | ||
this.fields = options.fields; | ||
} | ||
@@ -46,12 +65,15 @@ | ||
params.append('q', this.query); | ||
params.append('rows', String(this.rows)); | ||
params.append('page', String(this.start)); | ||
params.append('output', 'json'); | ||
this.fields.forEach(field => { | ||
if (this.rows) { | ||
params.append('rows', String(this.rows)); | ||
} | ||
if (this.page) { | ||
params.append('page', String(this.page)); | ||
} | ||
this.fields?.forEach(field => { | ||
params.append('fl[]', field); | ||
}); | ||
this.sort.forEach(sort => { | ||
params.append('sort[]', sort); | ||
this.sort?.forEach(sort => { | ||
params.append('sort[]', `${sort.asString}`); | ||
}); | ||
@@ -58,0 +80,0 @@ |
@@ -8,5 +8,20 @@ import { MetadataResponse } from './responses/metadata/metadata-response'; | ||
export interface SearchServiceInterface { | ||
/** | ||
* Perform a search for given search params | ||
* | ||
* @param {SearchParams} params | ||
* @returns {Promise<Result<SearchResponse, SearchServiceError>>} | ||
* @memberof SearchServiceInterface | ||
*/ | ||
search( | ||
params: SearchParams | ||
): Promise<Result<SearchResponse, SearchServiceError>>; | ||
/** | ||
* Fetch metadata for a given identifier | ||
* | ||
* @param {string} identifier | ||
* @returns {Promise<Result<MetadataResponse, SearchServiceError>>} | ||
* @memberof SearchServiceInterface | ||
*/ | ||
fetchMetadata( | ||
@@ -13,0 +28,0 @@ identifier: string |
import { SearchResponse } from './responses/search/search-response'; | ||
import { SearchBackendInterface } from './search-backend-interface'; | ||
import { SearchParams } from './search-params'; | ||
import { MetadataResponse } from './responses/metadata/metadata-response'; | ||
import { DefaultSearchBackend } from './default-search-backend'; | ||
import { DefaultSearchBackend } from './search-backend/default-search-backend'; | ||
import { Result } from './responses/result'; | ||
@@ -12,2 +11,3 @@ import { | ||
import { SearchServiceInterface } from './search-service-interface'; | ||
import { SearchBackendInterface } from './search-backend/search-backend-interface'; | ||
@@ -14,0 +14,0 @@ /** |
@@ -5,15 +5,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { SearchService } from '../src/search-service'; | ||
import { SearchParams } from '../src/search-params'; | ||
import { MockResponseGenerator } from './mock-response-generator'; | ||
import { SearchBackendInterface } from '../src/search-backend-interface'; | ||
import { SearchResponse } from '../src/responses/search/search-response'; | ||
import { MetadataResponse } from '../src/responses/metadata/metadata-response'; | ||
import { Result } from '../src/responses/result'; | ||
import { | ||
SearchServiceError, | ||
SearchServiceErrorType, | ||
} from '../src/search-service-error'; | ||
import { DefaultSearchBackend } from '../src/default-search-backend'; | ||
import { SearchServiceErrorType } from '../src/search-service-error'; | ||
import { DefaultSearchBackend } from '../src/search-backend/default-search-backend'; | ||
@@ -46,3 +37,3 @@ describe('DefaultSearchBackend', () => { | ||
const backend = new DefaultSearchBackend(); | ||
const params = new SearchParams('foo'); | ||
const params = new SearchParams({ query: 'foo' }); | ||
const result = await backend.performSearch(params); | ||
@@ -49,0 +40,0 @@ expect(result.success?.foo).to.equal('bar'); |
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { SearchResponse } from '../src/responses/search/search-response'; | ||
import { SearchParams } from '../src/search-params'; | ||
/* eslint-disable @typescript-eslint/camelcase */ | ||
export class MockResponseGenerator { | ||
generateMockSearchResponse(params: any): any { | ||
const fieldsAsString = params.fields.join(','); | ||
generateMockSearchResponse(params: SearchParams): SearchResponse { | ||
const fieldsAsString = params.fields?.join(','); | ||
return { | ||
rawResponse: { | ||
foo: 'bar', | ||
}, | ||
responseHeader: { | ||
@@ -14,7 +21,11 @@ status: 0, | ||
qin: params.query, | ||
fields: fieldsAsString, | ||
fields: fieldsAsString ?? '', | ||
wt: 'json', | ||
sort: params.sort, | ||
rows: params.rows, | ||
start: params.start, | ||
sort: params.sort?.reduce((prev, current, index) => { | ||
const isFirst = index === 0; | ||
const commaPrefix = isFirst ? '' : ', '; | ||
return `${prev}${commaPrefix}${current.field} ${current.direction}`; | ||
}, ''), | ||
rows: params.rows ? `${params.rows}` : '', | ||
start: params.page ?? 0, | ||
}, | ||
@@ -25,3 +36,8 @@ }, | ||
start: 0, | ||
docs: [{ identifier: 'foo' }, { identifier: 'bar' }], | ||
docs: [ | ||
{ | ||
identifier: 'foo', | ||
}, | ||
{ identifier: 'bar' }, | ||
], | ||
}, | ||
@@ -28,0 +44,0 @@ }; |
import { expect } from '@open-wc/testing'; | ||
import { FieldParserInterface } from '../../../src/models/metadata-fields/field-parsers'; | ||
import { FieldParserInterface } from '../../../src/models/metadata-fields/field-parser-interface'; | ||
@@ -4,0 +4,0 @@ import { MetadataField } from '../../../src/models/metadata-fields/metadata-field'; |
import { expect } from '@open-wc/testing'; | ||
import { SearchParams } from '../src/search-params'; | ||
import { SearchParams, SortDirection, SortParam } from '../src/search-params'; | ||
@@ -8,3 +8,3 @@ describe('SearchParams', () => { | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
expect(params.query).to.equal(query); | ||
@@ -16,9 +16,6 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const params = new SearchParams( | ||
const params = new SearchParams({ | ||
query, | ||
undefined, | ||
undefined, | ||
undefined, | ||
fields | ||
); | ||
fields, | ||
}); | ||
expect(params.fields).to.deep.equal(fields); | ||
@@ -35,7 +32,6 @@ }); | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = | ||
'q=title%3Afoo+AND+collection%3Abar&rows=25&page=0&output=json&fl%5B%5D=identifier'; | ||
const expected = 'q=title%3Afoo+AND+collection%3Abar&output=json'; | ||
expect(queryAsString).to.equal(expected); | ||
@@ -47,13 +43,10 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const params = new SearchParams( | ||
const params = new SearchParams({ | ||
query, | ||
undefined, | ||
undefined, | ||
undefined, | ||
fields | ||
); | ||
fields, | ||
}); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = | ||
'q=title%3Afoo+AND+collection%3Abar&rows=25&page=0&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar'; | ||
'q=title%3Afoo+AND+collection%3Abar&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar'; | ||
expect(queryAsString).to.equal(expected); | ||
@@ -65,10 +58,16 @@ }); | ||
const fields = ['identifier', 'foo', 'bar']; | ||
const sort = ['downloads desc']; | ||
const params = new SearchParams(query, sort, 53, 27, fields); | ||
const sort = [new SortParam('downloads', SortDirection.Desc)]; | ||
const params = new SearchParams({ | ||
query, | ||
sort, | ||
rows: 53, | ||
page: 27, | ||
fields, | ||
}); | ||
const urlSearchParam = params.asUrlSearchParams; | ||
const queryAsString = urlSearchParam.toString(); | ||
const expected = | ||
'q=title%3Afoo+AND+collection%3Abar&rows=53&page=27&output=json&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar&sort%5B%5D=downloads+desc'; | ||
'q=title%3Afoo+AND+collection%3Abar&output=json&rows=53&page=27&fl%5B%5D=identifier&fl%5B%5D=foo&fl%5B%5D=bar&sort%5B%5D=downloads+desc'; | ||
expect(queryAsString).to.equal(expected); | ||
}); | ||
}); |
@@ -9,3 +9,2 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { MockResponseGenerator } from './mock-response-generator'; | ||
import { SearchBackendInterface } from '../src/search-backend-interface'; | ||
import { SearchResponse } from '../src/responses/search/search-response'; | ||
@@ -18,2 +17,3 @@ import { MetadataResponse } from '../src/responses/metadata/metadata-response'; | ||
} from '../src/search-service-error'; | ||
import { SearchBackendInterface } from '../src/search-backend/search-backend-interface'; | ||
@@ -41,3 +41,3 @@ describe('SearchService', () => { | ||
const query = 'title:foo AND collection:bar'; | ||
const params = new SearchParams(query); | ||
const params = new SearchParams({ query }); | ||
const backend = new MockSearchBackend(); | ||
@@ -130,3 +130,3 @@ const service = new SearchService(backend); | ||
const params = new SearchParams('boop'); | ||
const params = new SearchParams({ query: 'boop' }); | ||
const searchResult = await service.search(params); | ||
@@ -174,3 +174,3 @@ expect(searchResult.error).to.not.equal(undefined); | ||
const params = new SearchParams('boop'); | ||
const params = new SearchParams({ query: 'boop' }); | ||
const searchResult = await service.search(params); | ||
@@ -177,0 +177,0 @@ expect(searchResult.error).to.not.equal(undefined); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
320941
181
4026
18
83
2