mirror of
https://github.com/bpatrik/pigallery2.git
synced 2026-06-20 00:15:49 +02:00
Fixing query validation
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
SearchQueryTypes,
|
||||
SomeOfSearchQuery,
|
||||
TextSearch,
|
||||
TextSearchQueryMatchTypes,
|
||||
TextSearchQueryTypes
|
||||
} from './entities/SearchQueryDTO';
|
||||
import {SearchQueryParser} from './SearchQueryParser';
|
||||
@@ -109,20 +110,24 @@ export const SearchQueryUtils = {
|
||||
query.type === undefined ||
|
||||
(query.type === SearchQueryTypes.any_text && !(query as TextSearch).value);
|
||||
},
|
||||
// Recursively strip negate:false so that optional false flags do not break validation
|
||||
// Recursively strip negate:false and matchType:like so that optional/default flags do not break validation
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
stripFalseNegate: (val: any): any => {
|
||||
stripDefault: (val: any): any => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.map((v) => SearchQueryUtils.stripFalseNegate(v));
|
||||
return val.map((v) => SearchQueryUtils.stripDefault(v));
|
||||
}
|
||||
if (val && typeof val === 'object') {
|
||||
const out: Record<string, unknown> = {};
|
||||
for (const k of Object.keys(val)) {
|
||||
const v = SearchQueryUtils.stripFalseNegate(val[k]);
|
||||
const v = SearchQueryUtils.stripDefault(val[k]);
|
||||
if (k === 'negate' && v === false) {
|
||||
// drop negate:false
|
||||
continue;
|
||||
}
|
||||
if (k === 'matchType' && v === TextSearchQueryMatchTypes.like) {
|
||||
// drop matchType:like (this is the default)
|
||||
continue;
|
||||
}
|
||||
// keep everything else, including negate:true and undefined-handled by equalsFilter
|
||||
out[k] = v;
|
||||
}
|
||||
@@ -139,9 +144,9 @@ export const SearchQueryUtils = {
|
||||
const sp = new SearchQueryParser();
|
||||
try {
|
||||
const parsed = sp.parse(sp.stringify(query));
|
||||
const normParsed = SearchQueryUtils.stripFalseNegate(parsed) as SearchQueryDTO;
|
||||
const normQuery = SearchQueryUtils.stripFalseNegate(query) as SearchQueryDTO;
|
||||
if (!Utils.equalsFilter(normParsed, normQuery)) {
|
||||
const normParsed = SearchQueryUtils.stripDefault(parsed) as SearchQueryDTO;
|
||||
const normQuery = SearchQueryUtils.stripDefault(query) as SearchQueryDTO;
|
||||
if (!Utils.equalsFilter(normParsed, normQuery) || !Utils.equalsFilter(normQuery, normParsed)) {
|
||||
throw new Error(
|
||||
`${what} is not valid. Expected: ${JSON.stringify(parsed)} to equal: ${JSON.stringify(query)}`
|
||||
);
|
||||
@@ -179,7 +184,7 @@ export const SearchQueryUtils = {
|
||||
if (!query) {
|
||||
return '';
|
||||
}
|
||||
query=SearchQueryUtils.stripFalseNegate(query);
|
||||
query=SearchQueryUtils.stripDefault(query);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const shorten = (obj: any): any => {
|
||||
if (Array.isArray(obj)) {
|
||||
|
||||
@@ -63,7 +63,7 @@ export const MetadataSearchQueryTypes = [
|
||||
|
||||
export enum TextSearchQueryMatchTypes {
|
||||
exact_match = 1,
|
||||
like = 2,
|
||||
like = 2, // default value
|
||||
}
|
||||
|
||||
export interface SearchQueryDTO {
|
||||
|
||||
@@ -16,6 +16,6 @@ export class SearchQueryParserService {
|
||||
}
|
||||
|
||||
stringify(query: SearchQueryDTO): string {
|
||||
return this.parser.stringify(SearchQueryUtils.stripFalseNegate(query));
|
||||
return this.parser.stringify(SearchQueryUtils.stripDefault(query));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ export class GallerySearchComponent implements OnDestroy {
|
||||
async saveSearch(): Promise<void> {
|
||||
await this.albumService.addSavedSearch(
|
||||
this.saveSearchName,
|
||||
SearchQueryUtils.stripFalseNegate(this.searchQueryDTO)
|
||||
SearchQueryUtils.stripDefault(this.searchQueryDTO)
|
||||
);
|
||||
this.hideSaveSearchModal();
|
||||
}
|
||||
|
||||
@@ -151,11 +151,26 @@ describe('SearchQueryDTOUtils.sortQuery', () => {
|
||||
// Added tests to cover validateSearchQuery behavior with negate:false
|
||||
// The validation should not fail merely because a negate:false property exists, even deeply nested.
|
||||
|
||||
describe('SearchQueryDTOUtils.validateSearchQuery with negate:false', () => {
|
||||
describe('SearchQueryDTOUtils.validateSearchQuery', () => {
|
||||
const assertValid = (q: SearchQueryDTO) => {
|
||||
expect(() => SearchQueryUtils.validateSearchQuery(q, 'SearchQuery')).to.not.throw();
|
||||
};
|
||||
|
||||
it('should validate a top-level leaf with mathtype exact_match', () => {
|
||||
const q: TextSearch = {type: SearchQueryTypes.person, value: 'alice', matchType: TextSearchQueryMatchTypes.exact_match};
|
||||
assertValid(q);
|
||||
});
|
||||
|
||||
it('should validate a top-level leaf with mathtype like', () => {
|
||||
const q: TextSearch = {type: SearchQueryTypes.person, value: 'alice', matchType: TextSearchQueryMatchTypes.like};
|
||||
assertValid(q);
|
||||
});
|
||||
|
||||
it('should validate a top-level leaf with mathtype like and spaces', () => {
|
||||
const q: TextSearch = {type: SearchQueryTypes.person, value: 'alice doe', matchType: TextSearchQueryMatchTypes.like};
|
||||
assertValid(q);
|
||||
});
|
||||
|
||||
it('should validate a top-level leaf with negate:false', () => {
|
||||
const q: TextSearch = {type: SearchQueryTypes.person, value: 'alice', negate: false};
|
||||
assertValid(q);
|
||||
@@ -205,8 +220,8 @@ describe('SearchQueryDTOUtils.validateSearchQuery with negate:false', () => {
|
||||
|
||||
describe('SearchQueryDTOUtils.urlify', () => {
|
||||
const assertValid = (q: SearchQueryDTO) => {
|
||||
expect(SearchQueryUtils.urlify(q).length).to.be.lessThan(JSON.stringify(SearchQueryUtils.stripFalseNegate(q)).length);
|
||||
expect(SearchQueryUtils.parseURLifiedQuery(SearchQueryUtils.urlify(q))).to.deep.equal(SearchQueryUtils.stripFalseNegate(q));
|
||||
expect(SearchQueryUtils.urlify(q).length).to.be.lessThan(JSON.stringify(SearchQueryUtils.stripDefault(q)).length);
|
||||
expect(SearchQueryUtils.parseURLifiedQuery(SearchQueryUtils.urlify(q))).to.deep.equal(SearchQueryUtils.stripDefault(q));
|
||||
};
|
||||
|
||||
it('should validate a top-level leaf with negate:false', () => {
|
||||
|
||||
Reference in New Issue
Block a user