solvent

package
v0.0.0-...-9ea5714 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 15, 2024 License: BSD-3-Clause Imports: 13 Imported by: 0

README

Solvent

A minimalistic CRDT-based To-Do list.

Introduction

The CRDTs (Conflictfree-Replicated-Data-Types) representing the to-do list have to cover three basic operations:

  • Adding / removing items
  • Checking / unchecking items
  • Re-ordering items
Adding / Removing

Can be represented with a 2P-Set consisting of two G-Sets (append only sets). One tracking all the added items (called liveSet) and another one tracking all the removed items (called tombstoneSet).

An item is visible if it is contained in the liveSet set and not in the tombstoneSet.

Renaming of items is treated as deleting the old item and creating a new one with the changed name.

Checking / Unchecking

The items themself hold the current checked state as simple boolean flag. Items can only be checked but not unchecked on their own. Unchecking will be modeled as an item deletion followed by creating a new and unchecked item with the same title.

Re-Ordering

Each item will be assigned an ordering value representing its order in the to-do list. When an item gets moved the new order value will be the the average of the two adjacent items. For the last position the order value will be the order value of the second to last item plus 10.

Getting Started

To run Solvent locally make sure you have Go, NPM and Docker-Compose installed your system.

git clone https://github.com/eldelto/solvent.git

cd solvent

// Setup a local PostgreSQL DB
docker-compose up

// Launch backend server
go run web/main.go

// Launch frontend client
cd react-client
npm install
npm start

// Build Docker image
./docker_build.sh

To-Do

  • Frontend rework
  • Mark lists as done when all items are checked
  • Properly handle errors in controllers
  • Implement user handling
  • Implement list removal
  • Use Websockets instead of polling
  • Fix potential DB race condition on update
  • Register a service worker to cache data on reloads
  • Send delta in update request / response instead of the everything
  • Implement search functionality

Screens

List View

Detail View

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type NotFoundError

type NotFoundError struct {
	ID uuid.UUID
	// contains filtered or unexported fields
}

NotFoundError indicates that a ToDoListItem with the given ID does not exist

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type Notebook

type Notebook struct {
	ID        uuid.UUID
	ToDoLists crdt.PSet[*ToDoList]
	CreatedAt int64
}

func NewNotebook

func NewNotebook() (*Notebook, error)

func (*Notebook) AddList

func (n *Notebook) AddList(title string) (*ToDoList, error)

func (*Notebook) GetCompletedLists

func (n *Notebook) GetCompletedLists() []*ToDoList

func (*Notebook) GetList

func (n *Notebook) GetList(id uuid.UUID) (*ToDoList, error)

func (*Notebook) GetLists

func (n *Notebook) GetLists() []*ToDoList

func (*Notebook) GetOpenLists

func (n *Notebook) GetOpenLists() []*ToDoList

func (*Notebook) Identifier

func (n *Notebook) Identifier() string

func (*Notebook) Merge

func (n *Notebook) Merge(other crdt.Mergeable) (crdt.Mergeable, error)

func (*Notebook) RemoveList

func (n *Notebook) RemoveList(id uuid.UUID)

type OrderValue

type OrderValue struct {
	Value     float64
	UpdatedAt int64
}

OrderValue represents an ordering value with its correspondent update timestamp

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(db *bbolt.DB) (*Service, error)

func (*Service) ApplyListPatch

func (s *Service) ApplyListPatch(userID, listID uuid.UUID, patch string) (*Notebook, error)

func (*Service) CheckItem

func (s *Service) CheckItem(userID, listID, itemID uuid.UUID) (*ToDoList, error)

func (*Service) Create

func (s *Service) Create(userID uuid.UUID) (*Notebook, error)

func (*Service) CreateList

func (s *Service) CreateList(userID uuid.UUID) (*ToDoList, error)

func (*Service) Fetch

func (s *Service) Fetch(userID uuid.UUID) (*Notebook, error)

func (*Service) Remove

func (s *Service) Remove(id uuid.UUID) error

func (*Service) UncheckItem

