If the project uses numerical IDs, and processes user input from a web
request URL where everything is a string, it is tedious to convert
between str and int on the application side. If done improperly, it
messes up the cache because the int id and str id will be entered
separately. So we let the database handle the id type and raise errors
if necessary.
- Store separate states for different url and param permutations.
- Add the etag_function which allows you to decide not to run the
function in the first place, instead of running it and seeing
that its return value matches the previous value.
This reduces the number of frivolous sql queries we make, since
the index contians all the tables anyway. The side effect is that
the function won't acknowledge tables created during the run time,
which I kind of think is a good thing since it reduces accident
surface area to the tables outlined by the programmer during init.
This helps ensure that the keys of the cache are the true and correct
data type and not just whatever the user provided. SQLite coerces
strings and ints.
Instead of handwriting the help text, which was time consuming and
prone to errors, I'm finally using the help parameter in
parser.add_argument. betterhelp will render and colorize this for
some good-looking automatic help text.
The make_helptext function is still extremely long and would be nice
to refactor, but I've been sitting on this commit for a few weeks now
and I want to get my git repositories back in sync.
Formerly I was normalizing backslash to forwardslash on unix, which is
bad. Then I removed the function because I thought normpath was the
right tool for the job. Now I'm finding a few situations I just want to
norm the sep again.
In spinal.walk sorting is optional because there I prioritize
configurability and speed, but for pathclass.walk I think it
makes sense to prioritize comfort and just-works results.
I was inspired by the idea of "making impossible states impossible"
and using a data model that accurately represents what we intend for
it to represent. Instead of storing the path as a string where "it's
a string but actually you're supposed to know that the parts between
os.seps are different parts and the first one is special and...", we
can use a data model that directly says that. Storing the path as a
tuple of (Drive, Part, Part) helps me focus on the semantics of the
Path as a collection of parts joined by the os.sep.
Furthermore, storing the path as a string made some operations slow.
Every time we call one of the os.path functions with a string, it
has to do a lot of normalization and edge-case handling even when we
know it wouldn't be needed. By storing the path as a tuple, we can
instantly get the drive name, parent dir name, and basename without
asking os.path to split it for us every single time. It also makes
relative path / common ancestor checks a lot easier to understand.
Fewer operations need to go into the slow functions.