# HG changeset patch # User Goffi # Date 1638371611 -3600 # Node ID b9718216a1c0b5f2149dab3f232711eb4347ddda # Parent af09b5aaa5d7331f5c6d1325e2c9036cbb35dd50# Parent 09f5ac48ffe328f9096cf69c18d0aba289d45103 merge bookmark 0.9 diff -r af09b5aaa5d7 -r b9718216a1c0 dev-requirements.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev-requirements.txt Wed Dec 01 16:13:31 2021 +0100 @@ -0,0 +1,4 @@ +-r requirements.txt + +pytest +pytest_twisted diff -r af09b5aaa5d7 -r b9718216a1c0 doc/_ext/__init__.py diff -r af09b5aaa5d7 -r b9718216a1c0 doc/_ext/docstring.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/_ext/docstring.py Wed Dec 01 16:13:31 2021 +0100 @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +"""Adapt Libervia docstring style to autodoc""" + + +def process_docstring(app, what, name, obj, options, lines): + lines[:] = [ + l.replace("@param", ":param").replace("@raise", ":raises") + for l in lines + ] + + +def setup(app): + app.connect("autodoc-process-docstring", process_docstring) + return { + 'version': '0.1', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff -r af09b5aaa5d7 -r b9718216a1c0 doc/components.rst --- a/doc/components.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/components.rst Wed Dec 01 16:13:31 2021 +0100 @@ -151,3 +151,107 @@ } .. _SI prefixes and binary prefixes: https://en.wikipedia.org/wiki/Octet_(computing)#Unit_multiples + + +ActivityPub Gateway +------------------- + +**entry_point:** ``ap-gateway`` + +.. note:: + + this component is currently in active development, and not yet usable for end-user. This + documentation will be updated during evolution of component. + + You can follow the development by reading `Libervia Progress Notes`_. + + .. _Libervia Progress Notes: https://www.goffi.org/tag/Libervia%20progress + +This gateway will provide a bidirectional gateway between XMPP and `ActivityPub`_ (or AP +below). That means that user from XMPP will be able to follow actors or comments messages +from any software compatible with ActivityPub protocol, and vice versa. + +.. _ActivityPub: https://activitypub.rocks/ + +.. note:: + + this component is mostly tested with Prosody as XMPP server reference, and Mastodon as + AP server reference, but it should work with any XMPP or AP server. + +The component launches a HTTP server (necessary to communicate with AP software). This +server needs to handle HTTP requests made at paths ``/.well-known/webfinger`` and ``/_ap`` +(or the ``ap_path`` set in configuration, see below). If the component is not directly +facing internet (e.g. integrated in an existing website though a proxy), you'll have to +redirect the requests made to those path to the HTTP server (i.e. to component host at the +port set at ``http_port``, see configuration below). Please check your HTTP server +documentation to find how this must be done. + +how to address an AP actor from XMPP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When addressing an ActivityPub actor from XMPP, you must use a JID corresponding to the +actor. The domain part of the JID correspond to the gateway JID (the one set in gateway +profile), while the local part (before the ``@``) is used to specify the AP actor. + +`XEP-0106`_ (JID Escaping) is used to indicate the AP actor identifier, thus the ``@`` +must be escaped with ``\40``. + +.. _XEP-0106: JID Escaping + +**example** + +If Louise wants to talk to Pierre which is on the ``example.net`` AP server, she can use +her XMPP AP gateway which is at ``ap.example.org``. Pierre AP's actor identifier is +``pierre@example.net``, Louise can access it via the JID +``pierre\40example.net@ap.example.org``. + +Of course, this is a bit cumbersome to do by hand, it is expected that XMPP clients will +do the (un)escaping automatically for end-user, in a way that Louise could enter +``pierre@example.net`` directly, with an indicator to show that this is an ActivityPub +actor identifier rather than an XMPP JID. + +how to address an XMPP entity from AP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To access an XMPP entity, just use its bare JID as AP actor. + +**example** + +If Pierre wants to talk Louise, he can directly use the JID which is the same as the AP +actor identifier, i.e. ``louise@example.org`` (note that on AP software, a ``@`` prefix is +often required, thus Pierre will look for ``@louise@example.org``). + +.. note:: + + Currently the gateway only uses bare JID, and character set must be recognised by the + AP software to be used. This will evolve in the close future to have a way to access + various XMPP Pubsub nodes. + + The actor endpoint can also be used directly in AP software (in the example above, it + would be by default ``https://example.org/_ap/actor/louise%40example.org``). + + +using the component +~~~~~~~~~~~~~~~~~~~ + +The component is currently only usable for development purpose, and it can be used with +the following method (with can be accessed through the ``APSend`` bridge method, client is +then replaced by the ``profile`` name, as last argument): + +.. automethod:: sat.plugins.plugin_comp_ap_gateway.APGateway.publishMessage + +The method can be used either with CLI's :ref:`debug bridge method +` or with any D-Bus tool like ``qdbus`` or ``d-feet`` (only if you +use the D-Bus bridge). + +example +~~~~~~~ + +On its ``example.net`` Mastodon instance, Pierre has published a message with the id +``https://example.net/@pierre/106986412193109832``. To send a reply to this message, +Louise can use the following command:: + + $ li debug bridge method -c APSend '"{\"node\": \"https://example.net/@pierre/106986412193109832\", \"content\": \"A lille hello from XMPP\"}","pierre\\40example.net@ap.example.org", "louise"' + +Note the double escaping, one for the shell argument, and the other to specify JSON +object. diff -r af09b5aaa5d7 -r b9718216a1c0 doc/conf.py --- a/doc/conf.py Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/conf.py Wed Dec 01 16:13:31 2021 +0100 @@ -12,13 +12,15 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) +import os +import sys import os.path import re +sys.path.insert(0, os.path.abspath("./_ext")) + + # -- Project information ----------------------------------------------------- project = 'Libervia' @@ -47,6 +49,8 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "sphinx.ext.autodoc", + "docstring" ] # Add any paths that contain templates here, relative to this directory. diff -r af09b5aaa5d7 -r b9718216a1c0 doc/configuration.rst --- a/doc/configuration.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/configuration.rst Wed Dec 01 16:13:31 2021 +0100 @@ -108,6 +108,8 @@ background = auto # end-user facing URL, used by Web frontend public_url = example.com + # uncomment next line if you don't want to use local cache for pubsub items + ; pubsub_cache_strategy = "no_cache" [plugin account] ; where a new account must be created diff -r af09b5aaa5d7 -r b9718216a1c0 doc/developer.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/developer.rst Wed Dec 01 16:13:31 2021 +0100 @@ -0,0 +1,82 @@ +.. _developer: + +======================= +Developer Documentation +======================= + +This documentation is intended for people who wants to contribute or work with the +internals of the project, it is not for end-users. + +Storage +======= + +Since version 0.9, Libervia uses SQLAlchemy_ with its Object–Relational Mapping as a +backend to store persistent data, and Alembic_ is used to handle schema and data +migrations. + +SQLite_ is currently the only supported database, but it is planned to add support for +other ones (notably PostgreSQL), probably during the development of 0.9 version. + +The mapping is done in ``sat.memory.sqla_mapping`` and working with database is done +through high level methods found in ``sat.memory.sqla``. + +Before the move to SQLAlchemy, there was a strict separation between database +implementation and the rest of the code. With 0.9, objects mapping to database can be used +and manipulated directly outside of ``sat.memory.sqla`` to take profit of SQLAlchemy +possibilities. + +Database state is detected when the backend starts, and the database will be created or +migrated automatically if necessary. + +To create a new migration script, ``Alembic`` may be used directly. To do so, be sure to +have an up-to-date database (and a backup in case of troubles), then activate the virtual +environment where Libervia is installed (Alembic needs to access ORM mapping), go to +``sat/memory/migration`` directory, and enter the following command:: + + alembic revision --autogenerate -m "some revision message" + +This will create a base migration file in ``versions`` directory. Adapt it to your needs, +try to create both ``upgrade`` and ``downgrade`` method whenever possible, and be sure to +test it in both directions (``alembic upgrade head`` and ``alembic downgrade +``). Please check Alembic documentation for more details. + +.. _SQLALchemy: https://www.sqlalchemy.org/ +.. _Alembic: https://alembic.sqlalchemy.org/ +.. _SQLite: https://sqlite.org + +Pubsub Cache +============ + +There is an internal cache for pubsub nodes and items, which is done in +``plugin_pubsub_cache``. The ``PubsubNode`` and ``PubsubItem`` class are the one mapping +the database. + +The cache is operated transparently to end-user, when a pubsub request is done, it uses a +trigger to check if the requested node is or must be cached, and if possible returns +result directly from database, otherwise it lets the normal workflow continue and query the +pubsub service. + +To save resources, not all nodes are fully cached. When a node is checked, a series of +analysers are checked, and the first one matching is used to determine if the node must be +synchronised or not. + +Analysers can be registered by any plugins using ``registerAnalyser`` method: + +.. automethod:: sat.plugins.plugin_pubsub_cache.PubsubCache.registerAnalyser + +If no analyser is found, ``to_sync`` is false, or an error happens during the caching, +the node won't be synchronised and the pubsub service will always be requested. + +Specifying an optional **parser** will store parsed data in addition to the raw XML of the +items. This is more space consuming, but may be desired for the following reasons: + +* the parsing is resource consuming (network call or some CPU intensive operations are + done) +* it is desirable to to queries on parsed data. Indeed the parsed data is stored in a + JSON_ field and its keys may be queried individually. + +The Raw XML is kept as the cache operates transparently, and a plugin may need raw data, or +an user may be doing a low-level pubsub request. + +.. _JSON: https://docs.sqlalchemy.org/en/14/core/type_basics.html#sqlalchemy.types.JSON + diff -r af09b5aaa5d7 -r b9718216a1c0 doc/index.rst --- a/doc/index.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/index.rst Wed Dec 01 16:13:31 2021 +0100 @@ -27,6 +27,7 @@ overview.rst configuration.rst components.rst + developer.rst /libervia-cli/index.rst /libervia-tui/index.rst /contributing/index.rst diff -r af09b5aaa5d7 -r b9718216a1c0 doc/libervia-cli/common_arguments.rst --- a/doc/libervia-cli/common_arguments.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/libervia-cli/common_arguments.rst Wed Dec 01 16:13:31 2021 +0100 @@ -88,6 +88,11 @@ this case the ``-m, --max`` argument should be prefered. See below for RSM common arguments. +``-C, --no-cache`` + skip pubsub cache. By default, internal pubsub cache is used automatically if requested + items are available there. With this option set, a request to the pubsub service will + always be done, regardless of presence of node items in internal cache. + result set management ===================== @@ -191,7 +196,7 @@ manipulated by a script, or if you want only a specific element of the result. ``-O {…}, --output {…}`` - specifiy the output to use. Available options depends of the command you are using, + specify the output to use. Available options depends of the command you are using, check ``li [your command] --help`` to know them. e.g.:: @@ -209,6 +214,66 @@ Some options expect parameters, in this case they can be specified using ``=``. - e.g. specifiying a template to use:: + e.g. specifying a template to use:: $ li blog get -O template --oo browser --oo template=/tmp/my_template.html + +.. _time_pattern: + +Time Pattern +============ + +When a command expect a date or date with time argument, you can use a "time pattern" (you +usually see the ``TIME_PATTERN`` as name of the argument in ``--help`` message when it can +be used). + +This is a flexible way to enter a date, you can enter a date in one of the following way: + +- the string ``now`` to indicate current date and time; +- an absolute date using an international format. The parser know many formats (please + check dateutil_ package documentation to have a detail of supported formats). Please + note that days are specified first and that if no time zone is specified, the local + time zone of your computer is assumed; +- a relative date (or "relative delta"), see below for details on how to construct it; +- a reference time (``now`` or absolute date as above) followed by a relative delta. If + the reference time is not specified, ``now`` is used; + +Time pattern is not case sensitive. + +.. _dateutil: https://dateutil.readthedocs.io + +Relative Delta +-------------- + +A relative delta is specified with: + +- an optional direction ``+`` for times after reference time or ``-`` for time before reference time (defaulting to ``+``); +- a number for the quantity of units +- a unit (e.g. seconds or minutes), see the bellow for details +- the word ``ago`` which is same as using ``-`` for direction (direction and ``ago`` can't + be used at the same time) + +Time Units +---------- + +The singular or plural form of following units can be used: + +- ``s``, ``sec``, ``second`` +- ``m``, ``min``, ``minute`` +- ``h``, ``hr``, ``hour`` +- ``d``, ``day`` +- ``w``, ``week`` +- ``mo``, ``month`` +- ``y``, ``yr``, ``year`` + +examples +-------- + +- ``2022-01-01``: first of January of 2022 at midnight +- ``2017-02-10T13:05:00Z``: 10th of February 2017 at 13:05 UTC +- ``2019-07-14 12:00:00 CET``: 14th of July 2019 at 12:00 CET +- ``10 min ago``: current time minus 10 minutes +- ``now - 10 m``: same as above (current time minus 10 minutes) +- ``07/08/2021 +5 hours``: 7 August 2021 at midnight (local time of the computer) + 5 + hours, i.e. 5 in the morning at local time. + diff -r af09b5aaa5d7 -r b9718216a1c0 doc/libervia-cli/debug.rst --- a/doc/libervia-cli/debug.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/libervia-cli/debug.rst Wed Dec 01 16:13:31 2021 +0100 @@ -4,7 +4,7 @@ ``debug`` groups commands to monitor or manipulate Libervia and XMPP stream. -.. _libervia-cli_debug_bridge_method: +.. _li_debug_bridge_method: bridge method ============= diff -r af09b5aaa5d7 -r b9718216a1c0 doc/libervia-cli/pubsub.rst --- a/doc/libervia-cli/pubsub.rst Tue Nov 30 23:31:09 2021 +0100 +++ b/doc/libervia-cli/pubsub.rst Wed Dec 01 16:13:31 2021 +0100 @@ -33,6 +33,8 @@ $ echo 'this is a note' | li pubsub set -n "notes" +.. _li_pubsub_get: + get === @@ -43,15 +45,16 @@ Retrieve the last 5 notes from our custom notes node:: - $ li pubsub get -n notes -m 5 + $ li pubsub get -n notes -M 5 .. _li_pubsub_delete: delete ====== -Delete an item from a node. If ``-N, --notify`` is specified, subscribers will be notified -of the item retraction. +Delete an item from a node. If ``--no-notification`` is specified, subscribers wont be notified +of the item retraction (this is NOT recommended, as it will cause trouble to keep items in +sync, take caution when using this flag). By default a confirmation is requested before deletion is requested to the PubSub service, but you can override this behaviour by using ``-f, --force`` option. @@ -330,7 +333,7 @@ example ------- -Imagine that you want to replace all occurrences of "sàt" by "Libervia" in your personal blog. You first create a Python script like this: +Imagine that you want to replace all occurrences of "SàT" by "Libervia" in your personal blog. You first create a Python script like this: .. sourcecode:: python @@ -338,10 +341,10 @@ import sys item_raw = sys.stdin.read() - if not "sàt" in item_raw: + if not "SàT" in item_raw: print("SKIP") else: - print(item_raw.replace("sàt", "Libervia")) + print(item_raw.replace("SàT", "Libervia")) And save it a some location, e.g. ``~/expand_sat.py`` (don't forget to make it executable with ``chmod +x ~/expand_sat.py``). @@ -380,3 +383,8 @@ ==== Subcommands for hooks management. Please check :ref:`libervia-cli_pubsub_hook`. + +cache +===== + +Subcommands for cache management. Please check :ref:`libervia-cli_pubsub_cache`. diff -r af09b5aaa5d7 -r b9718216a1c0 doc/libervia-cli/pubsub_cache.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/libervia-cli/pubsub_cache.rst Wed Dec 01 16:13:31 2021 +0100 @@ -0,0 +1,350 @@ +.. _libervia-cli_pubsub_cache: + +===================================== +pubsub/cache: PubSub Cache Management +===================================== + +Libervia runs transparently a cache for pubsub. That means that according to internal +criteria, some pubsub items are stored locally. + +The ``cache`` subcommands let user inspect and manipulate the internal cache. + +get +=== + +Retrieve items from internal cache only. Most end-users won't need to use this command, as +the usual ``pubsub get`` command will use cache transparently. However, it may be useful +to inspect local cache, notably for debugging. + +The parameters are basically the same as for :ref:`li_pubsub_get`. + +example +------- + +Retrieve the last 2 cached items for personal blog:: + + $ li pubsub cache get -n urn:xmpp:microblog:0 -M 2 + +.. _li_pubsub_cache_sync: + +sync +==== + +Synchronise or resynchronise a pubsub node. If the node is already in cache, it will be +deleted then re-cached. Node will be put in cache even if internal policy doesn't request +a synchronisation for this kind of nodes. Node will be (re-)subscribed to keep cache +synchronised. + +All items of the node (up to the internal limit which is high), will be retrieved and put +in cache, even if a previous version of those items have been deleted by the +:ref:`li_pubsub_cache_purge` command. + + +example +------- + +Resynchronise personal blog:: + + $ li pubusb cache sync -n urn:xmpp:microblog:0 + +.. _li_pubsub_cache_purge: + +purge +===== + +Remove items from cache. This may be desirable to save resource, notably disk space. + +Note that once a pubsub node is cached, the cache is the source of trust. That means that +if cache is not explicitly bypassed when retrieving items of a pubsub node (notably with +the ``-C, --no-cache`` option of :ref:`li_pubsub_get`), only items found in cache will be +returned, thus purged items won't be used or returned anymore even if they still exists on +the original pubsub service. + +If you have purged items by mistake, it is possible to retrieve them either node by node +using :ref:`li_pubsub_cache_sync`, or by resetting the whole pubsub cache with +:ref:`li_pubsub_cache_reset`. + +If you have a node or a profile (e.g. a component) caching a lot of items frequently, you +may use this command using a scheduler like cron_. + +.. _cron: https://en.wikipedia.org/wiki/Cron + +examples +-------- + +Remove all blog and event items from cache if they haven't been updated since 6 months:: + + $ li pubsub cache purge -t blog -t event -b "6 months ago" + +Remove items from profile ``ap_gateway`` if they have been created more that 2 months +ago:: + + $ li pubsub cache purge -p ap_gateway --created-before "2 months ago" + +.. _li_pubsub_cache_reset: + +reset +===== + +Reset the whole pubsub cache. This means that all nodes and all them items will be removed +from cache. After this command, cache will be re-filled progressively as if it where a new +one. + +.. note:: + + Use this command with caution: even if cache will be re-constructed with time, that + means that items will have to be retrieved again, that may be resource intensive both + for your machine and for the pubsub services which will be used. That also means that + searching items will return less results until all desired items are cached again. + + Also note that all items of cached nodes are retrieved, even if you have previously + purged items, they will be retrieved again. + +example +------- + +Reset the whole pubsub cache:: + + $ li pubsub cache reset + +search +====== + +Search items into pubsub cache. The search is done on the whole cache, it's not restricted +to a single node/profile (even if it may be if suitable filters are specified). Full-Text +Search can be done with ``-f FTS, --fts FTS`` argument, as well as filtering on parsed +data (with ``-F PATH OPERATOR VALUE, --field PATH OPERATOR VALUE``, see below). + +By default, parsed data are returned, with the 3 additional keys ``pubsub_service``, +``pubsub_items`` (the search being done on the whole cache, those data are here to get the +full location of each item) and ``node_profile``. + +"Parsed data" are the result of the parsing of the items XML payload by feature aware +plugins. Those data are usually more readable and easier to work with. Parsed data are +only stored when a parser is registered for a specific feature, that means that a Pubsub +item in cache may not have parsed data at all, in which case an empty dict will be used +instead (and ``-P, --payload`` argument should be used to get content of the item). + +The dates are normally stored as `Unix time`_ in database, but the default output convert +the ``updated``, ``created`` and ``published`` fields to human readable local time. Use +``--output simple`` if you want to keep the float (or int) value. + +XML item payload is not returned by default, but it can be added to the ``item_payload`` +field if ``-P, --payload`` argument is set. You can also use the ``--output xml`` (or +``xml_raw`` if you don't want prettifying) to output directly the highlighted XML +— without the parsed data —, to have an output similar to the one of ``li pubsub get``. + +If you are interested only in a specific data (e.g. item id and title), the ``-k KEY, +--key KEY`` can be used. + +You'll probably want to limit result size by using ``-l LIMIT, --limit LIMIT``, and do +pagination using ``-i INDEX, --index INDEX``. + +.. _Unix time: https://en.wikipedia.org/wiki/Unix_time + +Filters +------- + +By default search returns all items in cache, you have to use filter to specify what you +are looking after. We can split filters in 3 categories: nodes/items metadata, +Full-Text Search query and parsed metadata. + +Nodes/items metadata are the generic information you have on a node: which profile it +belong too, which pubsub service it's coming from, what's the name or type of the node, +etc. + +Arguments there should be self-explanatory. Type (set with ``-t TYPE, --type TYPE``) and +subtype (set with ``-S SUBTYPE, --subtype SUBTYPE``) are values dependent of the +plugin/feature associated with the node, so we can't list them in an exhaustive way here. +The most common type is probably ``blog``, from which a subtype can be ``comment``. An +empty string can be used to find items with (sub)type not set. + +It's usually a good idea to specify a profile with ``-p PROFILE, --profile PROFILE``, +otherwise you may get duplicated results. + +Full-Text Search +---------------- + +You can specify a Full-Text Search query with the ``-f FTS_QUERY, --fts FTS_QUERY`` +argument. The engine is currently SQLite FTS5, and you can check its `query syntax`_. +FTS is done on the whole raw XML payload, that means that all data there can be matched +(including XML tags and attributes). + +FTS queries are indexed, that means that they are fast and efficient. + +.. note:: + + Futures version of Libervia will probably include other FTS engines (support for + PostgreSQL and MySQL/MariaDB is planned). Thus the syntax may vary depending on the + engine, or a common syntax may be implemented for all engines in the future. Keep that + in mind if you plan to use FTS capabilities in long-term queries, e.g. in scripts. + +.. _query syntax: https://sqlite.org/fts5.html#full_text_query_syntax + +Parsed Metadata Filters +----------------------- + +It is possible to filter on any field of parsed data. This is done with the ``-F PATH +OPERATOR VALUE, --field PATH OPERATOR VALUE`` (be careful that the short option is an +uppercase ``F``, the lower case one being used for Full-Text Search). + +.. note:: + + Parsed Metadata Filters are not indexed, that means that using them is less efficient + than using e.g. Full-Text Search. If you want to filter on a text field, it's often a + good idea to pre-filter using Full-Text Search to have more efficient queries. + +``PATH`` and ``VALUE`` can be either specified as string, or using JSON syntax (if the +value can't be decoded as JSON, it is used as plain text). + +``PATH`` is the name of the field to use. If you must go beyond root level fields, you can +use a JSON array to specify each element of the path. If a string is used, it's an object +key, if a number is used it's an array index. Thus you can use ``title`` to access the +root title key, or ``'"title"'`` (JSON string escaped for shell) or ``'["title"]'`` (JSON +array with the "title" string, escaped for shell). + +.. note:: + + The extra fields ``pubsub_service``, ``pubsub_node`` and  ``node_profile`` are added to + the result after the query, thus they can't be used as fields for filtering (use the + direct arguments for that). + +``OPERATOR`` indicate how to use the value to make a filter. The currently supported +operators are: + +``==`` or ``eq`` + Equality operator, true if field value is the same as given value. + +``!=`` or ``ne`` + Inequality operator, true if the field value is different from given value. + +``>`` or ``gt`` + Greater than, true if the field value is higher than given value. For string, this is + according to alphabetical order. + + Time Pattern can be used here, see below. + +``<`` or ``lt`` + Lesser than, true if the field value is lower than given value. For string, this is + according to alphabetical order. + + Time Pattern can be used here, see below. + +``between`` + Given value must be an array with 2 elements. The condition is true if field value is + between the 2 elements (for string, this is according to alphabetical order). + + Time Pattern can be used here, see below. + +``in`` + Given value must be an array of elements. Field value must be one of them to make the + condition true. + +``not_in`` + Given value must be an array of elements. Field value must not be any of them the make + the condition true. + +``overlap`` + This can be used only on array fields. + + If given value is not already an array, it is put in an array. Condition is true if any + element of field value match any element of given value. Notably useful to filter on + tags. + +``ioverlap`` + Same as ``overlap`` but done in a case insensitive way. + +``disjoint`` + This can be used only on array fields. + + If given value is not already an array, it is put in an array. Condition is true if no + element of field value match any element of given value. Notably useful to filter out + tags. + +``idisjoint`` + Same as ``disjoint`` but done in a case insensitive way. + +``like`` + Does pattern matching on a string. ``%`` can be used to match zero or more characters + and ``_`` can be used to match any single character. + + If you're not looking after a specific field, it's better to use Full-Text Search when + possible. + +``ilike`` + Like ``like`` but done in a case insensitive way. + + +``not_like`` + Same as ``like`` except that condition is true when pattern is **not** matching. + +``not_ilike`` + Same as ``not_like`` but done in a case insensitive way. + + +For ``gt``/``>``, ``lt``/``<`` and ``between``, you can use :ref:`time_pattern` by using +the syntax ``TP(