func (s *Service) UncheckItem(userID, listID, itemID uuid.UUID) (*ToDoList, error)

func (*Service) Update

func (s *Service) Update(userID uuid.UUID, notebook *Notebook) (*Notebook, error)

type Title

type Title struct {
	Value     string
	UpdatedAt int64
}

Title represents a title value with its correspondent update timestamp

type ToDoItem

type ToDoItem struct {
	ID         uuid.UUID
	Title      string
	Checked    bool
	OrderValue OrderValue
}

ToDoItem representa a single task that needs to be done

func (*ToDoItem) Identifier

func (t *ToDoItem) Identifier() string

Identifier returns the ID of the ToDoItem

func (*ToDoItem) Merge

func (t *ToDoItem) Merge(other crdt.Mergeable) (crdt.Mergeable, error)

Merge combines the current ToDoItem with the one passed in as parameter or returns a CannotBeMerged error if the ToDoItems cannot be merged (e.g. they have different IDs)

func (*ToDoItem) String

func (t *ToDoItem) String() string

type ToDoList

type ToDoList struct {
	ID        uuid.UUID
	Title     Title
	ToDoItems crdt.PSet[*ToDoItem]
	CreatedAt int64
}

ToDoList represents a whole list of ToDoItems

func (*ToDoList) AddItem

func (tdl *ToDoList) AddItem(title string) (uuid.UUID, error)

AddItem creates a new ToDoItem object and adds it to the ToDoList it is called on

func (*ToDoList) CheckItem

func (tdl *ToDoList) CheckItem(id uuid.UUID) (uuid.UUID, error)

CheckItem checks the ToDoItem with the given id or returns a NotFoundError if no match could be found

func (*ToDoList) GetItem

func (tdl *ToDoList) GetItem(id uuid.UUID) (ToDoItem, error)

GetItem returns the ToDoItem matching the given id or returns a NotFoundError if no match could be found

func (*ToDoList) GetItems

func (tdl *ToDoList) GetItems() []ToDoItem

GetItems returns a slice with all ToDoItems that are in the liveSet but not in the tombstoneSet and are therefore considered active

func (*ToDoList) GetOrderedItems

func (tdl *ToDoList) GetOrderedItems(doneToBottom bool) []ToDoItem

func (*ToDoList) Identifier

func (tdl *ToDoList) Identifier() string

Identifier returns the ID of the ToDoList

func (*ToDoList) IsCompleted

func (tdl *ToDoList) IsCompleted() bool

func (*ToDoList) Merge

func (tdl *ToDoList) Merge(other crdt.Mergeable) (crdt.Mergeable, error)

Merge combines the current ToDoList with the one passed in as parameter or returns a CannotBeMerged error if the ToDoLists or their ToDoListItems cannot be merged (e.g. they have different IDs)

func (*ToDoList) MoveItem

func (tdl *ToDoList) MoveItem(id uuid.UUID, targetIndex int) error

MoveItem moves the ToDoItem with the given id to the targeted index or returns a NotFoundError if no match could be found

func (*ToDoList) RemoveItem

func (tdl *ToDoList) RemoveItem(id uuid.UUID)

RemoveItem removes the ToDoItem with the given id from the ToDoList but won't return an error if no match could be found as it is the desired state

func (*ToDoList) Rename

func (tdl *ToDoList) Rename(title string)

Rename sets the title of the ToDoList to the given one and updates the UpdatedAt field TODO: Use types for ToDoListID and ToDoItemID

func (*ToDoList) String

func (tdl *ToDoList) String() string

func (*ToDoList) UncheckItem

func (tdl *ToDoList) UncheckItem(id uuid.UUID) (uuid.UUID, error)

UncheckItem unchecks the ToDoItem with the given id by creating a new ToDoItem object with the same attributes or returns a NotfoundError if no match could be found

type UnknownError

type UnknownError struct {
	// contains filtered or unexported fields
}

UnknownError indicates an unhandled error from another library that gets wrapped

func (*UnknownError) Error

func (e *UnknownError) Error() string

func (*UnknownError) Unwrap

func (e *UnknownError) Unwrap() error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL