Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## 13.6.0

* Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance
* Add `Operator` class for atomic modification of rows via update, bulk update, upsert, and bulk upsert operations

## 13.5.0

* Add `create_resend_provider` and `update_resend_provider` methods to `Messaging` service
Expand Down
4 changes: 2 additions & 2 deletions appwrite/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ def __init__(self):
self._endpoint = 'https://cloud.appwrite.io/v1'
self._global_headers = {
'content-type': '',
'user-agent' : f'AppwritePythonSDK/13.5.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'user-agent' : f'AppwritePythonSDK/13.6.0 ({platform.uname().system}; {platform.uname().version}; {platform.uname().machine})',
'x-sdk-name': 'Python',
'x-sdk-platform': 'server',
'x-sdk-language': 'python',
'x-sdk-version': '13.5.0',
'x-sdk-version': '13.6.0',
'X-Appwrite-Response-Format' : '1.8.0',
}

Expand Down
152 changes: 152 additions & 0 deletions appwrite/operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import json
import math
from enum import Enum


class Condition(Enum):
EQUAL = "equal"
NOT_EQUAL = "notEqual"
GREATER_THAN = "greaterThan"
GREATER_THAN_EQUAL = "greaterThanEqual"
LESS_THAN = "lessThan"
LESS_THAN_EQUAL = "lessThanEqual"
CONTAINS = "contains"
IS_NULL = "isNull"
IS_NOT_NULL = "isNotNull"


class Operator():
def __init__(self, method, values=None):
self.method = method

if values is not None:
self.values = values if isinstance(values, list) else [values]

def __str__(self):
return json.dumps(
self.__dict__,
separators=(",", ":"),
default=lambda obj: obj.__dict__
)

@staticmethod
def increment(value=1, max=None):
if isinstance(value, float) and (math.isnan(value) or math.isinf(value)):
raise ValueError("Value cannot be NaN or Infinity")
if max is not None and isinstance(max, float) and (math.isnan(max) or math.isinf(max)):
raise ValueError("Max cannot be NaN or Infinity")
values = [value]
if max is not None:
values.append(max)
return str(Operator("increment", values))

@staticmethod
def decrement(value=1, min=None):
if isinstance(value, float) and (math.isnan(value) or math.isinf(value)):
raise ValueError("Value cannot be NaN or Infinity")
if min is not None and isinstance(min, float) and (math.isnan(min) or math.isinf(min)):
raise ValueError("Min cannot be NaN or Infinity")
values = [value]
if min is not None:
values.append(min)
return str(Operator("decrement", values))

@staticmethod
def multiply(factor, max=None):
if isinstance(factor, float) and (math.isnan(factor) or math.isinf(factor)):
raise ValueError("Factor cannot be NaN or Infinity")
if max is not None and isinstance(max, float) and (math.isnan(max) or math.isinf(max)):
raise ValueError("Max cannot be NaN or Infinity")
values = [factor]
if max is not None:
values.append(max)
return str(Operator("multiply", values))

@staticmethod
def divide(divisor, min=None):
if isinstance(divisor, float) and (math.isnan(divisor) or math.isinf(divisor)):
raise ValueError("Divisor cannot be NaN or Infinity")
if min is not None and isinstance(min, float) and (math.isnan(min) or math.isinf(min)):
raise ValueError("Min cannot be NaN or Infinity")
if divisor == 0:
raise ValueError("Divisor cannot be zero")
values = [divisor]
if min is not None:
values.append(min)
return str(Operator("divide", values))

@staticmethod
def modulo(divisor):
if isinstance(divisor, float) and (math.isnan(divisor) or math.isinf(divisor)):
raise ValueError("Divisor cannot be NaN or Infinity")
if divisor == 0:
raise ValueError("Divisor cannot be zero")
return str(Operator("modulo", [divisor]))

