fauna.query.query_builder
1import abc 2from typing import Any, Optional, List 3 4from .template import FaunaTemplate 5 6 7class Fragment(abc.ABC): 8 """An abstract class representing a Fragment of a query. 9 """ 10 11 @abc.abstractmethod 12 def get(self) -> Any: 13 """An abstract method for returning a stored value. 14 """ 15 pass 16 17 18class ValueFragment(Fragment): 19 """A concrete :class:`Fragment` representing a part of a query that can represent a template variable. 20 For example, if a template contains a variable ``${foo}``, and an object ``{ "prop": 1 }`` is provided for foo, 21 then ``{ "prop": 1 }`` should be wrapped as a :class:`ValueFragment`. 22 23 :param Any val: The value to be used as a fragment. 24 """ 25 26 def __init__(self, val: Any): 27 self._val = val 28 29 def get(self) -> Any: 30 """Gets the stored value. 31 32 :returns: The stored value. 33 """ 34 return self._val 35 36 37class LiteralFragment(Fragment): 38 """A concrete :class:`Fragment` representing a query literal For example, in the template ```let x = ${foo}```, 39 the portion ```let x = ``` is a query literal and should be wrapped as a :class:`LiteralFragment`. 40 41 :param str val: The query literal to be used as a fragment. 42 """ 43 44 def __init__(self, val: str): 45 self._val = val 46 47 def get(self) -> str: 48 """Returns the stored value. 49 50 :returns: The stored value. 51 """ 52 return self._val 53 54 55class Query: 56 """A class for representing a query. 57 58 e.g. { "fql": [...] } 59 """ 60 _fragments: List[Fragment] 61 62 def __init__(self, fragments: Optional[List[Fragment]] = None): 63 self._fragments = fragments or [] 64 65 @property 66 def fragments(self) -> List[Fragment]: 67 """The list of stored Fragments""" 68 return self._fragments 69 70 def __str__(self) -> str: 71 res = "" 72 for f in self._fragments: 73 res += str(f.get()) 74 75 return res 76 77 78def fql(query: str, **kwargs: Any) -> Query: 79 """Creates a Query - capable of performing query composition and simple querying. It can accept a 80 simple string query, or can perform composition using ``${}`` sigil string template with ``**kwargs`` as 81 substitutions. 82 83 The ``**kwargs`` can be Fauna data types - such as strings, document references, or modules - and embedded 84 Query - allowing you to compose arbitrarily complex queries. 85 86 When providing ``**kwargs``, following types are accepted: 87 - :class:`str`, :class:`int`, :class:`float`, :class:`bool`, :class:`datetime.datetime`, :class:`datetime.date`, 88 :class:`dict`, :class:`list`, :class:`Query`, :class:`DocumentReference`, :class:`Module` 89 90 :raises ValueError: If there is an invalid template placeholder or a value that cannot be encoded. 91 :returns: A :class:`Query` that can be passed to the client for evaluation against Fauna. 92 93 Examples: 94 95 .. code-block:: python 96 :name: Simple-FQL-Example 97 :caption: Simple query declaration using this function. 98 99 fql('Dogs.byName("Fido")') 100 101 .. code-block:: python 102 :name: Composition-FQL-Example 103 :caption: Query composition using this function. 104 105 def get_dog(id): 106 return fql('Dogs.byId(${id})', id=id) 107 108 def get_vet_phone(id): 109 return fql('${dog} { .vet_phone_number }', dog=get_dog(id)) 110 111 get_vet_phone('d123') 112 113 """ 114 115 fragments: List[Any] = [] 116 template = FaunaTemplate(query) 117 for text, field_name in template.iter(): 118 if text is not None and len(text) > 0: 119 fragments.append(LiteralFragment(text)) 120 121 if field_name is not None: 122 if field_name not in kwargs: 123 raise ValueError( 124 f"template variable `{field_name}` not found in provided kwargs") 125 126 # TODO: Reject if it's already a fragment, or accept *Fragment? Decide on API here 127 fragments.append(ValueFragment(kwargs[field_name])) 128 return Query(fragments)
8class Fragment(abc.ABC): 9 """An abstract class representing a Fragment of a query. 10 """ 11 12 @abc.abstractmethod 13 def get(self) -> Any: 14 """An abstract method for returning a stored value. 15 """ 16 pass
An abstract class representing a Fragment of a query.
19class ValueFragment(Fragment): 20 """A concrete :class:`Fragment` representing a part of a query that can represent a template variable. 21 For example, if a template contains a variable ``${foo}``, and an object ``{ "prop": 1 }`` is provided for foo, 22 then ``{ "prop": 1 }`` should be wrapped as a :class:`ValueFragment`. 23 24 :param Any val: The value to be used as a fragment. 25 """ 26 27 def __init__(self, val: Any): 28 self._val = val 29 30 def get(self) -> Any: 31 """Gets the stored value. 32 33 :returns: The stored value. 34 """ 35 return self._val
A concrete Fragment
representing a part of a query that can represent a template variable.
For example, if a template contains a variable ${foo}
, and an object { "prop": 1 }
is provided for foo,
then { "prop": 1 }
should be wrapped as a ValueFragment
.
Parameters
- Any val: The value to be used as a fragment.
38class LiteralFragment(Fragment): 39 """A concrete :class:`Fragment` representing a query literal For example, in the template ```let x = ${foo}```, 40 the portion ```let x = ``` is a query literal and should be wrapped as a :class:`LiteralFragment`. 41 42 :param str val: The query literal to be used as a fragment. 43 """ 44 45 def __init__(self, val: str): 46 self._val = val 47 48 def get(self) -> str: 49 """Returns the stored value. 50 51 :returns: The stored value. 52 """ 53 return self._val
A concrete Fragment
representing a query literal For example, in the template let x = ${foo}
,
the portion let x =
is a query literal and should be wrapped as a LiteralFragment
.
Parameters
- str val: The query literal to be used as a fragment.
56class Query: 57 """A class for representing a query. 58 59 e.g. { "fql": [...] } 60 """ 61 _fragments: List[Fragment] 62 63 def __init__(self, fragments: Optional[List[Fragment]] = None): 64 self._fragments = fragments or [] 65 66 @property 67 def fragments(self) -> List[Fragment]: 68 """The list of stored Fragments""" 69 return self._fragments 70 71 def __str__(self) -> str: 72 res = "" 73 for f in self._fragments: 74 res += str(f.get()) 75 76 return res
A class for representing a query.
e.g. { "fql": [...] }
79def fql(query: str, **kwargs: Any) -> Query: 80 """Creates a Query - capable of performing query composition and simple querying. It can accept a 81 simple string query, or can perform composition using ``${}`` sigil string template with ``**kwargs`` as 82 substitutions. 83 84 The ``**kwargs`` can be Fauna data types - such as strings, document references, or modules - and embedded 85 Query - allowing you to compose arbitrarily complex queries. 86 87 When providing ``**kwargs``, following types are accepted: 88 - :class:`str`, :class:`int`, :class:`float`, :class:`bool`, :class:`datetime.datetime`, :class:`datetime.date`, 89 :class:`dict`, :class:`list`, :class:`Query`, :class:`DocumentReference`, :class:`Module` 90 91 :raises ValueError: If there is an invalid template placeholder or a value that cannot be encoded. 92 :returns: A :class:`Query` that can be passed to the client for evaluation against Fauna. 93 94 Examples: 95 96 .. code-block:: python 97 :name: Simple-FQL-Example 98 :caption: Simple query declaration using this function. 99 100 fql('Dogs.byName("Fido")') 101 102 .. code-block:: python 103 :name: Composition-FQL-Example 104 :caption: Query composition using this function. 105 106 def get_dog(id): 107 return fql('Dogs.byId(${id})', id=id) 108 109 def get_vet_phone(id): 110 return fql('${dog} { .vet_phone_number }', dog=get_dog(id)) 111 112 get_vet_phone('d123') 113 114 """ 115 116 fragments: List[Any] = [] 117 template = FaunaTemplate(query) 118 for text, field_name in template.iter(): 119 if text is not None and len(text) > 0: 120 fragments.append(LiteralFragment(text)) 121 122 if field_name is not None: 123 if field_name not in kwargs: 124 raise ValueError( 125 f"template variable `{field_name}` not found in provided kwargs") 126 127 # TODO: Reject if it's already a fragment, or accept *Fragment? Decide on API here 128 fragments.append(ValueFragment(kwargs[field_name])) 129 return Query(fragments)
Creates a Query - capable of performing query composition and simple querying. It can accept a
simple string query, or can perform composition using ${}
sigil string template with **kwargs
as
substitutions.
The **kwargs
can be Fauna data types - such as strings, document references, or modules - and embedded
Query - allowing you to compose arbitrarily complex queries.
When providing **kwargs
, following types are accepted:
- str
, int
, float
, bool
, datetime.datetime
, datetime.date
,
dict
, list
, Query
, DocumentReference
, Module
Raises
- ValueError: If there is an invalid template placeholder or a value that cannot be encoded.
:returns: A
Query
that can be passed to the client for evaluation against Fauna.
Examples:
fql('Dogs.byName("Fido")')
def get_dog(id):
return fql('Dogs.byId(${id})', id=id)
def get_vet_phone(id):
return fql('${dog} { .vet_phone_number }', dog=get_dog(id))
get_vet_phone('d123')