Refactoring, added generic Store

This commit is contained in:
2022-12-11 02:05:03 +03:00
parent 4a4917beed
commit ed012d3715
17 changed files with 559 additions and 347 deletions

90
storage/mongoStore.go Normal file
View File

@ -0,0 +1,90 @@
package storage
import (
"context"
"log"
"reflect"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
func NewStore[T any](db *MongodbStorage, collection string) Store[T] {
return Store[T]{
Db: db.Db,
Coll: db.Collection(collection),
}
}
type Store[T any] struct {
Db *mongo.Client
Coll *mongo.Collection
}
func (s Store[T]) InsertOne(ctx context.Context, item *T) (primitive.ObjectID, error) {
result, err := s.Coll.InsertOne(ctx, item)
if err != nil {
if e, ok := err.(mongo.WriteError); ok {
log.Printf("Error writing new item of type %v: %v ", reflect.TypeOf(item), e)
return primitive.NilObjectID, e
}
log.Printf("Error creating new item of type %v: %v ", reflect.TypeOf(item), err)
return primitive.NilObjectID, err
}
rid, _ := result.InsertedID.(primitive.ObjectID)
return rid, nil
}
func (s Store[T]) GetById(ctx context.Context, id primitive.ObjectID) (*T, error) {
res := s.Coll.FindOne(ctx, bson.D{{Key: "_id", Value: id}})
if res.Err() != nil {
return nil, res.Err()
}
var item T
res.Decode(&item)
return &item, nil
}
func (s Store[T]) GetOne(ctx context.Context, filter *bson.D) (*T, error) {
f := getFilter(filter)
res := s.Coll.FindOne(ctx, f)
if res.Err() != nil {
return nil, res.Err()
}
var item T
res.Decode(&item)
return &item, nil
}
func (s Store[T]) GetMany(ctx context.Context, filter *bson.D) ([]*T, error) {
f := getFilter(filter)
cur, err := s.Coll.Find(ctx, f)
if err != nil {
log.Println("Error fetching items: ", err)
return nil, err
}
var res []*T
err = cur.All(ctx, &res)
if err != nil {
log.Println("Error collecting items to slice: ", err)
return nil, err
}
return res, nil
}
func (s Store[T]) DeleteByID(ctx context.Context, id primitive.ObjectID) error {
_, err := s.Coll.DeleteOne(ctx, bson.D{{Key: "_id", Value: id}})
return err
}
func (s Store[T]) ReplaceByID(ctx context.Context, id primitive.ObjectID, item *T) error {
_, err := s.Coll.ReplaceOne(ctx, bson.D{{Key: "_id", Value: id}}, item)
return err
}
func getFilter(f *bson.D) bson.D {
if f == nil {
return bson.D{}
}
return *f
}

110
storage/mongostorage.go Normal file
View File

@ -0,0 +1,110 @@
package storage
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
type MongodbStorage struct {
Db *mongo.Client
}
func (m MongodbStorage) CreateUser(user *User) (primitive.ObjectID, error) {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.InsertOne(ctx, user)
}
func (m MongodbStorage) GetUserByID(id primitive.ObjectID) (*User, error) {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.GetById(ctx, id)
}
func (m MongodbStorage) GetUser(filter *bson.D) (*User, error) {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.GetOne(ctx, filter)
}
func (m MongodbStorage) GetUsers(filter *bson.D) ([]*User, error) {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.GetMany(ctx, filter)
}
func (m MongodbStorage) UpdateUser(user *User) error {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.ReplaceByID(ctx, user.Id, user)
}
func (m MongodbStorage) DeleteUser(id primitive.ObjectID) error {
ctx := context.TODO()
store := NewStore[User](&m, "users")
return store.DeleteByID(ctx, id)
}
func (m MongodbStorage) CreateSession(s *Session) (primitive.ObjectID, error) {
ctx := context.TODO()
store := NewStore[Session](&m, "sessions")
return store.InsertOne(ctx, s)
}
func (m MongodbStorage) GetSessionByToken(token string) (*Session, error) {
ctx := context.TODO()
store := NewStore[Session](&m, "sessions")
return store.GetOne(ctx, &bson.D{{Key: "token", Value: token}})
}
func (m MongodbStorage) GetUserSessions(user *User) ([]*Session, error) {
ctx := context.TODO()
store := NewStore[Session](&m, "sessions")
return store.GetMany(ctx, &bson.D{{Key: "userid", Value: user.Id}})
}
func (m MongodbStorage) DeleteSession(id primitive.ObjectID) error {
ctx := context.TODO()
store := NewStore[Session](&m, "sessions")
return store.DeleteByID(ctx, id)
}
func (m MongodbStorage) CreateBookmark(bookmark *Bookmark) (primitive.ObjectID, error) {
ctx := context.TODO()
store := NewStore[Bookmark](&m, "bookmarks")
return store.InsertOne(ctx, bookmark)
}
func (m MongodbStorage) GetBookmarkByID(id primitive.ObjectID) (*Bookmark, error) {
ctx := context.TODO()
store := NewStore[Bookmark](&m, "bookmarks")
return store.GetById(ctx, id)
}
func (m MongodbStorage) GetBookmark(filter *bson.D) (*Bookmark, error) {
ctx := context.TODO()
store := NewStore[Bookmark](&m, "bookmarks")
return store.GetOne(ctx, filter)
}
func (m MongodbStorage) GetBookmarks(filter *bson.D) ([]*Bookmark, error) {
ctx := context.TODO()
store := NewStore[Bookmark](&m, "bookmarks")
return store.GetMany(ctx, filter)
}
func (m MongodbStorage) GetUserBookmarks(user *User, filter *bson.D) ([]*Bookmark, error) {
passedFilter := getFilter(filter)
f := bson.D{{Key: "userid", Value: user.Id}}
f = append(f, passedFilter...)
ctx := context.TODO()
store := NewStore[Bookmark](&m, "bookmarks")
return store.GetMany(ctx, &f)
}
func (m MongodbStorage) Collection(col string) *mongo.Collection {
return m.Db.Database("nash").Collection(col)
}

29
storage/storage.go Normal file
View File

@ -0,0 +1,29 @@
package storage
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type Storage interface {
// Users
CreateUser(*User) (primitive.ObjectID, error)
GetUser(*bson.D) (*User, error)
GetUsers(*bson.D) ([]*User, error)
GetUserByID(primitive.ObjectID) (*User, error)
UpdateUser(*User) error
DeleteUser(primitive.ObjectID) error
// Sessions
CreateSession(*Session) (primitive.ObjectID, error)
GetSessionByToken(string) (*Session, error)
GetUserSessions(*User) ([]*Session, error)
DeleteSession(primitive.ObjectID) error
// Bookmarks
CreateBookmark(*Bookmark) (primitive.ObjectID, error)
GetBookmarkByID(primitive.ObjectID) (*Bookmark, error)
GetBookmark(*bson.D) (*Bookmark, error)
GetBookmarks(*bson.D) ([]*Bookmark, error)
GetUserBookmarks(*User, *bson.D) ([]*Bookmark, error)
}

67
storage/types.go Normal file
View File

@ -0,0 +1,67 @@
package storage
import (
"crypto/rand"
"encoding/hex"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type User struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Username string
Password []byte `json:"-"`
IsAdmin bool
LastLogin time.Time
}
type Session struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Token string `json:"-"`
UserID primitive.ObjectID
IP string
LoggedAt time.Time
ExpiresAt time.Time
IsAdmin bool
}
type ApiKey struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
UserID primitive.ObjectID
Key string
}
type Folder struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Name string
ParentID primitive.ObjectID
Icon []byte
}
type Bookmark struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Name string
Url string
UserID primitive.ObjectID
FolderID primitive.ObjectID
Tags []string
// Icon []byte
Created time.Time
}
type Note struct {
Id primitive.ObjectID `bson:"_id" json:"id,omitempty"`
Name string
Tags []string
Content string
Created time.Time
}
func GenSessionToken() string {
b := make([]byte, 128)
if _, err := rand.Read(b); err != nil {
return ""
}
return hex.EncodeToString(b)
}