summaryrefslogtreecommitdiff
path: root/model
AgeCommit message (Collapse)Author
2024-05-07model: Init database with database pathxengineering
2024-05-06model: Do not write version.txt inside storagexengineering
The intention of this file was that a Ceres executable could compare its version with the version of the storage folder. If the versions match the storage folder could be directly used. If the storage version is lower the executable can apply migrations to the storage folder until the versions match. The problem is that executing migrations inside the database and updating the version.txt cannot be atomic. In contrast the version string could be saved inside the database itself in a metadata table. In that case the migration together with the update of the version string can be executed inside one database transaction which guarantees atomicity. The problem could still be that migrations should be applied also to the files and folders inside the storage folder. This problem can only be avoided by not using files to store data and instead use the BLOB datatype if necessary. Even in case of a future filesystem use it is still better to have the guarantee that the database with file paths and metadata and the there included version string are in sync.
2024-05-06model: Introduce NewStorage() functionxengineering
It is a common pattern inside the Go standard library to provide a constructor with this naming scheme to custom types of the package. Doing this here results in a style closer to the standard library which improves readability.
2024-05-04Move storage path logging to main() functionxengineering
The model package where this used to be implemented should not care too much about logging. Furthermore it is easier to compare the log output with the main() function if the log statements are there.
2024-05-04model: Add storage.Exists() and storage.Create()xengineering
These new methods provide essential functionality related to the storage folder.
2024-05-04model: Introduce type Storagexengineering
This new type definition will make it easier to handle the storage directory of Ceres and related functionality which can be implemented with methods.
2024-05-01Do not remove storage folderxengineering
This is not useful in production. Furthermore in the debug use case the default storage path is now ./storage which can easily be removed by `rm -rf storage`. This also allows to not remove the storage folder for further analysis of the storage folder.
2024-05-01Use default storage path instead of temp dirxengineering
2024-05-01model: Add version.txt file to storage folderxengineering
This prepares the ability to check for compatibility between a Ceres executable build and an existing storage folder.
2024-04-07model: Add helper function for safe CRUDxengineering
This removes the redundant setup of a database/sql.Tx in each HTTP handler.
2024-04-07model: Add model.Object interfacexengineering
This interface will allow to implement generic functions based on the Object interface which covers the four CRUD methods create, read, update and delete. This should be possible for every object handled by the server.
2024-04-06model: CRUD methods only for targeted objectsxengineering
A create, read, update or delete (CRUD) method should only care about the object which provides the receiver and the relations to its child objects. For example the method func (r *Recipe) Create(tx *sql.Tx) error {} should only create the relational data inside the database for the recipe, not for the steps nested into this Recipe struct. This should be covered by the func (s *Step) Create(tx *sql.Tx) error {} method which is then called by `func (r *Recipe) Create()`. This has the advantage that every CRUD method has a constraint scope and is more unified since the Step CRUD methods now have a Step struct as receiver instead of a Recipe receiver.
2024-04-06model: Always pass *sql.Tx to CRUD methodsxengineering
When nesting objects like steps into other objects like recipes it is required to pass a *sql.Tx value to the CRUD methods of the inner object to be able to roll back the whole transaction. The top level object used to be responsible for the creation of this *sql.Tx inside its CRUD methods. This is now moved to the caller of the CRUD methods (here the HTTP handler function). The advantage is that all CRUD methods now accept a *sql.Tx as only argument which makes those methods more consistent.
2024-03-24model: Add recipe stepsxengineering
This provides the infrastructure to create views and HTTP handlers to provide recipe steps.
2024-03-24model: Crash on failed test recipe injectionxengineering
This error used to be silent. Since it is just about test recipes and thus a debugging environment it is best to directly give up and log the error.
2024-03-12model: Remove .Touch() methodxengineering
The model package should never modify the data. Thus the functionality to update timestamps is moved to the controller package which is intended to modify data.
2024-03-05model: Move timestamp updates to controllerxengineering
The model package should handle the object relational mapping (ORM). This requires implementing the four CRUD methods: - create - read - update - delete On create and update the model package used to modify the timestamps like `last_changed`. This was detected by the unit tests which tested that the data is not changed in a create / read cycle or is updated correctly in an update / read cycle. This raised the question if it is a good idea that the model package is "smart" and updates timestamps. To keep the model package and the included unit tests simple the new design enforces that the complete data - including metadata - is always exactly the same after using any CRUD methods. The functionality of updating the timestamp is moved to the HTTP handler inside the controller package. This also matches the definition of the controller package as the part of the code which is alone responsible to actually change the data. This commit finally fixes the unit test suite.
2024-03-04model: Implement Stringer interface for Recipexengineering
This allows to print a recipe with a fmt.Printf() call more easily: fmt.Printf("%s\n", recipe) This is also used for better error output in unit tests with t.Fatalf(). The Stringer interface is implemented with the JSON package because an indented version of a recipe is a useful string representation.
2024-03-04model: Create test data with Go instead of SQLxengineering
This allows to formulate the test data with an object-based model which is easier than writing it down in a relational model.
2024-03-03controller: Update recipe based on JSONxengineering
2024-03-03model: Assert one affected row on .Update()xengineering
A missing or wrong .Id field for example otherwise results in a silent error because nothing is actually updated.
2024-03-03model: Use only string types for modelsxengineering
When a HTML form is converted to JSON by JavaScript using `FormData()`, `Object.fromEntries()` and `JSON.stringify` the data type is always `string`. This does not match the Go struct definitions using multiple types including e.g. `int`. There are several options to solve this conflict: 1. use only strings in Go struct definitions 2. write custom functions to parse string-based JSONs to Go structs 3. implement custom functions in JS to use `number` type if possible Option 3 seems to be a very clean solution. Nevertheless it is limited by the fact that JSON anyway has a way more limited type system than Go. So the types used in Go cannot be used and this would reduce this option to a variant of option 2. Option 2 requires significant effort per struct inside the model package. Every object which is transferred via JSON and serialized into Go structs would require a second struct definition with string types and a conversion function. This does not scale. Thus option 1 seems to be the best fit. The reasons for using types like `int` or `bool` are: - less memory consumption than `string` in most cases - implicit data validation (e.g. enforcing positive numbers with `uint`) - better compatibility with certain APIs which rely on e.g. `int` The first argument is not so relevant in this use case. The amount of required memory is still quite small for servers. Implicit data validation is a good thing but not enough. There should anyway be validation method which has to be called on CRUD methods and JSON deserialization.
2024-02-11model: Add type 'Recipes' with Read() methodxengineering
This type is provided to render overview pages easily with a list of all recipes.
2024-02-11model: Implement CRUD methods for type Recipexengineering
The new Go type 'Recipe' should contain every information directly related to a recipe. It should be sufficient to pass it to a template to directly render a HTML view or edit page for the recipe or to a template to generate a PDF. The CRUD methods are: - func (r *Recipe) Create() error - func (r *Recipe) Update() error - func (r *Recipe) Read() error - func (r *Recipe) Delete() error Together with the type itself they are the interface the model package provides for recipes.
2024-02-11model: Switch to very basic database schemaxengineering
This simple model is used to test if it is helpful to implement the four CRUD methods create, read, update and delete all inside the model package. The model package should also provide the datastructures for these operations (well suited for the required views) aswell as tests for them. With this approach it should be possible to easily implement the view and controller package because most of the logic is already inside the model package and is tested.
2023-12-27model: Inject test data into databasexengineering
This is useful for debugging and testing.
2023-12-27model: Add initial SQL migrationxengineering
This provides the basic table structure to the database.
2023-12-27model: Implement database connectionxengineering
The already implemented storage folder should contain a sqlite database to store most parts of the Ceres user data.
2023-12-27model: Implement temporary storage directoryxengineering
This temporary directory is provided to store the user data for the Ceres recipe server during development and testing.