diff --git a/src/queries.js b/src/queries.js index abf3f2e..5082e7b 100644 --- a/src/queries.js +++ b/src/queries.js @@ -24,54 +24,118 @@ export const MatchTypeEnum = { MATCH_LIKE: 2, }; -export const ResultFilterTypeEnum = { - MATCH_NAME: 1, +export const MatchAgainstEnum = { + MATCH_RESULT_NAME: 1, // Match on the name of whatever object type we are querying for + MATCH_IMAGE_NAME: 2, // Match on the name of the relevant image, if any + MATCH_ALBUM_NAME: 3, // Match on the name of the relevant album, if any } export const ResultTypeEnum = { IMAGE: 1, + ALBUM: 2, } export class ResultFilter { + constructor(type) { this.result_type = type; } + + result_type = ResultTypeEnum.IMAGE; + + to_sql_where() { return "(1=1)"; } +} + +export class ConstFilter extends ResultFilter { + constructor(type, val) { super(type); this.constval = val; } + constval = true; // True lets everything through, false rejects everything + + to_sql_where() { + return this.constval ? "(1=1)" : "(1=0)"; + } +} + +function match_column_name(result_type, match_against) { + if(match_against == MatchAgainstEnum.MATCH_IMAGE_NAME) { + return "Image.name"; + } + if(match_against == MatchAgainstEnum.MATCH_ALBUM_NAME) { + return "Album.name"; + } + if(match_against == MatchAgainstEnum.MATCH_RESULT_NAME) { + if(result_type == ResultTypeEnum.IMAGE) { + return match_column_name(result_type, MatchAgainstEnum.MATCH_IMAGE_NAME); + } + if(result_type == ResultTypeEnum.ALBUM) { + return match_column_name(result_type, MatchAgainstEnum.MATCH_ALBUM_NAME); + } + } + throw new Error("Could not get column name for matching properties passed."); +} + +export class MatchingFilter extends ResultFilter { + constructor(rtype, against, from, mtype, negate) { + super(rtype); + this.match_against = against; + this.match_from = from; + this.match_type = mtype; + this.negate = negate; + } + // What kind of filtering to apply - type = ResultFilterTypeEnum.MATCH_NAME; + match_against = MatchAgainstEnum.MATCH_RESULT_NAME; // optional string used in the filtering - match_against = ""; + match_from = ""; // How to use the matching string match_type = MatchTypeEnum.MATCH_EQUALS; - // On which types of results to apply the filter - result_types = []; - // If true, negates the filter negate = false; -} -export class UserQuery { - result_filters = []; - include_result_types = [ ResultTypeEnum.IMAGE ]; + to_sql_where() { + var match_against_str = match_column_name(this.result_type, this.match_against); + var match_type_str = false; + + if(this.match_type == MatchTypeEnum.MATCH_EQUALS) { + match_type_str = "="; + } else if(this.match_type == MatchTypeEnum.MATCH_LIKE) { + match_type_str = " LIKE "; + } else { + throw new Error('Unsupported match type: ' + this.match_type); + } + + return "(" + (this.negate ? "NOT " : "") + match_against_str + "\"" + match_type_str + "\"" + this.match_from + ")"; + } } -export function image_filter_to_where(image_filter) { - var match_from = false; - var match_to = image_filter.match_against; - var match_operator = false; - - if(image_filter.type == ResultFilterTypeEnum.MATCH_NAME) { - match_from = "Image.name"; - } else { - throw new Error("Unsupported image filter type: " + image_filter.type); - } +export const LogicalOperatorEnum = { + AND: 1, + OR: 2, +} - if(image_filter.match_type == MatchTypeEnum.MATCH_EQUALS) { - match_operator = "="; - } else if(image_filter.match_type == MatchTypeEnum.MATCH_LIKE) { - match_operator = " LIKE "; +export class LogicalOperatorFilter extends ResultFilter { + constructor(type, a, b, op) { super(type); this.sub_filter_a = a; this.sub_filter_b = b; this.operator = op; } + sub_filter_a = false; + sub_filter_b = false; + operator = LogicalOperatorEnum.AND; + + to_sql_where() { + var where1 = this.sub_filter_a.to_sql_where(); + var where2 = this.sub_filter_b.to_sql_where(); + var operator_str = ""; + if(this.operator == LogicalOperatorEnum.AND) { + operator_str = " AND "; + } else if(this.operator == LogicalOperatorEnum.OR) { + operator_str = " OR "; + } else { + throw new Error('Unsupported logical operator: ' + this.operator); + } + return "(" + where1 + operator_str + where2 + ")"; } +} - return match_from + match_operator + match_to; +export class UserQuery { + image_filter = new ConstFilter(ResultTypeEnum.IMAGE, true); + album_filter = new ConstFilter(ResultTypeEnum.ALBUM, true); } // This query will return database entries with the fields "id", "uniqueHash", "relativePath" (of the album) and "name" for each matching image. @@ -80,32 +144,16 @@ export function image_query_with_where(maybe_where) { } export function maybe_image_query(user_query) { - if(!user_query.include_result_types.includes(ResultTypeEnum.IMAGE)) { - return false; - } var where = false; - if(user_query.image_filters.length) { - where = "WHERE "; - var i = 0; - user_query.image_filters.forEach(elem => { - if(i > 0) { - where += "AND"; - } - where += image_filter_to_where(elem) + " "; - i++; - }); + if(user_query.image_filter) { + where = "WHERE " + user_query.image_filter.to_sql_where(); } - return image_query_with_where(where); } -function filter_from_text_segment(segment) { - var r = new ResultFilter(); - r.match_against = segment['text']; - r.negate = segment['negated']; - r.match_type = MatchTypeEnum.MATCH_EQUALS; - r.type = ResultFilterTypeEnum.MATCH_NAME; - return r; +function filter_from_text_segment(result_type, segment) { + return new MatchingFilter(result_type, MatchAgainstEnum.MATCH_RESULT_NAME, + segment['text'], MatchTypeEnum.MATCH_EQUALS, segment['negated']); } export function user_query_from_search_string(search_string) { @@ -118,9 +166,14 @@ export function user_query_from_search_string(search_string) { var r = new UserQuery(); texts.forEach(text => { - r.result_filters.push(filter_from_text_segment(text)); + console.log(text); + r.image_filter = new LogicalOperatorFilter(ResultTypeEnum.IMAGE, r.image_filter, + filter_from_text_segment(ResultTypeEnum.IMAGE, text), LogicalOperatorEnum.AND); + r.album_filter = new LogicalOperatorFilter(ResultTypeEnum.ALBUM, r.album_filter, + filter_from_text_segment(ResultTypeEnum.ALBUM, text), LogicalOperatorEnum.AND); }); console.log(search_string); console.log(r); + console.log(maybe_image_query(r)); } \ No newline at end of file