haydnv / tinychain

A next-gen database + SaaS framework for rapid development and integration of enterprise services

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update documentation to match the new `App` and `Model` classes

haydnv opened this issue · comments

These pages:

Have been badly out-of-date since Cluster was replaced by App. We should update them based on the App and Model examples in the tests/apps directory.

Hey @haydnv , I may need access to your gitbooks.for the time being if you could review the docs i'll add them to the comments.

Chain: persistent mutable state.

In order to serve a dynamic application, you’ll have to have a way of updating your service’s persistent state. To do this you can use a Chain, a data structure which keeps track of mutations to a Collection in order to maintain the consistency of that State across every replica of an
app.

class Persistent(tc.app.App):
    __uri__ = tc.URI("http://127.0.0.1:8702/test/chain")

    def _configure(self):
        self.rev = tc.Chain.Sync(0)
        tc.app.App.__init__(self)

    # this method looks up the value of "rev" within a transaction
    @tc.get
    def version(self) -> tc.Number:
        return self.rev

    # this method updates the value of "rev" within a transaction
    @tc.post
    def bump(self, txn):
        # note: the value of "version()" must be assigned a name
        # in order to be addressable by the instance method __add__ below
        txn.rev = self.version()
        return self.rev.set(txn.rev + 1)

When you start a TinyChain host with an App definition, it will assume that there is a hosted app with the given URI (”http://…/app/test/chain” in the example above) and attempt to join that App as a replica.
If the app URI has no host address, or is the same as the address of the running host, the host will serve a single replica of a new app.

Watch out for versioning issues! In production, it’s best to end your app URI with a version number which you can update in order to release a new, non-backwards-compatible version with different data and methods. We are attempting to find a solution to this and will be released at a future time.

Object orentation

One of TinyChain’s most powerful features is its object-oriented API.
You can use this to define your own classes, which must inherit from exactly one class, which ultimately inherits from a native class.

For example:

import tinychain as tc

URI = tc.URI("http://example.com/app/area") # <-- edit this

# Specifying `metaclass=tc.Meta` provides JSON encoding functionality for user-defined classes.
# It's only required when subclassing a native class -- subclasses of `Distance` automatically inherit its metaclass.


class Distance(tc.Number, metaclass=tc.Meta):
    __uri__ = URI.append("Distance")

    @tc.get
    def to_feet(self) -> Feet:
        return tc.error.NotImplemented("abstract")

    @tc.get
    def to_meters(self) -> Meters:
        return tc.error.NotImplemented("abstract")


class Feet(Distance):
    __uri__ = URI.append("Feet")

    @tc.get
    def to_feet(self) -> Feet:
        return self

    @tc.get
    def to_meters(self) -> Meters:
        return self / 3.28


class Meters(Distance):
    __uri__ = URI.append("Meters")

    @tc.get
    def to_feet(self) -> Feet:
        return self * 3.28

    @tc.get
    def to_meters(self) -> Meters:
        return self

TinyChain does not have any concept of member visibility, like a “public” or “private” method.
This is because TinyChain objects are meant to be sent over the network and used by client code, making a “private” method is meaningless (and deceptive to the developer implementing it).
If you want to hide an implementation detail from the public API of your class, consider using a helper function outside your class definition.

host your service

Now that we've defined some classes in and a Chain in ...(link to chain docs), it's time to put our service online! You can do this using the same object-oriented API that you used to build the service. For security reasons, TinyChain requires that you load your Cluster configuration from a local file on the host machine; see the next section, for instructions.

from __future__ import annotations
import tinychain as tc 

URI = tc.URI("http://127.0.0.1:8702/demo")


class User(tc.app.Model):
    __uri__ = URI.append("user")

    username = tc.Column("username", tc.String, 100)

    def __init__(self, username):
        self.username = username


class UserService(tc.graph.Graph):
    __uri__ = URI

    @tc.post
    def create_user(self, new_user: User) -> tc.Number:
        user_id = self.user.max_id() + 1
        return tc.After(self.user.insert([user_id], [new_user.username]), user_id)


def start_host(name, apps):
    # I intend to manually kbuild this out and not use the tests code. Once I publish.
    from tests.tctest.process import start_local_host, start_docker

    # return start_local_host(name, apps)
    return start_docker(name, apps)


if __name__ == "__main__":
    # start a new TinyChain host.
    host = start_host("demo", [UserService(models=[User])])

    # verify that it works as expected
    user_id = host.post("/demo/create_user", {"username": "user"})
    print(user_id)
    assert user_id > 0

You can see more in-depth examples in the tests directory.


With this one I think there is potentially a bug in tinychain?, every time I run the code using the latest tinychain bin (0.9.0-beta) i get the following:

start host process on port 8702
bin/tinychain: error while loading shared libraries: libaf.so.3: cannot open shared object file: No such file or directory
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/cormac/workspace/python/tinychain/script.py", line 25, in <module>
    start_host("demo", [Demo()])
  File "/home/cormac/workspace/python/tinychain/script.py", line 19, in start_host
    return start_local_host(name, apps)
  File "/home/cormac/workspace/python/tinychain/tests/tctest/process.py", line 206, in start_local_host
    process.start(wait_time)
  File "/home/cormac/workspace/python/tinychain/tests/tctest/process.py", line 141, in start
    raise RuntimeError(f"TinyChain process crashed on startup")
RuntimeError: TinyChain process crashed on startup

Note that running it with the docker host is fine and works as expected.
Also currently won't work because of issue: #175

readthedocs.io also has not updated since v0.4

The readthedocs.io issue is now fixed: https://tinychain.readthedocs.io/en/latest/