1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00

Update docs

This commit is contained in:
Steffo 2019-09-01 23:51:10 +02:00
parent 52079c6c27
commit ad4aa25c97
8 changed files with 294 additions and 20 deletions

Binary file not shown.

View file

@ -166,7 +166,7 @@ To match a pattern, :py:func:`re.match` is used, meaning that Python will try to
# ("carbonara", "al-dente") # ("carbonara", "al-dente")
Running code at the initialization of the bot Running code at the initialization of the bot
------------------------------------ ---------------------------------------------
You can run code while the bot is starting by overriding the :py:meth:`Command.__init__` function. You can run code while the bot is starting by overriding the :py:meth:`Command.__init__` function.
@ -229,14 +229,102 @@ function: ::
Avoid using :py:func:`time.sleep` function, as it is considered a slow operation: use instead :py:func:`asyncio.sleep`, Avoid using :py:func:`time.sleep` function, as it is considered a slow operation: use instead :py:func:`asyncio.sleep`,
a coroutine that does the same exact thing. a coroutine that does the same exact thing.
Accessing the database Using the database
------------------------------------ ------------------------------------
.. Usually, bots are connected to a PostgreSQL database through a :py:class:`royalnet.database.Alchemy` interface (which is Bots can be connected to a PostgreSQL database through a special SQLAlchemy interface called
itself a SQLAlchemy wrapper). :py:class:`royalnet.database.Alchemy`.
.. Commands can access the connected database through the :py:class:`royalnet.database.Alchemy` available at If the connection is established, the ``self.interface.alchemy`` and ``self.interface.session`` fields will be
``self.interface.alchemy``, and can access the database session at ``self.interface.session``. available for use in commands.
``self.interface.alchemy`` is an instance of :py:class:`royalnet.database.Alchemy`, which contains the
:py:class:`sqlalchemy.engine.Engine`, metadata and tables, while ``self.interface.session`` is a
:py:class:`sqlalchemy.orm.session.Session`, and can be interacted in the same way as one.
If you want to use :py:class:`royalnet.database.Alchemy` in your command, you should override the
``require_alchemy_tables`` field with the :py:class:`set` of Alchemy tables you need. ::
from royalnet.commands import Command
from royalnet.database.tables import Royal
class SpaghettiCommand(Command):
name = "spaghetti"
description = "Send a spaghetti emoji in the chat."
syntax = "(pasta)"
requrire_alchemy_tables = {Royal}
...
Querying the database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can :py:class:`sqlalchemy.orm.query.Query` the database using the SQLAlchemy ORM.
The SQLAlchemy tables can be found inside :py:class:`royalnet.database.Alchemy` with the same name they were created
from, if they were specified in ``require_alchemy_tables``. ::
RoyalTable = self.interface.alchemy.Royal
query = self.interface.session.query(RoyalTable)
Adding filters to the query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can filter the query results with the :py:meth:`sqlalchemy.orm.query.Query.filter` method.
.. note:: Remember to always use a table column as first comparision element, as it won't work otherwise.
::
query = query.filter(RoyalTable.role == "Member")
Ordering the results of a query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can order the query results in **ascending order** with the :py:meth:`sqlalchemy.orm.query.Query.order_by` method. ::
query = query.order_by(RoyalTable.username)
Additionally, you can append the `.desc()` method to a table column to sort in **descending order**: ::
query = query.order_by(RoyalTable.username.desc())
Fetching the results of a query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can fetch the query results with the :py:meth:`sqlalchemy.orm.query.Query.all`,
:py:meth:`sqlalchemy.orm.query.Query.first`, :py:meth:`sqlalchemy.orm.query.Query.one` and
:py:meth:`sqlalchemy.orm.query.Query.one_or_none` methods.
Remember to use :py:func:`royalnet.utils.asyncify` when fetching results, as it may take a while!
Use :py:meth:`sqlalchemy.orm.query.Query.all` if you want a :py:class:`list` of **all results**: ::
results: list = await asyncify(query.all)
Use :py:meth:`sqlalchemy.orm.query.Query.first` if you want **the first result** of the list, or :py:const:`None` if
there are no results: ::
result: typing.Union[..., None] = await asyncify(query.first)
Use :py:meth:`sqlalchemy.orm.query.Query.one` if you expect to have **a single result**, and you want the command to
raise an error if any different number of results is returned: ::
result: ... = await asyncify(query.one) # Raises an error if there are no results or more than a result.
Use :py:meth:`sqlalchemy.orm.query.Query.one_or_none` if you expect to have **a single result**, or **nothing**, and
if you want the command to raise an error if the number of results is greater than one. ::
result: typing.Union[..., None] = await asyncify(query.one_or_none) # Raises an error if there is more than a result.
More Alchemy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can read more about :py:mod:`sqlalchemy` at their `website <https://www.sqlalchemy.org/>`_.
Comunicating via Royalnet Comunicating via Royalnet
------------------------------------ ------------------------------------

