aboutsummaryrefslogtreecommitdiffstats
path: root/pysite/mixins.py
blob: 930a7eb7d4ecdbf357435b07ffd15b90ef427033 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# coding=utf-8
from _weakref import ref

from flask import Blueprint

from rethinkdb.ast import Table

from pysite.database import RethinkDB


class DBMixin():
    """
    Mixin for classes that make use of RethinkDB. It can automatically create a table with the specified primary
    key using the attributes set at class-level.

    This class is intended to be mixed in alongside one of the other view classes. For example:

    >>> class MyView(APIView, DBMixin):
    ...     name = "my_view"  # Flask internal name for this route
    ...     path = "/my_view"  # Actual URL path to reach this route
    ...     table_name = "my_table"  # Name of the table to create
    ...     table_primary_key = "username"  # Primary key to set for this table

    This class will also work with Websockets:

    >>> class MyWebsocket(WS, DBMixin):
    ...     name = "my_websocket"
    ...     path = "/my_websocket"
    ...     table_name = "my_table"
    ...     table_primary_key = "username"

    You may omit `table_primary_key` and it will be defaulted to RethinkDB's default column - "id".
    """

    table_name = ""  # type: str
    table_primary_key = "id"  # type: str

    @classmethod
    def setup(cls: "DBMixin", manager: "pysite.route_manager.RouteManager", blueprint: Blueprint):
        """
        Set up the view by creating the table specified by the class attributes - this will also deal with multiple
        inheritance by calling `super().setup()` as appropriate.

        :param manager: Instance of the current RouteManager (used to get a handle for the database object)
        :param blueprint: Current Flask blueprint
        """

        if hasattr(super(), "setup"):
            super().setup(manager, blueprint)  # pragma: no cover

        if not cls.table_name:
            raise RuntimeError("Routes using DBViewMixin must define `table_name`")

        cls._db = ref(manager.db)
        manager.db.create_table(cls.table_name, primary_key=cls.table_primary_key)

    @property
    def table(self) -> Table:
        return self.db.query(self.table_name)

    @property
    def db(self) -> RethinkDB:
        return self._db()