Got tags working.

master
Sander Vocke 6 years ago
parent dbc704d068
commit 70308af91e
  1. 43
      src/browser.js
  2. 28
      src/database.js
  3. 1
      src/main.js
  4. 6
      src/media.js
  5. 91
      src/queries.js
  6. 5
      src/userquerywidget.js

@ -22,25 +22,25 @@ class NavTreeItem {
} }
} }
export function split_relative_path(path) { export function split_path(path) {
var r = path.split("/"); var r = path.split("/");
r.shift(); if(path[0] === '/') { r.shift(); }
return r; return r;
} }
export function insert_into_album_tree(treebaseitem, treeitem) { export function insert_into_album_tree(treebaseitem, treeitem) {
var parts = split_relative_path(treeitem.data); var parts = split_path(treeitem.data);
var current_item = treebaseitem; var current_item = treebaseitem;
for (var i = 0; i < parts.length; i++) { for (var i = 0; i < parts.length; i++) {
var part = parts[i]; var part = parts[i];
var subitem = false; var subitem = false;
var required_relative_path = (current_item.data === "/") ? var required_path = (current_item.data === "/") ?
current_item.data + part : current_item.data + part :
current_item.data + "/" + part; current_item.data + "/" + part;
for (var j = 0; j < current_item.children.length; j++) { for (var j = 0; j < current_item.children.length; j++) {
var child = current_item.children[j]; var child = current_item.children[j];
if (child.data === required_relative_path) { if (child.data === required_path) {
subitem = child; subitem = child;
break; break;
} }
@ -48,7 +48,7 @@ export function insert_into_album_tree(treebaseitem, treeitem) {
if (!subitem) { if (!subitem) {
var new_sub = new NavTreeItem( var new_sub = new NavTreeItem(
part, part,
required_relative_path, required_path,
[] []
); );
current_item.children.push(new_sub); current_item.children.push(new_sub);
@ -75,7 +75,33 @@ export function build_albums_tree(all_db_albums) {
} }
export function insert_into_tag_tree(treebaseitem, treeitem) { export function insert_into_tag_tree(treebaseitem, treeitem) {
treebaseitem.children.push(treeitem); var parts = split_path(treeitem.data);
var current_item = treebaseitem;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var subitem = false;
var required_path = (current_item.data === "") ?
current_item.data + part :
current_item.data + "/" + part;
for (var j = 0; j < current_item.children.length; j++) {
var child = current_item.children[j];
if (child.data === required_path) {
subitem = child;
break;
}
}
if (!subitem) {
var new_sub = new NavTreeItem(
part,
required_path,
[]
);
current_item.children.push(new_sub);
subitem = new_sub;
}
current_item = subitem;
};
} }
export function build_tags_tree(all_db_tags) { export function build_tags_tree(all_db_tags) {
@ -84,11 +110,12 @@ export function build_tags_tree(all_db_tags) {
var tag = all_db_tags[i]; var tag = all_db_tags[i];
var item = new NavTreeItem( var item = new NavTreeItem(
tag.state.name, tag.state.name,
tag.state.name, tag.state.fullname,
[] []
); );
insert_into_tag_tree(tree, item); insert_into_tag_tree(tree, item);
}; };
return tree; return tree;
} }

@ -4,9 +4,19 @@ import NodeEnvironment from 'jest-environment-node';
export async function sqljs_async_queries(sqljs_object, queries) { export async function sqljs_async_queries(sqljs_object, queries) {
//var t0 = performance.now(); //var t0 = performance.now();
for (let i = 0; i < (queries.length - 1); i++) { for (let i = 0; i < (queries.length - 1); i++) {
sqljs_object.exec(queries[i]); console.log("Query: ", queries[i]);
try {
sqljs_object.exec(queries[i]);
} catch (e) {
throw e;
}
}
console.log("Query: ", queries[queries.length - 1]);
try {
var r = sqljs_object.exec(queries[queries.length - 1]);
} catch (e) {
throw e;
} }
var r = sqljs_object.exec(queries[queries.length - 1]);
//console.log("Queries took ", (performance.now() - t0), " ms."); //console.log("Queries took ", (performance.now() - t0), " ms.");
//console.log("Query result for ", queries[queries.length - 1], ": ", r); //console.log("Query result for ", queries[queries.length - 1], ": ", r);
return r; return r;
@ -87,7 +97,9 @@ export async function add_full_tag_info(db) {
db.exec(query); db.exec(query);
}); });
var r = db.exec("SELECT * FROM Tags;"); console.log(db.exec("PRAGMA table_info([Tags]);"));
return db;
} }
export function ProvideDB(props) { export function ProvideDB(props) {
@ -98,10 +110,10 @@ export function ProvideDB(props) {
useEffect(() => { useEffect(() => {
fetch_sqljs_db_from_sqlite(db_url) fetch_sqljs_db_from_sqlite(db_url)
.then(db => { .then(db => {
add_full_tag_info(db).then(() => { add_full_tag_info(db).then((newdb) => {
add_custom_functions(db); add_custom_functions(newdb);
setError(false); setError(false);
setDb(db); setDb(newdb);
}) })
}) })
.catch(error => { setError(error); }); .catch(error => { setError(error); });
@ -112,5 +124,9 @@ export function ProvideDB(props) {
db_error: error, db_error: error,
}; };
if (db != null) {
console.log("Provided DB tags schema:", db.exec("PRAGMA table_info([Tags]);"));
}
return children({ ...child_props }); return children({ ...child_props });
} }

@ -109,7 +109,6 @@ export function LoadedMainPage(props) {
} }
function onNewQuery(q) { function onNewQuery(q) {
console.log(q.image_filter, " ?= ", gallery_user_query.image_filter);
var do_update_photos = !_.isEqual(q.image_filter, gallery_user_query.image_filter); var do_update_photos = !_.isEqual(q.image_filter, gallery_user_query.image_filter);
var do_update_albums = !_.isEqual(q.album_filter, gallery_user_query.album_filter); var do_update_albums = !_.isEqual(q.album_filter, gallery_user_query.album_filter);
var do_update_tags = !_.isEqual(q.tag_filter, gallery_user_query.tag_filter); var do_update_tags = !_.isEqual(q.tag_filter, gallery_user_query.tag_filter);

@ -24,7 +24,8 @@ export class Album extends Media {
export class Tag extends Media { export class Tag extends Media {
state = { state = {
id: false, id: false,
name: false name: false, // This is the name of the leaf only, like "Sander"
fullname: false, // this is the full "path" to the tag, like "People/Sander"
} }
} }
@ -51,10 +52,11 @@ export function create_album(maybe_id, maybe_name, maybe_relative_path) {
return a; return a;
} }
export function create_tag(maybe_id, maybe_name) { export function create_tag(maybe_id, maybe_name, maybe_fullname) {
var t = new Tag(); var t = new Tag();
if (maybe_id) { t.state.id = maybe_id; } if (maybe_id) { t.state.id = maybe_id; }
if (maybe_name) { t.state.name = maybe_name; } if (maybe_name) { t.state.name = maybe_name; }
if (maybe_fullname) { t.state.fullname = maybe_fullname }
return t; return t;
} }

@ -11,6 +11,7 @@ export function do_image_query(query, database, collection_path, collection_thum
var queries = []; var queries = [];
queries.push(query); queries.push(query);
sqljs_async_queries(database, queries).then(res => { sqljs_async_queries(database, queries).then(res => {
console.log("response: ", res);
var photos = []; var photos = [];
if (res && Array.isArray(res) && res.length > 0) { if (res && Array.isArray(res) && res.length > 0) {
var cols = res[0].columns; var cols = res[0].columns;
@ -30,7 +31,8 @@ export function do_image_query(query, database, collection_path, collection_thum
}); });
} }
resolve(photos); resolve(photos);
}); })
.catch(err => { throw err; });
}); });
} }
@ -58,13 +60,14 @@ export function do_tag_query(query, database) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var queries = []; var queries = [];
queries.push(query); queries.push(query);
console.log("Provided DB tags schema before query:", database.exec("PRAGMA table_info([Tags]);"));
sqljs_async_queries(database, queries).then(res => { sqljs_async_queries(database, queries).then(res => {
var tags = []; var tags = [];
if (res && Array.isArray(res) && res.length > 0) { if (res && Array.isArray(res) && res.length > 0) {
var cols = res[0].columns; var cols = res[0].columns;
var data = res[0].values; var data = res[0].values;
data.forEach(row => { data.forEach(row => {
tags.push(create_tag(row[cols.indexOf("id")], row[cols.indexOf("fullname")])); tags.push(create_tag(row[cols.indexOf("id")], row[cols.indexOf("name")], row[cols.indexOf("fullname")]));
}); });
} }
resolve(tags); resolve(tags);
@ -79,7 +82,10 @@ export const MatchTypeEnum = {
MATCH_ALBUM_EQUALS_OR_CHILD: 4, // Match on the full name (relative path) of the relevant album, if any, or any of its children MATCH_ALBUM_EQUALS_OR_CHILD: 4, // Match on the full name (relative path) of the relevant album, if any, or any of its children
MATCH_ALBUM_NATURAL: 5, MATCH_ALBUM_NATURAL: 5,
MATCH_ALBUM_NAME_EQUALS: 6, // Match on the local album name (excluding parents) MATCH_ALBUM_NAME_EQUALS: 6, // Match on the local album name (excluding parents)
MATCH_TAG_EQUALS: 7, // Match on the name of the relevant tag(s), if any MATCH_TAG_EQUALS: 7, // Match on the full name (relative path) of the relevant tag, if any
MATCH_TAG_EQUALS_OR_CHILD: 8, // Match on the full name (path) of the relevant tag, if any, or any of its children
MATCH_TAG_NATURAL: 9,
MATCH_TAG_NAME_EQUALS: 10, // Match on the local tag name (excluding parents)
} }
export const ResultTypeEnum = { export const ResultTypeEnum = {
@ -164,7 +170,7 @@ export class MatchingFilter extends ResultFilter {
+ escape_regex(this.match_from) + escape_regex(this.match_from)
+ '.*"))'; + '.*"))';
} else if (this.match_type == MatchTypeEnum.MATCH_ALBUM_EQUALS) { } else if (this.match_type == MatchTypeEnum.MATCH_ALBUM_EQUALS) {
return '(Albums.relativePath = "' + this.match_from + '")'; return '(Albums.relativePath="' + this.match_from + '")';
} else if (this.match_type == MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) { } else if (this.match_type == MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) {
return 'REGEXP(Albums.relativePath, "' return 'REGEXP(Albums.relativePath, "'
+ escape_regex(this.match_from) + escape_regex(this.match_from)
@ -176,7 +182,17 @@ export class MatchingFilter extends ResultFilter {
+ escape_regex(this.match_from) + escape_regex(this.match_from)
+ '(\/[^\/]+)*")'; + '(\/[^\/]+)*")';
} else if (this.match_type == MatchTypeEnum.MATCH_TAG_EQUALS) { } else if (this.match_type == MatchTypeEnum.MATCH_TAG_EQUALS) {
return '(Tags.name="' + this.match_from + '")'; return '(Tags.fullname="' + this.match_from + '")';
} else if (this.match_type == MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD) {
return '(Tags.fullname NOT NULL AND REGEXP(Tags.fullname, "'
+ escape_regex(this.match_from)
+ '(\/[^\/]+)*"))';
} else if (this.match_type == MatchTypeEnum.MATCH_TAG_NATURAL) {
throw new Error("Natural matching on tag names is not yet supported.");
} else if (this.match_type == MatchTypeEnum.MATCH_TAG_NAME_EQUALS) {
return 'REGEXP(Tags.fullname, "\/(.*\/)*'
+ escape_regex(this.match_from)
+ '(\/[^\/]+)*")';
} }
console.log(this); console.log(this);
@ -314,7 +330,7 @@ function filter_from_text_segment(result_type, segment) {
var album_filter = new MatchingFilter( var album_filter = new MatchingFilter(
result_type, result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS_OR_CHILD
); );
filter = new LogicalOperatorFilter(result_type, name_filter, album_filter, LogicalOperatorEnum.OR); filter = new LogicalOperatorFilter(result_type, name_filter, album_filter, LogicalOperatorEnum.OR);
@ -326,18 +342,18 @@ function filter_from_text_segment(result_type, segment) {
name_filter = new MatchingFilter( name_filter = new MatchingFilter(
result_type, result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS_OR_CHILD
); );
filter = name_filter; filter = name_filter;
if (segment['negated']) { if (segment['negated']) {
filter = new NegationFilter(result_type, filter); filter = new NegationFilter(result_type, filter);
} }
} else if (result_type === ResultTypeEnum.TAG) { } else if (result_type === ResultTypeEnum.TAG) {
// Match against the tag name. // TODO: We need a natural matcher for tag names
name_filter = new MatchingFilter( name_filter = new MatchingFilter(
result_type, result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_TAG_EQUALS MatchTypeEnum.MATCH_TAG_NAME_EQUALS_OR_CHILD
); );
filter = name_filter; filter = name_filter;
if (segment['negated']) { if (segment['negated']) {
@ -371,26 +387,51 @@ export function user_query_from_search_string(search_string) {
export function user_query_from_browsed_album(album_path) { export function user_query_from_browsed_album(album_path) {
var r = new UserQuery(); var r = new UserQuery();
r.image_filter = new MatchingFilter( r.image_filter =
ResultTypeEnum.IMAGE, new MatchingFilter(
album_path, ResultTypeEnum.IMAGE,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD, album_path,
false).simplify(); MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
r.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false).simplify(); false).simplify();
r.tag_filter = new ConstFilter(ResultTypeEnum.TAG, false).simplify(); /*
r.album_filter =
new MatchingFilter(
ResultTypeEnum.ALBUM,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify();
r.tag_filter =
new MatchingFilter(
ResultTypeEnum.TAG,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify();
*/
return r; return r;
} }
export function user_query_from_browsed_tag(name) { export function user_query_from_browsed_tag(tag_path) {
var r = new UserQuery(); var r = new UserQuery();
r.image_filter = new MatchingFilter( r.image_filter =
ResultTypeEnum.IMAGE, new MatchingFilter(
name, ResultTypeEnum.IMAGE,
MatchTypeEnum.MATCH_TAG_EQUALS, tag_path,
false).simplify(); MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
r.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false).simplify(); false).simplify();
r.tag_filter = new ConstFilter(ResultTypeEnum.TAG, false).simplify(); /*
r.album_filter =
new MatchingFilter(
ResultTypeEnum.ALBUM,
tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
false).simplify();
r.tag_filter =
new MatchingFilter(
ResultTypeEnum.TAG,
tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
false).simplify();
*/
return r; return r;
} }

@ -138,6 +138,9 @@ export function EditMatchingFilterExpression(props) {
<MenuItem value={MatchTypeEnum.MATCH_ALBUM_NATURAL}>Album Natural</MenuItem> <MenuItem value={MatchTypeEnum.MATCH_ALBUM_NATURAL}>Album Natural</MenuItem>
<MenuItem value={MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS}>Album Name Equals</MenuItem> <MenuItem value={MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS}>Album Name Equals</MenuItem>
<MenuItem value={MatchTypeEnum.MATCH_TAG_EQUALS}>Tag Equals</MenuItem> <MenuItem value={MatchTypeEnum.MATCH_TAG_EQUALS}>Tag Equals</MenuItem>
<MenuItem value={MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD}>Tag Equals Or Child</MenuItem>
<MenuItem value={MatchTypeEnum.MATCH_TAG_NATURAL}>Tag Natural</MenuItem>
<MenuItem value={MatchTypeEnum.MATCH_TAG_NAME_EQUALS}>Tag Name Equals</MenuItem>
</Select> </Select>
<TextField className={classes.margined} label="Value" type="text" onChange={handleMatchChange} /> <TextField className={classes.margined} label="Value" type="text" onChange={handleMatchChange} />
</FormControl> </FormControl>
@ -311,6 +314,8 @@ export function MatchingFilterExpressionControl(props) {
.replace(/"$/g, ''); .replace(/"$/g, '');
if (expr.match_type === MatchTypeEnum.MATCH_TAG_EQUALS) { if (expr.match_type === MatchTypeEnum.MATCH_TAG_EQUALS) {
return <TagEqualsExpressionControl name={pretty_name} onClick={onClick} /> return <TagEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD) {
return <TagEqualsExpressionControl name={pretty_name + '(/...)'} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS) { } else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS) {
return <AlbumEqualsExpressionControl name={pretty_name} onClick={onClick} /> return <AlbumEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) { } else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) {

Loading…
Cancel
Save