Skip to content

Commit 6664937

Browse files
committed
version 20241027.1, deprecated datastore, welcome firestore
1 parent e204852 commit 6664937

File tree

7 files changed

+68
-16
lines changed

7 files changed

+68
-16
lines changed

pydal/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "20241020.1"
1+
__version__ = "20241027.1"
22

33
from .base import DAL
44
from .helpers.classes import SQLCustomType

pydal/adapters/google.py

+51-6
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,45 @@ def _find_work_folder(self):
106106
self.folder = os.path.relpath(self.folder, os.getcwd())
107107

108108

109+
# db = DAL("firestore") on Google App Engine
110+
# db = DAL("firestore://cred=credentials.json") everywhere else
111+
# (get credentials.json from google console)
112+
#
113+
# supports:
114+
# db(db.table).select(...)
115+
# db(db.table.id==id).select(...)
116+
# db(db.table.id>0).select(...)
117+
# db(db.table.field==value).select(...)
118+
# db(db.table.field!=value).select(...)
119+
# db(db.table.field>value).select(...)
120+
# db(db.table.field<value).select(...)
121+
# db(db.table.field>=value).select(...)
122+
# db(db.table.field<=value).select(...)
123+
# db(db.table.field.belnogs(values)).select(...)
124+
# db(~db.table.field.belnogs(values)).select(...)
125+
# db(simple_query1|simple_query2|simple_query3).select(...)
126+
# db(simple_query1&simple_query2&simple_query3).select(...)
127+
# db(or_query1&or_query2&or_query3).select(...)
128+
# db.table(id)
129+
# db.table(field1=value, field2=value)
130+
# db.table(id, field1=value, field2=value)
131+
# db(...).delete()
132+
# db(...).update(...) but only reliable when updating one or a few records
133+
#
134+
# does not support:
135+
# - joins
136+
# - transaction
137+
# - composition of queries involving field id
138+
# - or of and such as db(query1|(query2&query2))
139+
# - db.table.field.contains(...)
140+
# - db.table.field.like(...)
141+
# - db.table.field.startswith(...)
142+
# - non-zero offset such as select(limitby=(3,7))
143+
#
144+
# supports but unreliable
145+
# db(...).update(...) for many records
146+
147+
109148
@adapters.register_for("firestore")
110149
class Firestore(NoSQLAdapter):
111150
dbengine = "firestore"
@@ -174,6 +213,8 @@ def apply_filter(self, source, table, query):
174213
if isinstance(query, Query) and query.first is table._id:
175214
if query.op.__name__ == "eq":
176215
return source.document(str(query.second)).get()
216+
elif isinstance(query, Table):
217+
return source
177218
elif query.op.__name__ == "gt" and query.second == 0:
178219
return source
179220
raise RuntimeError("operator not supported")
@@ -265,6 +306,9 @@ def count(self, query, distinct=None, limit=None):
265306
table = self.get_table(query)
266307
source = self._client.collection(table._tablename)
267308
source = self.apply_filter(source, table, query)
309+
# deal with the case or returning a single item which may be empty
310+
if not hasattr(source, "where"):
311+
return 1 if source.to_dict() else 0
268312
aggregate_query = aggregation.AggregationQuery(source)
269313
aggregate_query.count()
270314
results = aggregate_query.get()
@@ -274,12 +318,13 @@ def count(self, query, distinct=None, limit=None):
274318

275319
def delete(self, table, query):
276320
counter = 0
277-
docs = list(self.get_docs(table, query))
278-
batch = self._client.batch()
279-
for doc in docs:
280-
batch.delete(doc.reference)
281-
counter += 1
282-
batch.commit()
321+
while self.db(query).count() > 0:
322+
docs = list(self.get_docs(table, query))
323+
batch = self._client.batch()
324+
for doc in docs:
325+
batch.delete(doc.reference)
326+
counter += 1
327+
batch.commit()
283328
return counter
284329

285330
def update(self, table, query, update_fields):

pydal/dialects/google.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ def comma(self, first, second, query_env={}):
4949
raise NotImplementedError
5050

5151
def belongs(self, first, second, query_env={}):
52-
return FieldFilter(first.name, "in", [[item] for item in second])
52+
return FieldFilter(first.name, "in", second)
5353

5454
def contains(self, first, second, case_sensitive=True, query_env={}):
55-
return FieldFilter(first.name, "array-contains", second)
55+
raise NotImplementedError
5656

5757
def _not(self, val, query_env={}):
5858
op, f, s = val.op, val.first, val.second
@@ -71,6 +71,8 @@ def _not(self, val, query_env={}):
7171
rv = FieldFilter(f.name, "<=", s)
7272
elif op == self.gte:
7373
rv = FieldFilter(f.name, "<", s)
74+
elif op == self.belongs:
75+
rv = FieldFilter(f.name, "not-in", s)
7476
else:
7577
# TODO the IN operator must be split into a sequence of
7678
# (field!=value) AND (field!=value) AND ...

pydal/helpers/classes.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,14 @@ def as_yaml(self, sanitize=True):
189189
return serializers.yaml(self.as_dict(flat=True, sanitize=sanitize))
190190

191191

192-
class Reference(long):
192+
class Reference(int):
193193
def __allocate(self):
194194
if not self._record:
195-
self._record = self._table[long(self)]
195+
self._record = self._table[int(self)]
196196
if not self._record:
197197
raise RuntimeError(
198198
"Using a recursive select but encountered a broken "
199-
+ "reference: %s %d" % (self._table, long(self))
199+
+ "reference: %s %d" % (self._table, int(self))
200200
)
201201

202202
def __getattr__(self, key, default=None):

pydal/parsers/google.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import base64
22

33
from ..adapters.google import Firestore
4-
from . import Parser, before_parse, for_type, parsers
4+
from ..helpers.classes import Reference
5+
from . import before_parse, for_type, parsers
56
from .base import BasicParser, JSONParser
67

78

@@ -18,7 +19,7 @@ def _boolean(self, value):
1819
@for_type("id")
1920
def _id(self, value):
2021
if not isinstance(value, int):
21-
return int(value, 16)
22+
return int(value)
2223
return value
2324

2425
@for_type("json")
@@ -36,7 +37,7 @@ def reference_extras(self, field_type):
3637
@for_type("reference")
3738
def _reference(self, value, referee):
3839
if not isinstance(value, int):
39-
value = long(value, 16)
40+
value = int(value)
4041
if "." not in referee:
4142
value = Reference(value)
4243
value._table, value._record = self.adapter.db[referee], None

pydal/representers/google.py

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def _json(self, value):
2929
def _json(self, value):
3030
return base64.b64decode(value)
3131

32+
@for_type("reference")
33+
def _json(self, value):
34+
return str(value)
35+
3236
@for_type("list:integer")
3337
def _list_integer(self, value):
3438
if not isinstance(value, list):

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "pydal"
3-
version = "20241020.1"
3+
version = "20241027.1"
44
authors = [{ name="Massimo Di Pierro", email="massimo.dipierro@gmail.com" },]
55
description = 'pyDAL is a Database Abstraction Layer. It generates queries for SQlite, PotsgreSQL, MySQL, and other backends. It was originally part of the web2py frameworks but it is now an independent project. Example: db.define_table("thing",Field("name")) and db.thing.insert(name="Pizza")'
66
readme = "README.md"

0 commit comments

Comments
 (0)