implemented new filter for tags when requesting list of events:
until now, filtering was done _after_ reading events from the db. Now we first search viable appointment ids when tags are set and add these to the where clause for the actual request Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -4,6 +4,7 @@ package de.srsoftware.cal.db;
|
|||||||
import de.srsoftware.cal.api.Appointment;
|
import de.srsoftware.cal.api.Appointment;
|
||||||
import de.srsoftware.tools.Result;
|
import de.srsoftware.tools.Result;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ public interface Database {
|
|||||||
* @param till restrict appointments to times before this date time
|
* @param till restrict appointments to times before this date time
|
||||||
* @return list of appointments in this time span
|
* @return list of appointments in this time span
|
||||||
*/
|
*/
|
||||||
Result<List<Appointment>> list(LocalDateTime from, LocalDateTime till, Integer count, Integer offset);
|
Result<List<Appointment>> list(LocalDateTime from, LocalDateTime till, Integer count, Integer offset, Collection<String> tags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list appointments
|
* list appointments
|
||||||
|
|||||||
@@ -26,13 +26,18 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class MariaDB implements Database {
|
public class MariaDB implements Database {
|
||||||
private static final System.Logger LOG = System.getLogger(MariaDB.class.getSimpleName());
|
private static final System.Logger LOG = System.getLogger(MariaDB.class.getSimpleName());
|
||||||
private static final String APPOINTMENTS = "appointments";
|
private static final String APPOINTMENTS = "appointments";
|
||||||
private static final String APPOINTMENT_TAGS = "appointment_tags";
|
private static final String APPOINTMENT_ATTACHMENTS = "appointment_attachments";
|
||||||
private static final String APPOINTMENT_URLS = "appointment_urls";
|
private static final String APPOINTMENT_TAGS = "appointment_tags";
|
||||||
private static final String URLS = "urls";
|
private static final String APPOINTMENT_URLS = "appointment_urls";
|
||||||
private static final String APPOINTMENT_ATTACHMENTS = "appointment_attachments";
|
private static final String CONFIG = "config";
|
||||||
private static final String TAGS = "tags";
|
private static final Object DB_VERSION = "dbversion";
|
||||||
|
private static final String KEYNAME = "keyname";
|
||||||
|
private static final String TAGS = "tags";
|
||||||
|
private static final String TAG_SEARCH = "tag_search";
|
||||||
|
private static final String URLS = "urls";
|
||||||
|
private static final String VALUE = "value";
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
|
|
||||||
private MariaDB(Connection conn) throws SQLException {
|
private MariaDB(Connection conn) throws SQLException {
|
||||||
@@ -42,15 +47,17 @@ public class MariaDB implements Database {
|
|||||||
|
|
||||||
private void applyUpdates() throws SQLException {
|
private void applyUpdates() throws SQLException {
|
||||||
LOG.log(INFO, "Checking for updates…");
|
LOG.log(INFO, "Checking for updates…");
|
||||||
var rs = select("value").from("config").where("keyname", equal("dbversion")).exec(connection);
|
var rs = select(VALUE).from(CONFIG).where(KEYNAME, equal(DB_VERSION)).exec(connection);
|
||||||
var version = 0;
|
var version = 0;
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
version = rs.getInt("value");
|
version = rs.getInt(VALUE);
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 0:
|
case 0:
|
||||||
createTables();
|
createTables();
|
||||||
|
case 1:
|
||||||
|
createTagSearch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +65,11 @@ public class MariaDB implements Database {
|
|||||||
throw new RuntimeException("%s.createTables() not implemented!");
|
throw new RuntimeException("%s.createTables() not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createTagSearch() throws SQLException {
|
||||||
|
connection.prepareStatement("CREATE VIEW tag_search AS SELECT aid, GROUP_CONCAT(keyword) AS tags FROM appointment_tags LEFT JOIN tags ON appointment_tags.tid = tags.tid GROUP BY aid").execute();
|
||||||
|
Query.update(CONFIG).set(VALUE).where(KEYNAME,equal(DB_VERSION)).prepare(connection).apply(2);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Appointment> add(Appointment appointment) {
|
public Result<Appointment> add(Appointment appointment) {
|
||||||
try {
|
try {
|
||||||
@@ -162,13 +174,28 @@ public class MariaDB implements Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<List<Appointment>> list(LocalDateTime from, LocalDateTime till, Integer count, Integer offset) {
|
public Result<List<Appointment>> list(LocalDateTime from, LocalDateTime till, Integer count, Integer offset, Collection<String> tags) {
|
||||||
|
List<Long> aids = null;
|
||||||
|
if (tags != null && !tags.isEmpty()){
|
||||||
|
var query = select(AID).from(TAG_SEARCH);
|
||||||
|
for (var tag : tags) query.where(TAGS,like("%"+tag+"%"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var rs = query.exec(connection);
|
||||||
|
aids = new ArrayList<>();
|
||||||
|
while (rs.next()) aids.add(rs.getLong(AID));
|
||||||
|
rs.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return SqlError.of(e,"Failed to read appointment ids for tags %s",tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
var query = select("appointments.*", "GROUP_CONCAT(keyword) AS tags")
|
var query = select("appointments.*", "GROUP_CONCAT(keyword) AS tags")
|
||||||
.from(APPOINTMENTS)
|
.from(APPOINTMENTS)
|
||||||
.leftJoin(AID, "appointment_tags", AID)
|
.leftJoin(AID, "appointment_tags", AID)
|
||||||
.leftJoin("tid", "tags", "tid")
|
.leftJoin("tid", "tags", "tid")
|
||||||
.groupBy(AID)
|
.groupBy(AID)
|
||||||
.sort("start ASC");
|
.sort("start ASC");
|
||||||
|
if (aids != null && !aids.isEmpty()) query.where(APPOINTMENTS+"."+AID,in(aids.toArray()));
|
||||||
if (from != null) query.where(START, moreThan(Timestamp.valueOf(from)));
|
if (from != null) query.where(START, moreThan(Timestamp.valueOf(from)));
|
||||||
if (till != null) query.where(END, lessThan(Timestamp.valueOf(till)));
|
if (till != null) query.where(END, lessThan(Timestamp.valueOf(till)));
|
||||||
if (count != null) query.limit(count);
|
if (count != null) query.limit(count);
|
||||||
@@ -186,6 +213,7 @@ public class MariaDB implements Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addAttachments(ArrayList<Appointment> list) {
|
private void addAttachments(ArrayList<Appointment> list) {
|
||||||
|
if (list.isEmpty()) return;
|
||||||
var map = new HashMap<Long,BaseAppointment>();
|
var map = new HashMap<Long,BaseAppointment>();
|
||||||
|
|
||||||
list.stream().filter(app -> app instanceof BaseAppointment)
|
list.stream().filter(app -> app instanceof BaseAppointment)
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ public class ApiEndpoint extends PathHandler {
|
|||||||
Result<LocalDateTime> end = parseDate(param.get(END));
|
Result<LocalDateTime> end = parseDate(param.get(END));
|
||||||
var endDate = (end == null) ? null: end.optional().orElse(null);
|
var endDate = (end == null) ? null: end.optional().orElse(null);
|
||||||
|
|
||||||
return db.list(startDate, endDate, count, offset).map(res -> filterByTags(res, tags));
|
return db.list(startDate, endDate, count, offset, tags).map(res -> filterByTags(res, tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result<List<Appointment>> filterByTags(Result<List<Appointment>> res, List<String> tags) {
|
private Result<List<Appointment>> filterByTags(Result<List<Appointment>> res, List<String> tags) {
|
||||||
|
|||||||
Reference in New Issue
Block a user