You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

217 lines
7.4 KiB

import { create_photo, create_album } from './media.js';
export function escape_regex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
export function do_image_query(query, database, collection_path, collection_thumbs_path) {
return new Promise(function (resolve, reject) {
var queries = [];
queries.push(query);
database.queries_async(queries).then(res => {
var photos = [];
if (res && Array.isArray(res)) {
res.forEach(row => {
var imagepath = process.env.PUBLIC_URL + collection_path + "/" + row["relativePath"] + "/" + row["name"];
var thumbpath = process.env.PUBLIC_URL + collection_thumbs_path + "/" + row["uniqueHash"] + ".jpg";
photos.push(create_photo(row["id"], row["name"], imagepath, thumbpath));
});
}
resolve(photos);
});
});
}
export function do_album_query(query, database) {
return new Promise(function (resolve, reject) {
var queries = [];
queries.push(query);
database.queries_async(queries).then(res => {
var albums = [];
if (res && Array.isArray(res)) {
res.forEach(row => {
var album_name = new String(row["relativePath"]).substring(row["relativePath"].lastIndexOf('/') + 1);
albums.push(create_album(row["id"], album_name, row["relativePath"]));
});
}
resolve(albums);
});
});
}
export const MatchTypeEnum = {
MATCH_EQUALS: 1,
MATCH_REGEXP: 2,
};
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)";
}
}
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 string to match against, e.g. "Image.name" (field) or "\"Image.name\"" (literal)
match_against = "";
// optional string used in the filtering
match_from = "";
// How to use the matching string
match_type = MatchTypeEnum.MATCH_EQUALS;
// If true, negates the filter
negate = false;
to_sql_where() {
var match_type_str = false;
if(this.match_type == MatchTypeEnum.MATCH_EQUALS) {
match_type_str = "=";
} else if(this.match_type == MatchTypeEnum.MATCH_REGEXP) {
match_type_str = " REGEXP ";
} else {
throw new Error('Unsupported match type: ' + this.match_type);
}
return "(" + (this.negate ? "NOT " : "") + this.match_against + match_type_str + this.match_from + ")";
}
}
export const LogicalOperatorEnum = {
AND: 1,
OR: 2,
}
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 + ")";
}
}
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.
export function image_query_with_where(maybe_where) {
return "SELECT Images.id, Images.name, Images.uniqueHash, Albums.relativePath FROM Images INNER JOIN Albums ON Images.album=Albums.id " + (maybe_where ? maybe_where : "") + ";";
}
// This query will return database entries with the fields "id" and "relativePath" for each matching album.
export function album_query_with_where(maybe_where) {
return "SELECT Albums.id, Albums.relativePath FROM Albums " + (maybe_where ? maybe_where : "") + ";";
}
export function maybe_image_query(user_query) {
var where = false;
if(user_query.image_filter) {
where = "WHERE " + user_query.image_filter.to_sql_where();
}
return image_query_with_where(where);
}
export function maybe_album_query(user_query) {
var where = false;
if(user_query.album_filter) {
where = "WHERE " + user_query.album_filter.to_sql_where();
}
return album_query_with_where(where);
}
function filter_from_text_segment(result_type, segment) {
var match_type = false;
var match_text = false;
var match_against = false;
if(result_type == ResultTypeEnum.IMAGE) {
match_type = MatchTypeEnum.MATCH_EQUALS;
match_text = "\"" + segment['text'] + "\"";
match_against = "Images.name";
} else if(result_type == ResultTypeEnum.ALBUM) {
// Match against the album "name", which is the basename of its relative path.
match_type = MatchTypeEnum.MATCH_REGEXP;
match_text = "\"" + '\/(.*\/)*' + escape_regex(segment['text']) + "\"";
match_against = "Albums.relativePath";
}
return new MatchingFilter(result_type, match_against,match_text, match_type, segment['negated']);
}
export function user_query_from_search_string(search_string) {
const parser = require('search-string');
var parsed = parser.parse(search_string);
var conditions = parsed.getParsedQuery();
var texts = parsed.getTextSegments();
var r = new UserQuery();
texts.forEach(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);
});
return r;
}
export function user_query_from_album_path(album_path) {
var r = new UserQuery();
var match_type = MatchTypeEnum.MATCH_EQUALS;
var match_text = "\"" + album_path + "\"";
var match_against = "Albums.relativePath";
r.image_filter = new MatchingFilter(ResultTypeEnum.ALBUM, match_against, match_text, match_type, false);
r.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false);
return r;
}