Storage for Knowledge Bases
Today's update is brought to you by my lack of motivation ๐. I decided to work on building out a storage layer for Knowledge Bases objects, and then got burned by lack of interest.
Restating our storage requirements: we need notes, todos, etc to be persisted to disk in a way where git's diff will capably show edits, additions, and deletions, and which allows for easily querying these objects by identifier or by their relation to each other (we want to support parent-child, related-to, etc). To meet those requirements I intend to persist data in two ways. First, in an appropriately-sorted JSON or YAML file, to solve for the git-diff requirement. Second, in a SQLite database to make it easy to add/edit/delete/query. The program will mirror the SQLite database onto the JSON file unless it's determined to be out of date (i.e. when the git branch is changed), in which case we'll rebuild the database from the JSON file. For now I'm starting with the SQLite db, as that can be useful for purely local todo storage, and we'll bolt-on the ability to synchronize them over git later.
Anyway, today's changes are a little messy because I got the basic shape of storage repositories interacting with OCaml's SQLite3 bindings (having opted not to bring in an ORM), but with a lot of extraneous lines that can probably be simplified or extracted into helper functions (you quickly see why people invented ORMs when interacting with db connections at a low level). But every time I came back to do the clean up I lost all motivation. I've found that this pattern really kills forward momentum for me โ my desire for perfection interferes with the mental rewards of having something of the final product. The only way through that I know is to declare bankruptcy โ so I committed what I had in order to move on.
Repositories
The intended usage of these repositories is to instantiate a value of the Root repository, which will share database connections amongst the other repositories, and to access the specific repository via the root. A Repository.Sqlite helper exists to raise the abstraction level of SQLite interactions, wrapping errors and automatically handling statements.
Pre-Push Hook
I'm not a fan of most git pre-commit hooks because they seek to block committing on some coding or formatting standard, removing the ability to commit and amend commits in pieces. However, I like the guardrail of ensuring the code compiles and the tests pass before pushing the commit elsewhere, and thus the scripts/install-pre-push-hook.sh was born.
Unhappiness
1. Data modeling. I cut a corner, using "inheritance" instead of composition, and now I'm sad. I didn't attempt a Repository.Todo because Todo contains a Note instead of pulling all its attributes up into Todo. The TypeId for a Todo can be (and probably should be) different from a Note by using a different prefix, like proj_todo_XXXXXX and proj_note_XXXXXX, but this isn't clean because Todo is "reusing" Note's TypeId.
2. Clunky SQL interaction. I extracted helper functions into Repository.Sqlite, but the code in the repositories still feels too clunky and too duplicated.
Next steps: I'm just going to leave these problems for a future me who's more motivated to fix them. Getting the end-to-end functionality working for notes should make it more fulfilling to work out the issues with Todo. The SQL may be made better when revisiting it for the Todo repository, or may just stay as clunky as it is. Sometimes you draw a box around code that works and it's fine that it's ugly because you're not going to go back in there any time soon.