View file

@ -383,7 +383,7 @@
<dl class="method"> <dl class="method">
<dt id="royalnet.bots.TelegramBot._init_client"> <dt id="royalnet.bots.TelegramBot._init_client">
<code class="sig-name descname">_init_client</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#royalnet.bots.TelegramBot._init_client" title="Permalink to this definition"></a></dt> <code class="sig-name descname">_init_client</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#royalnet.bots.TelegramBot._init_client" title="Permalink to this definition"></a></dt>
<dd><p>Create the <a class="reference external" href="https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html#telegram.Bot" title="(in Python Telegram Bot v11.1)"><code class="xref py py-class docutils literal notranslate"><span class="pre">telegram.Bot</span></code></a>, and set the starting offset.</p> <dd><p>Create the <a class="reference external" href="https://python-telegram-bot.readthedocs.io/en/stable/telegram.bot.html#telegram.Bot" title="(in Python Telegram Bot v12.0)"><code class="xref py py-class docutils literal notranslate"><span class="pre">telegram.Bot</span></code></a>, and set the starting offset.</p>
</dd></dl> </dd></dl>
<dl class="method"> <dl class="method">

View file

@ -93,7 +93,14 @@
</li> </li>
<li class="toctree-l2"><a class="reference internal" href="#running-code-at-the-initialization-of-the-bot">Running code at the initialization of the bot</a></li> <li class="toctree-l2"><a class="reference internal" href="#running-code-at-the-initialization-of-the-bot">Running code at the initialization of the bot</a></li>
<li class="toctree-l2"><a class="reference internal" href="#coroutines-and-slow-operations">Coroutines and slow operations</a></li> <li class="toctree-l2"><a class="reference internal" href="#coroutines-and-slow-operations">Coroutines and slow operations</a></li>
<li class="toctree-l2"><a class="reference internal" href="#accessing-the-database">Accessing the database</a></li> <li class="toctree-l2"><a class="reference internal" href="#using-the-database">Using the database</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#querying-the-database">Querying the database</a></li>
<li class="toctree-l3"><a class="reference internal" href="#adding-filters-to-the-query">Adding filters to the query</a></li>
<li class="toctree-l3"><a class="reference internal" href="#ordering-the-results-of-a-query">Ordering the results of a query</a></li>
<li class="toctree-l3"><a class="reference internal" href="#fetching-the-results-of-a-query">Fetching the results of a query</a></li>
<li class="toctree-l3"><a class="reference internal" href="#more-alchemy">More Alchemy</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#comunicating-via-royalnet">Comunicating via Royalnet</a></li> <li class="toctree-l2"><a class="reference internal" href="#comunicating-via-royalnet">Comunicating via Royalnet</a></li>
</ul> </ul>
</li> </li>
@ -371,10 +378,94 @@ function:</p>
<p>Avoid using <a class="reference external" href="https://docs.python.org/3.7/library/time.html#time.sleep" title="(in Python v3.7)"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.sleep()</span></code></a> function, as it is considered a slow operation: use instead <a class="reference external" href="https://docs.python.org/3.7/library/asyncio-task.html#asyncio.sleep" title="(in Python v3.7)"><code class="xref py py-func docutils literal notranslate"><span class="pre">asyncio.sleep()</span></code></a>, <p>Avoid using <a class="reference external" href="https://docs.python.org/3.7/library/time.html#time.sleep" title="(in Python v3.7)"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.sleep()</span></code></a> function, as it is considered a slow operation: use instead <a class="reference external" href="https://docs.python.org/3.7/library/asyncio-task.html#asyncio.sleep" title="(in Python v3.7)"><code class="xref py py-func docutils literal notranslate"><span class="pre">asyncio.sleep()</span></code></a>,
a coroutine that does the same exact thing.</p> a coroutine that does the same exact thing.</p>
</div> </div>
<div class="section" id="accessing-the-database"> <div class="section" id="using-the-database">
<h2>Accessing the database<a class="headerlink" href="#accessing-the-database" title="Permalink to this headline"></a></h2> <h2>Using the database<a class="headerlink" href="#using-the-database" title="Permalink to this headline"></a></h2>
<p>itself a SQLAlchemy wrapper).</p> <p>Bots can be connected to a PostgreSQL database through a special SQLAlchemy interface called
<p><code class="docutils literal notranslate"><span class="pre">self.interface.alchemy</span></code>, and can access the database session at <code class="docutils literal notranslate"><span class="pre">self.interface.session</span></code>.</p> <a class="reference internal" href="apireference.html#royalnet.database.Alchemy" title="royalnet.database.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.database.Alchemy</span></code></a>.</p>
<p>If the connection is established, the <code class="docutils literal notranslate"><span class="pre">self.interface.alchemy</span></code> and <code class="docutils literal notranslate"><span class="pre">self.interface.session</span></code> fields will be
available for use in commands.</p>
<p><code class="docutils literal notranslate"><span class="pre">self.interface.alchemy</span></code> is an instance of <a class="reference internal" href="apireference.html#royalnet.database.Alchemy" title="royalnet.database.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.database.Alchemy</span></code></a>, which contains the
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/core/connections.html#sqlalchemy.engine.Engine" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.engine.Engine</span></code></a>, metadata and tables, while <code class="docutils literal notranslate"><span class="pre">self.interface.session</span></code> is a
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.orm.session.Session</span></code></a>, and can be interacted in the same way as one.</p>
<p>If you want to use <a class="reference internal" href="apireference.html#royalnet.database.Alchemy" title="royalnet.database.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.database.Alchemy</span></code></a> in your command, you should override the
<code class="docutils literal notranslate"><span class="pre">require_alchemy_tables</span></code> field with the <a class="reference external" href="https://docs.python.org/3.7/library/stdtypes.html#set" title="(in Python v3.7)"><code class="xref py py-class docutils literal notranslate"><span class="pre">set</span></code></a> of Alchemy tables you need.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">royalnet.commands</span> <span class="k">import</span> <span class="n">Command</span>
<span class="kn">from</span> <span class="nn">royalnet.database.tables</span> <span class="k">import</span> <span class="n">Royal</span>
<span class="k">class</span> <span class="nc">SpaghettiCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;spaghetti&quot;</span>
<span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;Send a spaghetti emoji in the chat.&quot;</span>
<span class="n">syntax</span> <span class="o">=</span> <span class="s2">&quot;(pasta)&quot;</span>
<span class="n">requrire_alchemy_tables</span> <span class="o">=</span> <span class="p">{</span><span class="n">Royal</span><span class="p">}</span>
<span class="o">...</span>
</pre></div>
</div>
<div class="section" id="querying-the-database">
<h3>Querying the database<a class="headerlink" href="#querying-the-database" title="Permalink to this headline"></a></h3>
<p>You can <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query" title="(in SQLAlchemy v1.3)"><code class="xref py py-class docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query</span></code></a> the database using the SQLAlchemy ORM.</p>
<p>The SQLAlchemy tables can be found inside <a class="reference internal" href="apireference.html#royalnet.database.Alchemy" title="royalnet.database.Alchemy"><code class="xref py py-class docutils literal notranslate"><span class="pre">royalnet.database.Alchemy</span></code></a> with the same name they were created
from, if they were specified in <code class="docutils literal notranslate"><span class="pre">require_alchemy_tables</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">RoyalTable</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">interface</span><span class="o">.</span><span class="n">alchemy</span><span class="o">.</span><span class="n">Royal</span>
<span class="n">query</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">interface</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">RoyalTable</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="adding-filters-to-the-query">
<h3>Adding filters to the query<a class="headerlink" href="#adding-filters-to-the-query" title="Permalink to this headline"></a></h3>
<p>You can filter the query results with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.filter" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.filter()</span></code></a> method.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Remember to always use a table column as first comparision element, as it wont work otherwise.</p>
</div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">RoyalTable</span><span class="o">.</span><span class="n">role</span> <span class="o">==</span> <span class="s2">&quot;Member&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="ordering-the-results-of-a-query">
<h3>Ordering the results of a query<a class="headerlink" href="#ordering-the-results-of-a-query" title="Permalink to this headline"></a></h3>
<p>You can order the query results in <strong>ascending order</strong> with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.order_by" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.order_by()</span></code></a> method.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">RoyalTable</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
</pre></div>
</div>
<p>Additionally, you can append the <cite>.desc()</cite> method to a table column to sort in <strong>descending order</strong>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">RoyalTable</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">desc</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="section" id="fetching-the-results-of-a-query">
<h3>Fetching the results of a query<a class="headerlink" href="#fetching-the-results-of-a-query" title="Permalink to this headline"></a></h3>
<p>You can fetch the query results with the <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.all" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.all()</span></code></a>,
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.first" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.first()</span></code></a>, <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one()</span></code></a> and
<a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one_or_none" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one_or_none()</span></code></a> methods.</p>
<p>Remember to use <a class="reference internal" href="apireference.html#royalnet.utils.asyncify" title="royalnet.utils.asyncify"><code class="xref py py-func docutils literal notranslate"><span class="pre">royalnet.utils.asyncify()</span></code></a> when fetching results, as it may take a while!</p>
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.all" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.all()</span></code></a> if you want a <a class="reference external" href="https://docs.python.org/3.7/library/stdtypes.html#list" title="(in Python v3.7)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> of <strong>all results</strong>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">results</span><span class="p">:</span> <span class="nb">list</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">all</span><span class="p">)</span>
</pre></div>
</div>
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.first" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.first()</span></code></a> if you want <strong>the first result</strong> of the list, or <code class="xref py py-const docutils literal notranslate"><span class="pre">None</span></code> if
there are no results:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">first</span><span class="p">)</span>
</pre></div>
</div>
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one()</span></code></a> if you expect to have <strong>a single result</strong>, and you want the command to
raise an error if any different number of results is returned:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="o">...</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">one</span><span class="p">)</span> <span class="c1"># Raises an error if there are no results or more than a result.</span>
</pre></div>
</div>
<p>Use <a class="reference external" href="https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.one_or_none" title="(in SQLAlchemy v1.3)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">sqlalchemy.orm.query.Query.one_or_none()</span></code></a> if you expect to have <strong>a single result</strong>, or <strong>nothing</strong>, and
if you want the command to raise an error if the number of results is greater than one.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncify</span><span class="p">(</span><span class="n">query</span><span class="o">.</span><span class="n">one_or_none</span><span class="p">)</span> <span class="c1"># Raises an error if there is more than a result.</span>
</pre></div>
</div>
</div>
<div class="section" id="more-alchemy">
<h3>More Alchemy<a class="headerlink" href="#more-alchemy" title="Permalink to this headline"></a></h3>
<p>You can read more about <code class="xref py py-mod docutils literal notranslate"><span class="pre">sqlalchemy</span></code> at their <a class="reference external" href="https://www.sqlalchemy.org/">website</a>.</p>
</div>
</div> </div>
<div class="section" id="comunicating-via-royalnet"> <div class="section" id="comunicating-via-royalnet">
<h2>Comunicating via Royalnet<a class="headerlink" href="#comunicating-via-royalnet" title="Permalink to this headline"></a></h2> <h2>Comunicating via Royalnet<a class="headerlink" href="#comunicating-via-royalnet" title="Permalink to this headline"></a></h2>

