Got album queries working.

master
Sander Vocke 6 years ago
parent 500aea8d18
commit 508fa9feb5
  1. 10
      src/TableLine.css
  2. 4
      src/database.js
  3. 31
      src/index.js
  4. 49
      src/media.js
  5. 86
      src/queries.js

@ -1,27 +1,27 @@
.PhotoTableLine_body {
.TableLine_body {
border: 2px solid black;
background-color: lightgrey;
height:80px;
}
.PhotoTableLine_thumb {
.TableLine_thumb {
height: inherit;
}
.PhotoTableLine_field {
.TableLine_field {
border: 2px solid black;
float: left;
height: inherit;
}
.PhotoTableLine_textsubfield {
.TableLine_textsubfield {
display: flex;
align-items: center;
justify-content: center;
height: inherit;
}
.PhotoTableLine_textsubsubfield {
.TableLine_textsubsubfield {
margin: 8px;
border: 0 solid black;
}

@ -15,7 +15,9 @@ export const DBSourceEnum = {
export function alasql_async_queries(alasql_object, queries) {
var p = Promise.resolve(null);
for (let i = 0; i < queries.length; i++) {
p = p.then(() => { return alasql_object.promise(queries[i]); });
p = p.then(() => {
return alasql_object.promise(queries[i]);
});
}
return p;

@ -2,8 +2,8 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { Fetch } from './fetch.js';
import { ProvideDB, DBQueryConsole, DBQueryBar, DBTypeEnum, DBSourceEnum } from './database.js';
import { PhotoView, PhotoThumbView, PhotoTableLine } from './media.js';
import { do_image_query, image_query_with_where, user_query_from_search_string, maybe_image_query } from './queries.js';
import { PhotoTableLine, MediaTableLine } from './media.js';
import { do_image_query, do_album_query, image_query_with_where, user_query_from_search_string, maybe_image_query, maybe_album_query } from './queries.js';
import './index.css';
import { thisExpression } from '@babel/types';
@ -80,11 +80,11 @@ export class ImageWhereConsole extends React.Component {
}
}
const PhotosTable = ({ photos }) => (
const MediaTable = ({ items }) => (
<>
{
photos.map((value, index) => {
return <PhotoTableLine photo={value} />
items.map((value, index) => {
return value && <MediaTableLine media={value} />
})
}
</>
@ -94,19 +94,26 @@ export class TestDBStringQuery extends React.Component {
state = {
string: false,
query: false,
sql_query: false,
photos: false
sql_image_query: false,
sql_album_query: false,
photos: false,
albums: false,
}
onQueryChangeHandler = str => { this.setState({ string: str }); }
onQuerySubmitHandler = () => {
var q = user_query_from_search_string(this.state.string);
var sql_q = maybe_image_query(q);
this.setState({ query: q, sql_query: sql_q });
do_image_query(sql_q, this.props.db, "/test_photos", "/test_photos_thumbs").then(photos => {
var sql_image_query = maybe_image_query(q);
var sql_album_query = maybe_album_query(q);
this.setState({ query: q, sql_image_query: sql_image_query, sql_album_query: sql_album_query, photos: false, albums: false });
do_image_query(sql_image_query, this.props.db, "/test_photos", "/test_photos_thumbs").then(photos => {
console.log(photos);
this.setState({ done: true, photos: photos });
});
do_album_query(sql_album_query, this.props.db, "/test_photos", "/test_photos_thumbs").then(albums => {
console.log(albums);
this.setState({ done: true, albums: albums });
});
}
render() {
@ -117,7 +124,9 @@ export class TestDBStringQuery extends React.Component {
<DBQueryBar onChange={this.onQueryChangeHandler}/>
<button onClick={this.onQuerySubmitHandler}>Submit</button>
{ this.state.photos && <p>Found {this.state.photos.length} photos.</p> }
{ this.state.photos && <PhotosTable photos={this.state.photos} /> }
{ this.state.photos && <MediaTable items={this.state.photos} /> }
{ this.state.albums && <p>Found {this.state.albums.length} albums.</p> }
{ this.state.albums && <MediaTable items={this.state.albums} /> }
</div>
</>
);

@ -1,5 +1,6 @@
import React from 'react';
import './PhotoTableLine.css';
import './TableLine.css';
import { findAllByDisplayValue } from '@testing-library/dom';
export class Media { }
@ -12,6 +13,14 @@ export class Photo extends Media {
}
}
export class Album extends Media {
state = {
id: false,
name: false, // Equal to the last item in the relativePath
relative_path: false,
}
}
export function create_photo(maybe_id, maybe_name, maybe_path, maybe_thumbnail_path) {
var p = new Photo();
if (maybe_id) { p.state.id = maybe_id; }
@ -21,6 +30,14 @@ export function create_photo(maybe_id, maybe_name, maybe_path, maybe_thumbnail_p
return p;
}
export function create_album(maybe_id, maybe_name, maybe_relative_path) {
var a = new Album();
if (maybe_id) { a.state.id = maybe_id; }
if (maybe_name) { a.state.name = maybe_name; }
if (maybe_relative_path) { a.state.relative_path = maybe_relative_path; }
return a;
}
export const PhotoView = ({ photo }) => <img src={photo.state.path ? photo.state.path : "/resources/no_image_available.png"} alt="" />;
export class PhotoThumbView extends React.Component {
@ -37,9 +54,33 @@ export class PhotoThumbView extends React.Component {
export const PhotoTableLine = ({ photo }) => (
<>
<div class="PhotoTableLine_body">
<div class="PhotoTableLine_field"><PhotoThumbView photo={photo} class="PhotoTableLine_thumb" href={photo.state.path}/></div>
<div class="PhotoTableLine_field"><div class="PhotoTableLine_textsubfield"><div class="PhotoTableLine_textsubsubfield"><p>{photo.state.name ? photo.state.name : "Unknown"}</p></div></div></div>
<div class="TableLine_body">
<div class="TableLine_field"><PhotoThumbView photo={photo} class="TableLine_thumb" href={photo.state.path} /></div>
<div class="TableLine_field"><div class="TableLine_textsubfield"><div class="TableLine_textsubsubfield"><p>{photo.state.name ? photo.state.name : "Unknown name"}</p></div></div></div>
</div>
</>
)
export const AlbumTableLine = ({ album }) => (
<>
<div class="TableLine_body">
<div class="TableLine_field"><div class="TableLine_textsubfield"><div class="TableLine_textsubsubfield"><p>Album</p></div></div></div>
<div class="TableLine_field"><div class="TableLine_textsubfield"><div class="TableLine_textsubsubfield"><p>{album.state.name ? album.state.name : "Unknown name"}</p></div></div></div>
<div class="TableLine_field"><div class="TableLine_textsubfield"><div class="TableLine_textsubsubfield"><p>{album.state.relative_path ? album.state.relative_path : "Unknown relative path"}</p></div></div></div>
</div>
</>
)
export const MediaTableLine = ({ media }) => (
<>
{
(() => {
if (media instanceof Photo) {
return <PhotoTableLine photo={media} />;
} else if (media instanceof Album) {
return <AlbumTableLine album={media} />;
}
})()
}
</>
)

@ -1,5 +1,9 @@
import { Photo, PhotoView, PhotoThumbView, create_photo } from './media.js';
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) {
@ -19,9 +23,26 @@ export function do_image_query(query, database, collection_path, collection_thum
});
}
export function do_album_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 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_LIKE: 2,
MATCH_REGEXP: 2,
};
export const MatchAgainstEnum = {
@ -52,24 +73,6 @@ export class ConstFilter extends ResultFilter {
}
}
function match_column_name(result_type, match_against) {
if(match_against == MatchAgainstEnum.MATCH_IMAGE_NAME) {
return "Images.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);
@ -79,8 +82,8 @@ export class MatchingFilter extends ResultFilter {
this.negate = negate;
}
// What kind of filtering to apply
match_against = MatchAgainstEnum.MATCH_RESULT_NAME;
// What string to match against, e.g. "Image.name" (field) or "\"Image.name\"" (literal)
match_against = "";
// optional string used in the filtering
match_from = "";
@ -92,18 +95,17 @@ export class MatchingFilter extends ResultFilter {
negate = false;
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 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 " : "") + match_against_str + match_type_str + this.match_from + ")";
return "(" + (this.negate ? "NOT " : "") + this.match_against + match_type_str + this.match_from + ")";
}
}
@ -143,6 +145,11 @@ 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) {
@ -151,9 +158,31 @@ export function maybe_image_query(user_query) {
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) {
return new MatchingFilter(result_type, MatchAgainstEnum.MATCH_RESULT_NAME,
"\"" + segment['text'] + "\"", MatchTypeEnum.MATCH_EQUALS, segment['negated']);
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) {
@ -176,6 +205,7 @@ export function user_query_from_search_string(search_string) {
console.log(search_string);
console.log(r);
console.log(maybe_image_query(r));
console.log(maybe_album_query(r));
return r;
}
Loading…
Cancel
Save