@staticmethod
def power(exponent, max=None):
if isinstance(exponent, float) and (math.isnan(exponent) or math.isinf(exponent)):
raise ValueError("Exponent cannot be NaN or Infinity")
if max is not None and isinstance(max, float) and (math.isnan(max) or math.isinf(max)):
raise ValueError("Max cannot be NaN or Infinity")
values = [exponent]
if max is not None:
values.append(max)
return str(Operator("power", values))

@staticmethod
def array_append(values):
return str(Operator("arrayAppend", values))

@staticmethod
def array_prepend(values):
return str(Operator("arrayPrepend", values))

@staticmethod
def array_insert(index, value):
return str(Operator("arrayInsert", [index, value]))

@staticmethod
def array_remove(value):
return str(Operator("arrayRemove", [value]))

@staticmethod
def array_unique():
return str(Operator("arrayUnique", []))

@staticmethod
def array_intersect(values):
return str(Operator("arrayIntersect", values))

@staticmethod
def array_diff(values):
return str(Operator("arrayDiff", values))

@staticmethod
def array_filter(condition, value=None):
values = [condition.value if isinstance(condition, Condition) else condition, value]
return str(Operator("arrayFilter", values))

@staticmethod
def string_concat(value):
return str(Operator("stringConcat", [value]))

@staticmethod
def string_replace(search, replace):
return str(Operator("stringReplace", [search, replace]))

@staticmethod
def toggle():
return str(Operator("toggle", []))

@staticmethod
def date_add_days(days):
return str(Operator("dateAddDays", [days]))

@staticmethod
def date_sub_days(days):
return str(Operator("dateSubDays", [days]))

@staticmethod
def date_set_now():
return str(Operator("dateSetNow", []))
12 changes: 6 additions & 6 deletions appwrite/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,27 +125,27 @@ def not_ends_with(attribute, value):

@staticmethod
def created_before(value):
return str(Query("createdBefore", None, value))
return Query.less_than("$createdAt", value)

@staticmethod
def created_after(value):
return str(Query("createdAfter", None, value))
return Query.greater_than("$createdAt", value)

@staticmethod
def created_between(start, end):
return str(Query("createdBetween", None, [start, end]))
return Query.between("$createdAt", start, end)

@staticmethod
def updated_before(value):
return str(Query("updatedBefore", None, value))
return Query.less_than("$updatedAt", value)

@staticmethod
def updated_after(value):
return str(Query("updatedAfter", None, value))
return Query.greater_than("$updatedAt", value)

@staticmethod
def updated_between(start, end):
return str(Query("updatedBetween", None, [start, end]))
return Query.between("$updatedAt", start, end)

@staticmethod
def or_queries(queries):
Expand Down
10 changes: 8 additions & 2 deletions appwrite/services/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,16 @@ def update_email(self, email: str, password: str) -> Dict[str, Any]:
'content-type': 'application/json',
}, api_params)

def list_identities(self, queries: Optional[List[str]] = None) -> Dict[str, Any]:
def list_identities(self, queries: Optional[List[str]] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
Get the list of identities for the currently logged in user.

Parameters
----------
queries : Optional[List[str]]
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -143,6 +145,7 @@ def list_identities(self, queries: Optional[List[str]] = None) -> Dict[str, Any]
api_params = {}

api_params['queries'] = queries
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down Expand Up @@ -201,14 +204,16 @@ def create_jwt(self) -> Dict[str, Any]:
'content-type': 'application/json',
}, api_params)