View file

@ -163,7 +163,14 @@
</li> </li>
<li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#running-code-at-the-initialization-of-the-bot">Running code at the initialization of the bot</a></li> <li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#running-code-at-the-initialization-of-the-bot">Running code at the initialization of the bot</a></li>
<li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#coroutines-and-slow-operations">Coroutines and slow operations</a></li> <li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#coroutines-and-slow-operations">Coroutines and slow operations</a></li>
<li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#accessing-the-database">Accessing the database</a></li> <li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#using-the-database">Using the database</a><ul>
<li class="toctree-l3"><a class="reference internal" href="creatingacommand.html#querying-the-database">Querying the database</a></li>
<li class="toctree-l3"><a class="reference internal" href="creatingacommand.html#adding-filters-to-the-query">Adding filters to the query</a></li>
<li class="toctree-l3"><a class="reference internal" href="creatingacommand.html#ordering-the-results-of-a-query">Ordering the results of a query</a></li>
<li class="toctree-l3"><a class="reference internal" href="creatingacommand.html#fetching-the-results-of-a-query">Fetching the results of a query</a></li>
<li class="toctree-l3"><a class="reference internal" href="creatingacommand.html#more-alchemy">More Alchemy</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#comunicating-via-royalnet">Comunicating via Royalnet</a></li> <li class="toctree-l2"><a class="reference internal" href="creatingacommand.html#comunicating-via-royalnet">Comunicating via Royalnet</a></li>
</ul> </ul>
</li> </li>

