diff --git a/store/db/migration/dev/LATEST__SCHEMA.sql b/store/db/migration/dev/LATEST__SCHEMA.sql index fad5573..8d006f0 100644 --- a/store/db/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/migration/dev/LATEST__SCHEMA.sql @@ -40,5 +40,6 @@ CREATE TABLE shortcut ( name TEXT NOT NULL UNIQUE, link TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', - visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE' + visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE', + tag TEXT NOT NULL DEFAULT '' ); diff --git a/store/db/migration/prod/LATEST__SCHEMA.sql b/store/db/migration/prod/LATEST__SCHEMA.sql index fad5573..8d006f0 100644 --- a/store/db/migration/prod/LATEST__SCHEMA.sql +++ b/store/db/migration/prod/LATEST__SCHEMA.sql @@ -40,5 +40,6 @@ CREATE TABLE shortcut ( name TEXT NOT NULL UNIQUE, link TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', - visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE' + visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE', + tag TEXT NOT NULL DEFAULT '' ); diff --git a/store/shortcut.go b/store/shortcut.go index 3c0e02b..68f3e7b 100644 --- a/store/shortcut.go +++ b/store/shortcut.go @@ -45,6 +45,7 @@ type Shortcut struct { Link string Description string Visibility Visibility + Tag string } type UpdateShortcut struct { @@ -55,6 +56,7 @@ type UpdateShortcut struct { Link *string Description *string Visibility *Visibility + Tag *string } type FindShortcut struct { @@ -63,6 +65,7 @@ type FindShortcut struct { RowStatus *RowStatus Name *string VisibilityList []Visibility + Tag *string } type DeleteShortcut struct { @@ -76,9 +79,9 @@ func (s *Store) CreateShortcut(ctx context.Context, create *Shortcut) (*Shortcut } defer tx.Rollback() - set := []string{"creator_id", "name", "link", "description", "visibility"} - args := []any{create.CreatorID, create.Name, create.Link, create.Description, create.Visibility} - placeholder := []string{"?", "?", "?", "?", "?"} + set := []string{"creator_id", "name", "link", "description", "visibility", "tag"} + args := []any{create.CreatorID, create.Name, create.Link, create.Description, create.Visibility, create.Tag} + placeholder := []string{"?", "?", "?", "?", "?", "?"} query := ` INSERT INTO shortcut ( @@ -126,6 +129,9 @@ func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*Sh if update.Visibility != nil { set, args = append(set, "visibility = ?"), append(args, update.Visibility.String()) } + if update.Tag != nil { + set, args = append(set, "tag = ?"), append(args, *update.Tag) + } if len(set) == 0 { return nil, fmt.Errorf("no update specified") } @@ -137,7 +143,7 @@ func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*Sh ` + strings.Join(set, ", ") + ` WHERE id = ? - RETURNING id, creator_id, created_ts, updated_ts, row_status, name, link, description, visibility + RETURNING id, creator_id, created_ts, updated_ts, row_status, name, link, description, visibility, tag ` shortcut := &Shortcut{} if err := tx.QueryRowContext(ctx, query, args...).Scan( @@ -150,6 +156,7 @@ func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*Sh &shortcut.Link, &shortcut.Description, &shortcut.Visibility, + &shortcut.Tag, ); err != nil { return nil, err } @@ -250,6 +257,9 @@ func listShortcuts(ctx context.Context, tx *sql.Tx, find *FindShortcut) ([]*Shor } where = append(where, fmt.Sprintf("visibility in (%s)", strings.Join(list, ","))) } + if v := find.Tag; v != nil { + where, args = append(where, "tag LIKE ?"), append(args, "%"+*v+"%") + } rows, err := tx.QueryContext(ctx, ` SELECT @@ -261,7 +271,8 @@ func listShortcuts(ctx context.Context, tx *sql.Tx, find *FindShortcut) ([]*Shor name, link, description, - visibility + visibility, + tag FROM shortcut WHERE `+strings.Join(where, " AND ")+` ORDER BY created_ts DESC`, @@ -285,6 +296,7 @@ func listShortcuts(ctx context.Context, tx *sql.Tx, find *FindShortcut) ([]*Shor &shortcut.Link, &shortcut.Description, &shortcut.Visibility, + &shortcut.Tag, ); err != nil { return nil, err } diff --git a/test/store/shortcut_test.go b/test/store/shortcut_test.go new file mode 100644 index 0000000..f1890aa --- /dev/null +++ b/test/store/shortcut_test.go @@ -0,0 +1,53 @@ +package teststore + +import ( + "context" + "testing" + + "github.com/boojack/shortify/store" + "github.com/stretchr/testify/require" +) + +func TestShortcutStore(t *testing.T) { + ctx := context.Background() + ts := NewTestingStore(ctx, t) + user, err := createTestingAdminUser(ctx, ts) + require.NoError(t, err) + shortcut, err := ts.CreateShortcut(ctx, &store.Shortcut{ + CreatorID: user.ID, + Name: "test", + Link: "https://test.link", + Description: "A test shortcut", + Visibility: store.VisibilityPrivate, + Tag: "test link", + }) + require.NoError(t, err) + shortcuts, err := ts.ListShortcuts(ctx, &store.FindShortcut{ + CreatorID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 1, len(shortcuts)) + require.Equal(t, shortcut, shortcuts[0]) + newLink := "https://new.link" + updatedShortcut, err := ts.UpdateShortcut(ctx, &store.UpdateShortcut{ + ID: shortcut.ID, + Link: &newLink, + }) + require.NoError(t, err) + require.Equal(t, newLink, updatedShortcut.Link) + tag := "test" + shortcut, err = ts.GetShortcut(ctx, &store.FindShortcut{ + Tag: &tag, + }) + require.NoError(t, err) + require.Equal(t, updatedShortcut, shortcut) + err = ts.DeleteShortcut(ctx, &store.DeleteShortcut{ + ID: shortcut.ID, + }) + require.NoError(t, err) + shortcuts, err = ts.ListShortcuts(ctx, &store.FindShortcut{ + CreatorID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 0, len(shortcuts)) +}