diff --git a/README.rst b/README.rst index b742336..b562d13 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,8 @@ .. _header: -************************ +************* calibrestekje -************************ +************* .. image:: https://img.shields.io/badge/license-GPL-brightgreen.svg :target: LICENSE @@ -26,9 +26,32 @@ calibrestekje .. _introduction: -Calibre database bindings for prototyping your own library software! +Library prototyping based on Calibre ------------------------------------ +Calibrestekje is a Python library which provides a way to work with the +`Calibre`_ metadata database outside the context of the Calibre desktop and web +interfaces. A set of generated `SQLAlchemy`_ bindings (see `sqlacodegen`_ for +more) are provided which allow for the querying of an existing Calibre metadata +database (a file typically called ``metadata.db``). These bindings are more +fine grained than Calibres `database interface`_ and provide access to the +Database table layer. + +The idea of a "stekje" (Dutch word meaning "little graft") in the context of +software came out of the discussions at `Relearn`_ around cutting, grafting, +remixing, re-using and misusing software for collective work. + +This stekje can be understood as a low level building block for experimenting +with new ways of doing library software. One exciting part about a stekje is +that it is possible that new roots will appear. It is hoped that Calibrestekje +may help new library software take root. + +.. _Calibre: https://calibre-ebook.com/ +.. _SQLALchemy: https://docs.sqlalchemy.org/ +.. _sqlacodegen: https://github.com/agronholm/sqlacodegen +.. _database interface: https://manual.calibre-ebook.com/db_api.html +.. _Relearn: http://relearn.be/2019/ + .. _example: Example @@ -36,7 +59,17 @@ Example .. code-block:: python - # TODO + from calibrestekje import Book, Publisher, init_session + + session = init_session("sqlite:///mymetadata.db") + + publisher = (session.query(Publisher) + .filter(Publisher.name == "MIT Press").one()) + + books = (session.query(Book) + .filter(Book.publishers.contains(publisher))) + + print(f"Books published by MIT Press: {books.count()}") .. _documentation: diff --git a/docs/source/conf.py b/docs/source/conf.py index 2aa1175..a97626f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,4 +5,4 @@ html_theme = 'sphinx_rtd_theme' master_doc = 'index' project = 'calibrestekje' templates_path = ['_templates'] -extensions = ['sphinx.ext.autodoc', 'sphinx_autodoc_typehints'] +extensions = ['sphinx.ext.autodoc'] diff --git a/docs/source/examples.rst b/docs/source/examples.rst new file mode 100644 index 0000000..87e6534 --- /dev/null +++ b/docs/source/examples.rst @@ -0,0 +1,89 @@ +.. _examples: + +******** +Examples +******** + +In order to work with Calibrestkje, you'll need to learn more about +`SQLAlchemy`_. SQLAlchemy is a Python "Object Relational Mapper", meaning that +it can help you write Python programs that interact with a database without +having to write raw database queries (that is often harder to do correctly). +The `querying`_ documentation is particularly useful. The following examples +are laid out in a "cookbook" style. Hopefully there is something useful in here +for you. + +.. _SQLAlchemy: https://docs.sqlalchemy.org/en/13/ +.. _querying: https://docs.sqlalchemy.org/en/13/orm/tutorial.html#querying + +Working with the Calibre database +--------------------------------- + +Calibrestkje works with the Calibre metadata database. This means, you need to +install `Calibre`_ first on your system. On my Debian operating system , that +means I would run: + +.. _Calibre: https://calibre-ebook.com + +.. code-block:: bash + + $ sudo apt install -y calibre + +And the first time I run Calibre, I would find that a metadata database has +been created in the ``/home/myuser/calibre/`` folder with the name +``metadata.db``. If you've been using Calibre for some time already, then +you'll probably already have this folder and database. + +Sometimes it is useful to start from an empty metadata database and this can be +achieved by creating one with the ``calibredb`` command on the command-line. An +example of this would be: + +.. code-block:: bash + + $ mkdir mytestcalibredb + $ calibredb restore_database --really-do-it --with-library mytestcalibredb + +Unfortunately, there is no "create new database command" (AFAIK) and therefore +it is required to run this magical incantation that is hard to remember. +Afterwards, you'll have a new ``mytestcalibredb/metadata.db`` file which you +can start to work with. + +Please see the :ref:`limitations` documentation for understanding what +Calibrestekje can't do right now. + +Initialising a new session +-------------------------- + +.. code-block:: python + + from calibrestkje import init_session + + sqlite_url = "sqlite:///path_to_my_calibre_metadata.db" + session = init_session(sqlite_url) + +All books without a publisher +----------------------------- + +.. code-block:: python + + (session.query(Book) + .filter(Book.publishers == None)) + +All books with multiple authors +------------------------------- + +.. code-block:: python + + from sqlalchemy.sql.expression import func + + (session.query(Book) + .join(Book.authors) + .group_by(Book) + .having(func.count(Author.id) > 1)) + +List of all tags that contain some pattern +------------------------------------------ + +.. code-block:: python + + (session.query(Tag) + .filter(Tag.name.contains("humanities"))) diff --git a/docs/source/forking.rst b/docs/source/forking.rst new file mode 100644 index 0000000..7534eac --- /dev/null +++ b/docs/source/forking.rst @@ -0,0 +1,40 @@ +.. _forking: + +******* +Forking +******* + +If you're not interested in maintaining compatibility with Calibre and would +like to embark on a new experimental library but do not want to have to +re-invent the database schema, you can get Calibrestekje to output +`SQLAlchemy`_ schemas definition based on Calibre but ones which you can change +yourself. This makes it possible to add new columns and tables to your new +database. + +.. _SQLALchemy: https://docs.sqlalchemy.org/ + +To get started, you would run the following command. + +.. code-block:: bash + + $ calibrestekje generate > mynewdb.py + +From there, you can tell SQLAlchemy to create a new Sqlite database based on +this schema. + +.. code-block:: python + + from mynewdb import Base + from sqlalchemy import create_engine + + engine = create_engine('sqlite:///mynewdb.db') + + Base.metadata.create_all(engine) + +It is then possible to investigate your new database with `sqlitebrowser`_. + +.. _sqlitebrowser: https://sqlitebrowser.org/ + +.. code-block:: bash + + sqlitebrowser mynewdb.db diff --git a/docs/source/index.rst b/docs/source/index.rst index 3ae4cc1..50e79e9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,6 +6,9 @@ :hidden: install + examples + forking + limitations upgrade contribute changelog diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst new file mode 100644 index 0000000..82da90f --- /dev/null +++ b/docs/source/limitations.rst @@ -0,0 +1,18 @@ +.. _limitations: + +*********** +Limitations +*********** + +* Only read-only access to the ``metadata.db`` is available file right now. + There is some more technical work that needs wrangling before it becomes + possible to programmatically write new entries to a ``metadata.db`` that is + managed by Calibre. + +* It is not possible to extend the Calibre database schema from within the + context of Calibrestekje right now. This means you can't easily add a new + column to the Book table. It is however possible to "fork" the Calibre + database schema and make your own. This involves more work and it is not + clear if it is possible to stay compatible with the Calibre database schema + afterwards. This might be useful if you want to start from scratch but not + re-invent the database schema. See the :ref:`forking` documentation for more.