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("/");
r.shift();
if(path[0] === '/') { r.shift(); }
return r;
}
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;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var subitem = false;
var required_relative_path = (current_item.data === "/") ?
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_relative_path) {
if (child.data === required_path) {
subitem = child;
break;
}
@ -48,7 +48,7 @@ export function insert_into_album_tree(treebaseitem, treeitem) {
if (!subitem) {
var new_sub = new NavTreeItem(
part,
required_relative_path,
required_path,
[]
);
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) {
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) {
@ -84,11 +110,12 @@ export function build_tags_tree(all_db_tags) {
var tag = all_db_tags[i];
var item = new NavTreeItem(
tag.state.name,
tag.state.name,
tag.state.fullname,
[]
);
insert_into_tag_tree(tree, item);
};
return tree;
}

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

@ -109,7 +109,6 @@ export function LoadedMainPage(props) {
}
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_albums = !_.isEqual(q.album_filter, gallery_user_query.album_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 {
state = {
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;
}
export function create_tag(maybe_id, maybe_name) {
export function create_tag(maybe_id, maybe_name, maybe_fullname) {
var t = new Tag();
if (maybe_id) { t.state.id = maybe_id; }
if (maybe_name) { t.state.name = maybe_name; }
if (maybe_fullname) { t.state.fullname = maybe_fullname }
return t;
}

@ -11,6 +11,7 @@ export function do_image_query(query, database, collection_path, collection_thum
var queries = [];
queries.push(query);
sqljs_async_queries(database, queries).then(res => {
console.log("response: ", res);
var photos = [];
if (res && Array.isArray(res) && res.length > 0) {
var cols = res[0].columns;
@ -30,7 +31,8 @@ export function do_image_query(query, database, collection_path, collection_thum
});
}
resolve(photos);
});
})
.catch(err => { throw err; });
});
}
@ -58,13 +60,14 @@ export function do_tag_query(query, database) {
return new Promise(function (resolve, reject) {
var queries = [];
queries.push(query);
console.log("Provided DB tags schema before query:", database.exec("PRAGMA table_info([Tags]);"));
sqljs_async_queries(database, queries).then(res => {
var tags = [];
if (res && Array.isArray(res) && res.length > 0) {
var cols = res[0].columns;
var data = res[0].values;
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);
@ -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_NATURAL: 5,
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 = {
@ -164,7 +170,7 @@ export class MatchingFilter extends ResultFilter {
+ escape_regex(this.match_from)
+ '.*"))';
} 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) {
return 'REGEXP(Albums.relativePath, "'
+ escape_regex(this.match_from)
@ -176,7 +182,17 @@ export class MatchingFilter extends ResultFilter {
+ escape_regex(this.match_from)
+ '(\/[^\/]+)*")';
} 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);
@ -314,7 +330,7 @@ function filter_from_text_segment(result_type, segment) {
var album_filter = new MatchingFilter(
result_type,
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);
@ -326,18 +342,18 @@ function filter_from_text_segment(result_type, segment) {
name_filter = new MatchingFilter(
result_type,
segment['text'],
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS_OR_CHILD
);
filter = name_filter;
if (segment['negated']) {
filter = new NegationFilter(result_type, filter);
}
} else if (result_type === ResultTypeEnum.TAG) {
// Match against the tag name.
// TODO: We need a natural matcher for tag names
name_filter = new MatchingFilter(
result_type,
segment['text'],
MatchTypeEnum.MATCH_TAG_EQUALS
MatchTypeEnum.MATCH_TAG_NAME_EQUALS_OR_CHILD
);
filter = name_filter;
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) {
var r = new UserQuery();
r.image_filter = new MatchingFilter(
ResultTypeEnum.IMAGE,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify();
r.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false).simplify();
r.tag_filter = new ConstFilter(ResultTypeEnum.TAG, false).simplify();
r.image_filter =
new MatchingFilter(
ResultTypeEnum.IMAGE,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
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;
}
export function user_query_from_browsed_tag(name) {
export function user_query_from_browsed_tag(tag_path) {
var r = new UserQuery();
r.image_filter = new MatchingFilter(
ResultTypeEnum.IMAGE,
name,
MatchTypeEnum.MATCH_TAG_EQUALS,
false).simplify();
r.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false).simplify();
r.tag_filter = new ConstFilter(ResultTypeEnum.TAG, false).simplify();
r.image_filter =
new MatchingFilter(
ResultTypeEnum.IMAGE,
tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
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;
}

@ -138,6 +138,9 @@ export function EditMatchingFilterExpression(props) {
<MenuItem value={MatchTypeEnum.MATCH_ALBUM_NATURAL}>Album Natural</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_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>
<TextField className={classes.margined} label="Value" type="text" onChange={handleMatchChange} />
</FormControl>
@ -311,6 +314,8 @@ export function MatchingFilterExpressionControl(props) {
.replace(/"$/g, '');
if (expr.match_type === MatchTypeEnum.MATCH_TAG_EQUALS) {
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) {
return <AlbumEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) {

Loading…
Cancel
Save