Skip to content

Commit

Permalink
Add method to exclude or include some tags
Browse files Browse the repository at this point in the history
  • Loading branch information
RadhiFadlillah committed Aug 11, 2019
1 parent 11c6680 commit 4e76288
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 66 deletions.
11 changes: 7 additions & 4 deletions internal/cmd/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func printCmd() *cobra.Command {
cmd.Flags().BoolP("index-only", "i", false, "Only print the index of bookmarks")
cmd.Flags().StringP("search", "s", "", "Search bookmark with specified keyword")
cmd.Flags().StringSliceP("tags", "t", []string{}, "Print bookmarks with matching tag(s)")
cmd.Flags().StringSliceP("exclude-tags", "e", []string{}, "Print bookmarks without these tag(s)")

return cmd
}
Expand All @@ -36,6 +37,7 @@ func printHandler(cmd *cobra.Command, args []string) {
useJSON, _ := cmd.Flags().GetBool("json")
indexOnly, _ := cmd.Flags().GetBool("index-only")
orderLatest, _ := cmd.Flags().GetBool("latest")
excludedTags, _ := cmd.Flags().GetStringSlice("exclude-tags")

// Convert args to ids
ids, err := parseStrIndices(args)
Expand All @@ -51,10 +53,11 @@ func printHandler(cmd *cobra.Command, args []string) {
}

searchOptions := database.GetBookmarksOptions{
IDs: ids,
Tags: tags,
Keyword: keyword,
OrderMethod: orderMethod,
IDs: ids,
Tags: tags,
ExcludedTags: excludedTags,
Keyword: keyword,
OrderMethod: orderMethod,
}

bookmarks, err := db.GetBookmarks(searchOptions)
Expand Down
15 changes: 8 additions & 7 deletions internal/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ const (

// GetBookmarksOptions is options for fetching bookmarks from database.
type GetBookmarksOptions struct {
IDs []int
Tags []string
Keyword string
WithContent bool
OrderMethod OrderMethod
Limit int
Offset int
IDs []int
Tags []string
ExcludedTags []string
Keyword string
WithContent bool
OrderMethod OrderMethod
Limit int
Offset int
}

// DB is interface for accessing and manipulating data in database.
Expand Down
108 changes: 99 additions & 9 deletions internal/database/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,28 +228,72 @@ func (db *MySQLDatabase) GetBookmarks(opts GetBookmarksOptions) ([]model.Bookmar
// Add where clause
args := []interface{}{}

// Add where clause for IDs
if len(opts.IDs) > 0 {
query += ` AND id IN (?)`
args = append(args, opts.IDs)
}

// Add where clause for search keyword
if opts.Keyword != "" {
query += ` AND (
url LIKE ? OR
MATCH(title, excerpt, content) AGAINST (? IN BOOLEAN MODE)
)`

args = append(args,
"%"+opts.Keyword+"%",
opts.Keyword)
args = append(args, "%"+opts.Keyword+"%", opts.Keyword)
}

// Add where clause for tags.
// First we check for * in excluded and included tags,
// which means all tags will be excluded and included, respectively.
excludeAllTags := false
for _, excludedTag := range opts.ExcludedTags {
if excludedTag == "*" {
excludeAllTags = true
opts.ExcludedTags = []string{}
break
}
}

includeAllTags := false
for _, includedTag := range opts.Tags {
if includedTag == "*" {
includeAllTags = true
opts.Tags = []string{}
break
}
}

// If all tags excluded, we will only show bookmark without tags.
// In other hand, if all tags included, we will only show bookmark with tags.
if excludeAllTags {
query += ` AND id NOT IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
} else if includeAllTags {
query += ` AND id IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
}

// Now we only need to find the normal tags
if len(opts.Tags) > 0 {
query += ` AND id IN (
SELECT bookmark_id FROM bookmark_tag
WHERE tag_id IN (SELECT id FROM tag WHERE name IN (?)))`
SELECT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?)
GROUP BY bt.bookmark_id
HAVING COUNT(bt.bookmark_id) = ?)`

args = append(args, opts.Tags, len(opts.Tags))
}

args = append(args, opts.Tags)
if len(opts.ExcludedTags) > 0 {
query += ` AND id NOT IN (
SELECT DISTINCT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?))`

args = append(args, opts.ExcludedTags)
}

// Add order clause
Expand Down Expand Up @@ -312,11 +356,13 @@ func (db *MySQLDatabase) GetBookmarksCount(opts GetBookmarksOptions) (int, error
// Add where clause
args := []interface{}{}

// Add where clause for IDs
if len(opts.IDs) > 0 {
query += ` AND id IN (?)`
args = append(args, opts.IDs)
}

// Add where clause for search keyword
if opts.Keyword != "" {
query += ` AND (
url LIKE ? OR
Expand All @@ -328,12 +374,56 @@ func (db *MySQLDatabase) GetBookmarksCount(opts GetBookmarksOptions) (int, error
opts.Keyword)
}

// Add where clause for tags.
// First we check for * in excluded and included tags,
// which means all tags will be excluded and included, respectively.
excludeAllTags := false
for _, excludedTag := range opts.ExcludedTags {
if excludedTag == "*" {
excludeAllTags = true
opts.ExcludedTags = []string{}
break
}
}

includeAllTags := false
for _, includedTag := range opts.Tags {
if includedTag == "*" {
includeAllTags = true
opts.Tags = []string{}
break
}
}

// If all tags excluded, we will only show bookmark without tags.
// In other hand, if all tags included, we will only show bookmark with tags.
if excludeAllTags {
query += ` AND id NOT IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
} else if includeAllTags {
query += ` AND id IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
}

// Now we only need to find the normal tags
if len(opts.Tags) > 0 {
query += ` AND id IN (
SELECT bookmark_id FROM bookmark_tag
WHERE tag_id IN (SELECT id FROM tag WHERE name IN (?)))`
SELECT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?)
GROUP BY bt.bookmark_id
HAVING COUNT(bt.bookmark_id) = ?)`

args = append(args, opts.Tags, len(opts.Tags))
}

if len(opts.ExcludedTags) > 0 {
query += ` AND id NOT IN (
SELECT DISTINCT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?))`

args = append(args, opts.Tags)
args = append(args, opts.ExcludedTags)
}

// Expand query, because some of the args might be an array
Expand Down
104 changes: 98 additions & 6 deletions internal/database/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,13 @@ func (db *SQLiteDatabase) GetBookmarks(opts GetBookmarksOptions) ([]model.Bookma
// Add where clause
args := []interface{}{}

// Add where clause for IDs
if len(opts.IDs) > 0 {
query += ` AND b.id IN (?)`
args = append(args, opts.IDs)
}

// Add where clause for search keyword
if opts.Keyword != "" {
query += ` AND (b.url LIKE ? OR b.excerpt LIKE ? OR b.id IN (
SELECT docid id
Expand All @@ -242,12 +244,56 @@ func (db *SQLiteDatabase) GetBookmarks(opts GetBookmarksOptions) ([]model.Bookma
opts.Keyword)
}

// Add where clause for tags.
// First we check for * in excluded and included tags,
// which means all tags will be excluded and included, respectively.
excludeAllTags := false
for _, excludedTag := range opts.ExcludedTags {
if excludedTag == "*" {
excludeAllTags = true
opts.ExcludedTags = []string{}
break
}
}

includeAllTags := false
for _, includedTag := range opts.Tags {
if includedTag == "*" {
includeAllTags = true
opts.Tags = []string{}
break
}
}

// If all tags excluded, we will only show bookmark without tags.
// In other hand, if all tags included, we will only show bookmark with tags.
if excludeAllTags {
query += ` AND b.id NOT IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
} else if includeAllTags {
query += ` AND b.id IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
}

// Now we only need to find the normal tags
if len(opts.Tags) > 0 {
query += ` AND b.id IN (
SELECT bookmark_id FROM bookmark_tag
WHERE tag_id IN (SELECT id FROM tag WHERE name IN (?)))`
SELECT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?)
GROUP BY bt.bookmark_id
HAVING COUNT(bt.bookmark_id) = ?)`

args = append(args, opts.Tags, len(opts.Tags))
}

if len(opts.ExcludedTags) > 0 {
query += ` AND b.id NOT IN (
SELECT DISTINCT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?))`

args = append(args, opts.Tags)
args = append(args, opts.ExcludedTags)
}

// Add order clause
Expand Down Expand Up @@ -313,11 +359,13 @@ func (db *SQLiteDatabase) GetBookmarksCount(opts GetBookmarksOptions) (int, erro
// Add where clause
args := []interface{}{}

// Add where clause for IDs
if len(opts.IDs) > 0 {
query += ` AND b.id IN (?)`
args = append(args, opts.IDs)
}

// Add where clause for search keyword
if opts.Keyword != "" {
query += ` AND (b.url LIKE ? OR b.excerpt LIKE ? OR b.id IN (
SELECT docid id
Expand All @@ -331,12 +379,56 @@ func (db *SQLiteDatabase) GetBookmarksCount(opts GetBookmarksOptions) (int, erro
opts.Keyword)
}

// Add where clause for tags.
// First we check for * in excluded and included tags,
// which means all tags will be excluded and included, respectively.
excludeAllTags := false
for _, excludedTag := range opts.ExcludedTags {
if excludedTag == "*" {
excludeAllTags = true
opts.ExcludedTags = []string{}
break
}
}

includeAllTags := false
for _, includedTag := range opts.Tags {
if includedTag == "*" {
includeAllTags = true
opts.Tags = []string{}
break
}
}

// If all tags excluded, we will only show bookmark without tags.
// In other hand, if all tags included, we will only show bookmark with tags.
if excludeAllTags {
query += ` AND b.id NOT IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
} else if includeAllTags {
query += ` AND b.id IN (SELECT DISTINCT bookmark_id FROM bookmark_tag)`
}

// Now we only need to find the normal tags
if len(opts.Tags) > 0 {
query += ` AND b.id IN (
SELECT bookmark_id FROM bookmark_tag
WHERE tag_id IN (SELECT id FROM tag WHERE name IN (?)))`
SELECT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?)
GROUP BY bt.bookmark_id
HAVING COUNT(bt.bookmark_id) = ?)`

args = append(args, opts.Tags, len(opts.Tags))
}

if len(opts.ExcludedTags) > 0 {
query += ` AND b.id NOT IN (
SELECT DISTINCT bt.bookmark_id
FROM bookmark_tag bt
LEFT JOIN tag t ON bt.tag_id = t.id
WHERE t.name IN(?))`

args = append(args, opts.Tags)
args = append(args, opts.ExcludedTags)
}

// Expand query, because some of the args might be an array
Expand Down
6 changes: 3 additions & 3 deletions internal/view/js/component/bookmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var template = `
<p class="id" v-show="showId">{{id}}</p>
</a>
<div class="bookmark-tags" v-if="tags.length > 0">
<a v-for="tag in tags" @click="tagClicked(tag.name)">{{tag.name}}</a>
<a v-for="tag in tags" @click="tagClicked($event, tag.name)">{{tag.name}}</a>
</div>
<div class="spacer"></div>
<div class="bookmark-menu">
Expand Down Expand Up @@ -78,8 +78,8 @@ export default {
}
},
methods: {
tagClicked(name) {
this.$emit("tag-clicked", name);
tagClicked(name, event) {
this.$emit("tag-clicked", name, event);
},
selectBookmark() {
this.$emit("select", this.eventItem);
Expand Down
Loading

0 comments on commit 4e76288

Please sign in to comment.