def list_logs(self, queries: Optional[List[str]] = None) -> Dict[str, Any]:
def list_logs(self, queries: Optional[List[str]] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.

Parameters
----------
queries : Optional[List[str]]
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -225,6 +230,7 @@ def list_logs(self, queries: Optional[List[str]] = None) -> Dict[str, Any]:
api_params = {}

api_params['queries'] = queries
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down
25 changes: 20 additions & 5 deletions appwrite/services/databases.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def __init__(self, client) -> None:
super(Databases, self).__init__(client)

@deprecated("This API has been deprecated since 1.8.0. Please use `tablesDB.list` instead.")
def list(self, queries: Optional[List[str]] = None, search: Optional[str] = None) -> Dict[str, Any]:
def list(self, queries: Optional[List[str]] = None, search: Optional[str] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.

Expand All @@ -24,6 +24,8 @@ def list(self, queries: Optional[List[str]] = None, search: Optional[str] = None
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name
search : Optional[str]
Search term to filter your list results. Max length: 256 chars.
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -41,6 +43,7 @@ def list(self, queries: Optional[List[str]] = None, search: Optional[str] = None

api_params['queries'] = queries
api_params['search'] = search
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down Expand Up @@ -397,7 +400,7 @@ def delete(self, database_id: str) -> Dict[str, Any]:
}, api_params)

@deprecated("This API has been deprecated since 1.8.0. Please use `tablesDB.list_tables` instead.")
def list_collections(self, database_id: str, queries: Optional[List[str]] = None, search: Optional[str] = None) -> Dict[str, Any]:
def list_collections(self, database_id: str, queries: Optional[List[str]] = None, search: Optional[str] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.

Expand All @@ -411,6 +414,8 @@ def list_collections(self, database_id: str, queries: Optional[List[str]] = None
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity
search : Optional[str]
Search term to filter your list results. Max length: 256 chars.
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -432,6 +437,7 @@ def list_collections(self, database_id: str, queries: Optional[List[str]] = None

api_params['queries'] = queries
api_params['search'] = search
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down Expand Up @@ -630,7 +636,7 @@ def delete_collection(self, database_id: str, collection_id: str) -> Dict[str, A
}, api_params)

@deprecated("This API has been deprecated since 1.8.0. Please use `tablesDB.list_columns` instead.")
def list_attributes(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None) -> Dict[str, Any]:
def list_attributes(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
List attributes in the collection.

Expand All @@ -644,6 +650,8 @@ def list_attributes(self, database_id: str, collection_id: str, queries: Optiona
Collection ID.
queries : Optional[List[str]]
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -668,6 +676,7 @@ def list_attributes(self, database_id: str, collection_id: str, queries: Optiona
api_path = api_path.replace('{collectionId}', collection_id)

api_params['queries'] = queries
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down Expand Up @@ -2356,7 +2365,7 @@ def update_relationship_attribute(self, database_id: str, collection_id: str, ke
}, api_params)

@deprecated("This API has been deprecated since 1.8.0. Please use `tablesDB.list_rows` instead.")
def list_documents(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None, transaction_id: Optional[str] = None) -> Dict[str, Any]:
def list_documents(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None, transaction_id: Optional[str] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
Get a list of all the user's documents in a given collection. You can use the query params to filter your results.

Expand All @@ -2372,6 +2381,8 @@ def list_documents(self, database_id: str, collection_id: str, queries: Optional
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.
transaction_id : Optional[str]
Transaction ID to read uncommitted changes within the transaction.
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -2397,6 +2408,7 @@ def list_documents(self, database_id: str, collection_id: str, queries: Optional

api_params['queries'] = queries
api_params['transactionId'] = transaction_id
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down Expand Up @@ -3000,7 +3012,7 @@ def increment_document_attribute(self, database_id: str, collection_id: str, doc
}, api_params)

@deprecated("This API has been deprecated since 1.8.0. Please use `tablesDB.list_indexes` instead.")
def list_indexes(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None) -> Dict[str, Any]:
def list_indexes(self, database_id: str, collection_id: str, queries: Optional[List[str]] = None, total: Optional[bool] = None) -> Dict[str, Any]:
"""
List indexes in the collection.

Expand All @@ -3014,6 +3026,8 @@ def list_indexes(self, database_id: str, collection_id: str, queries: Optional[L
Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).
queries : Optional[List[str]]
Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error
total : Optional[bool]
When set to false, the total count returned will be 0 and will not be calculated.

Returns
-------
Expand All @@ -3038,6 +3052,7 @@ def list_indexes(self, database_id: str, collection_id: str, queries: Optional[L
api_path = api_path.replace('{collectionId}', collection_id)

api_params['queries'] = queries
api_params['total'] = total

return self.client.call('get', api_path, {
}, api_params)
Expand Down
Loading