libkosokoso/Readme.rst

111 lines
3.0 KiB
ReStructuredText

Libkosokoso -- simple tagging with sqlalchemy.
==============================================
Libkosokoso provides compact and table-stingy tags for
sqlalchemy-backed objects.
Usage
-----
::
import libkosokoso as kk
import sqlalchemy as sa
base = sa.orm.declarative_base()
kk.__dict__.update(kk.init_base(base))
class Foo(kk.Taggable, base):
__tablename__ = 'foos'
a = Foo()
a.tags.append('tag1')
a.tags.extend(['tag2', 'tag3'])
and so forth. (Note that certain key steps, like connecting to a
database, are omitted.)
The code above will generate tables like this::
foos:
db_id
1
kk_tag_associations:
db_id tag_id target_table target_id
1 1 foos 1
2 2 foos 1
3 3 foos 1
kk_tags:
db_id text
1 tag1
2 tag2
3 tag3
To access the tags::
for i in a.tags:
print(i)
tag1
tag2
tag3
The tags member gives you a list of tag strings. To access the tag
objects, iterate the kk_tag_associations member::
return [ta.tag_obj for ta in a.kk_tag_associations]
This will bypass the association proxy and return a list of Tag
objects. The tag object has a useful member, "collection", which
provides direct access to the objects with this tag.
It's also possible to add kk.Tag objects directly to the tags
property on a taggable object, and they'll be handled correctly.
Similarly, it's possible to add objects to the collections member of a
Tag object.
Design considerations
---------------------
My basic reasoning was that at some point I'd have to go and muck
about in the database by hand, and I wanted a structure that was easy
to perceive and modify.
I also wanted to avoid modifying preexisting tables. This structure
can be dropped into a live system without interfering with any current
entities. (Likewise the reverse.)
At all times I aimed to have an interface that matches my intuitions.
Hence things like being able to both add tags to an object and add
objects to a tag, despite the massive increase in complexity for
arguably minimal gain.
I explicitly did not aim for efficiency. The underlying code is
object-happy and probably very inefficient.
Implementation notes
--------------------
The init_base() call required to set up the library is an absolute
mess. I'm pleased that I got it working, but kind of surprised.
The authors of SQLAlchemy would most likely be appalled. This model
breaks the "relational" element of the database quite badly. One
solution that might make everyone happy would be to add a tags table
for every current type, and use a view to consolidate them if desired.
Why is it called that?
----------------------
"kosokoso" is Japanese onomatopoeia for sneaking or whispering
secretly. I picked the name because tags always feel like a kind of
buzzing side channel to me.
(I also sometimes call it "guzuguzu", which is, like, slow. This took
me way longer to write than I was expecting.)