diff --git a/NEWS b/NEWS index c1d1e3f88e..3c2110d55f 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ ver 0.24 (not yet released) - stickers on playlists and some tag types - new command "stickernames" - "sticker find" supports sort and window parameter + - "sticker find" supports integer comparision * database - attribute "added" shows when each song was added to the database - proxy: require MPD 0.21 or later diff --git a/doc/protocol.rst b/doc/protocol.rst index 86b1c60e21..b654801cab 100644 --- a/doc/protocol.rst +++ b/doc/protocol.rst @@ -1468,7 +1468,7 @@ the database for songs). For each matching song, it prints the URI and that one sticker's value. - ``sort`` sorts the result by "``uri``" or "``value``". [#since_0_24]_ + ``sort`` sorts the result by "``uri``","``value`` or "``value_int``" (casts the sticker value to an integer). [#since_0_24]_ .. _command_sticker_find_value: @@ -1476,7 +1476,7 @@ the database for songs). Searches for stickers with the given value. Other supported operators are: - "``<``", "``>``" + "``<``", "``>``" for strings and "``lt``", "``gt``" to cast the value to an integer. Examples: diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index d08c673daa..70ebcc8d26 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -406,7 +406,10 @@ handle_sticker(Client &client, Request args, Response &r) descending = true; ++s; } - if (StringIsEqual(s, "uri") || StringIsEqual(s, "value")) { + if (StringIsEqual(s, "uri") || + StringIsEqual(s, "value") || + StringIsEqual(s, "value_int") + ) { sort = s; } else { @@ -430,6 +433,10 @@ handle_sticker(Client &client, Request args, Response &r) op = StickerOperator::LESS_THAN; else if (StringIsEqual(op_s, ">")) op = StickerOperator::GREATER_THAN; + else if (StringIsEqual(op_s, "lt")) + op = StickerOperator::LESS_THAN_INT; + else if (StringIsEqual(op_s, "gt")) + op = StickerOperator::GREATER_THAN_INT; else { r.FmtError(ACK_ERROR_ARG, "bad operator \"{}\"", op_s); return CommandResult::ERROR; diff --git a/src/sticker/Database.cxx b/src/sticker/Database.cxx index d259e82672..68f9232061 100644 --- a/src/sticker/Database.cxx +++ b/src/sticker/Database.cxx @@ -24,6 +24,9 @@ enum sticker_sql_find { STICKER_SQL_FIND_LT, STICKER_SQL_FIND_GT, + STICKER_SQL_FIND_LT_INT, + STICKER_SQL_FIND_GT_INT, + STICKER_SQL_FIND_COUNT }; @@ -55,6 +58,12 @@ static constexpr auto sticker_sql_find = std::array { //[STICKER_SQL_FIND_GT] = "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND value>?", + + //[STICKER_SQL_FIND_LT_INT] = + "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND CAST(value AS INT)?", }; static constexpr auto sticker_sql = std::array { @@ -317,13 +326,15 @@ StickerDatabase::BindFind(const char *type, const char *base_uri, auto order_by = sort[0] == '\0' ? std::string() - : fmt::format("order by {} {}", sort, descending ? "desc" : "asc"); + : StringIsEqual(sort, "value_int") + ? fmt::format("ORDER BY CAST(value AS INT) {}", descending ? "desc" : "asc") + : fmt::format("ORDER BY {} {}", sort, descending ? "desc" : "asc"); auto offset = window.IsAll() ? std::string() : window.IsOpenEnded() - ? fmt::format("limit -1 offset {}", window.start) - : fmt::format("limit {} offset {}", window.Count(), window.start); + ? fmt::format("LIMIT -1 OFFSET {}", window.start) + : fmt::format("LIMIT {} OFFSET {}", window.Count(), window.start); std::string sql_str; sqlite3_stmt *sql; @@ -356,6 +367,20 @@ StickerDatabase::BindFind(const char *type, const char *base_uri, sql = Prepare(db, sql_str.c_str()); BindAll(sql, type, base_uri, name, value); return sql; + + case StickerOperator::LESS_THAN_INT: + sql_str = fmt::format("{} {} {}", + sticker_sql_find[STICKER_SQL_FIND_LT_INT], order_by, offset); + sql = Prepare(db, sql_str.c_str()); + BindAll(sql, type, base_uri, name, value); + return sql; + + case StickerOperator::GREATER_THAN_INT: + sql_str = fmt::format("{} {} {}", + sticker_sql_find[STICKER_SQL_FIND_GT_INT], order_by, offset); + sql = Prepare(db, sql_str.c_str()); + BindAll(sql, type, base_uri, name, value); + return sql; } assert(false); diff --git a/src/sticker/Database.hxx b/src/sticker/Database.hxx index a7a1987a96..d0e3e9fe83 100644 --- a/src/sticker/Database.hxx +++ b/src/sticker/Database.hxx @@ -62,6 +62,9 @@ class StickerDatabase { SQL_FIND_LT, SQL_FIND_GT, + SQL_FIND_LT_INT, + SQL_FIND_GT_INT, + SQL_FIND_COUNT }; diff --git a/src/sticker/Match.hxx b/src/sticker/Match.hxx index d3a0cc9e36..17a7bab9ec 100644 --- a/src/sticker/Match.hxx +++ b/src/sticker/Match.hxx @@ -28,6 +28,18 @@ enum class StickerOperator { * value bigger than the specified one. */ GREATER_THAN, + + /** + * Matches if a sticker with the specified name exists with a + * integer value smaller than the specified one. + */ + LESS_THAN_INT, + + /** + * Matches if a sticker with the specified name exists with a + * integer value bigger than the specified one. + */ + GREATER_THAN_INT, }; #endif