File diff suppressed because one or more lines are too long

View file

@ -166,7 +166,7 @@ To match a pattern, :py:func:`re.match` is used, meaning that Python will try to
# ("carbonara", "al-dente") # ("carbonara", "al-dente")
Running code at the initialization of the bot Running code at the initialization of the bot
------------------------------------ ---------------------------------------------
You can run code while the bot is starting by overriding the :py:meth:`Command.__init__` function. You can run code while the bot is starting by overriding the :py:meth:`Command.__init__` function.
@ -229,14 +229,102 @@ function: ::
Avoid using :py:func:`time.sleep` function, as it is considered a slow operation: use instead :py:func:`asyncio.sleep`, Avoid using :py:func:`time.sleep` function, as it is considered a slow operation: use instead :py:func:`asyncio.sleep`,
a coroutine that does the same exact thing. a coroutine that does the same exact thing.
Accessing the database Using the database
------------------------------------ ------------------------------------
.. Usually, bots are connected to a PostgreSQL database through a :py:class:`royalnet.database.Alchemy` interface (which is Bots can be connected to a PostgreSQL database through a special SQLAlchemy interface called
itself a SQLAlchemy wrapper). :py:class:`royalnet.database.Alchemy`.
.. Commands can access the connected database through the :py:class:`royalnet.database.Alchemy` available at If the connection is established, the ``self.interface.alchemy`` and ``self.interface.session`` fields will be
``self.interface.alchemy``, and can access the database session at ``self.interface.session``. available for use in commands.
``self.interface.alchemy`` is an instance of :py:class:`royalnet.database.Alchemy`, which contains the
:py:class:`sqlalchemy.engine.Engine`, metadata and tables, while ``self.interface.session`` is a
:py:class:`sqlalchemy.orm.session.Session`, and can be interacted in the same way as one.
If you want to use :py:class:`royalnet.database.Alchemy` in your command, you should override the
``require_alchemy_tables`` field with the :py:class:`set` of Alchemy tables you need. ::
from royalnet.commands import Command
from royalnet.database.tables import Royal
class SpaghettiCommand(Command):
name = "spaghetti"
description = "Send a spaghetti emoji in the chat."
syntax = "(pasta)"
requrire_alchemy_tables = {Royal}
...
Querying the database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can :py:class:`sqlalchemy.orm.query.Query` the database using the SQLAlchemy ORM.
The SQLAlchemy tables can be found inside :py:class:`royalnet.database.Alchemy` with the same name they were created
from, if they were specified in ``require_alchemy_tables``. ::
RoyalTable = self.interface.alchemy.Royal
query = self.interface.session.query(RoyalTable)
Adding filters to the query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can filter the query results with the :py:meth:`sqlalchemy.orm.query.Query.filter` method.
.. note:: Remember to always use a table column as first comparision element, as it won't work otherwise.
::
query = query.filter(RoyalTable.role == "Member")
Ordering the results of a query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can order the query results in **ascending order** with the :py:meth:`sqlalchemy.orm.query.Query.order_by` method. ::
query = query.order_by(RoyalTable.username)
Additionally, you can append the `.desc()` method to a table column to sort in **descending order**: ::
query = query.order_by(RoyalTable.username.desc())
Fetching the results of a query
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can fetch the query results with the :py:meth:`sqlalchemy.orm.query.Query.all`,
:py:meth:`sqlalchemy.orm.query.Query.first`, :py:meth:`sqlalchemy.orm.query.Query.one` and
:py:meth:`sqlalchemy.orm.query.Query.one_or_none` methods.
Remember to use :py:func:`royalnet.utils.asyncify` when fetching results, as it may take a while!
Use :py:meth:`sqlalchemy.orm.query.Query.all` if you want a :py:class:`list` of **all results**: ::
results: list = await asyncify(query.all)
Use :py:meth:`sqlalchemy.orm.query.Query.first` if you want **the first result** of the list, or :py:const:`None` if
there are no results: ::
result: typing.Union[..., None] = await asyncify(query.first)
Use :py:meth:`sqlalchemy.orm.query.Query.one` if you expect to have **a single result**, and you want the command to
raise an error if any different number of results is returned: ::
result: ... = await asyncify(query.one) # Raises an error if there are no results or more than a result.
Use :py:meth:`sqlalchemy.orm.query.Query.one_or_none` if you expect to have **a single result**, or **nothing**, and
if you want the command to raise an error if the number of results is greater than one. ::
result: typing.Union[..., None] = await asyncify(query.one_or_none) # Raises an error if there is more than a result.
More Alchemy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can read more about :py:mod:`sqlalchemy` at their `website <https://www.sqlalchemy.org/>`_.
Comunicating via Royalnet Comunicating via Royalnet
------------------------------------ ------------------------------------