Skip to content

Commit 06d9fe6

Browse files
authored
Merge pull request #17 from octabytes/feature
Feature
2 parents b9ed3fa + 3914581 commit 06d9fe6

File tree

12 files changed

+335
-24
lines changed

12 files changed

+335
-24
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# Versions should comply with PEP440. For a discussion on single-sourcing
1717
# the version across setup.py and the project code, see
1818
# https://packaging.python.org/en/latest/single_source_version.html
19-
version='0.2.0',
19+
version='0.3.0',
2020

2121
description="FireO ORM is specifically designed for the Google's Firestore",
2222
long_description=long_description,

src/fireo/fields/field_attribute.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ def parse(self, value, ignore_required=False):
7272

7373
# check this field is required or not
7474
if self.required and value is None and not ignore_required:
75-
raise RequiredField(f'"{self.field.__class__.__name__}" is required but received '
76-
f'no default and no value.')
75+
raise RequiredField(f'"{self.field.__class__.__name__}" is required for model {self.field.model_cls} '
76+
f'but received no default and no value.')
7777

7878
# check if there any custom validation provided by user
7979
if self.validator is not None:

src/fireo/managers/managers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ def create(self, mutable_instance=None, **kwargs,):
156156
field_list[f.name] = model_instance._get_fields()
157157
else:
158158
field_list[k] = v
159+
# Create instance for nested model
160+
for f in self.model_cls._meta.field_list.values():
161+
if isinstance(f, NestedModel):
162+
field_list[f.name] = f.nested_model()._get_fields()
159163
else:
160164
field_list = kwargs
161165

src/fireo/models/model.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ def __init__(self, *args, **kwargs):
134134
for k, v in kwargs.items():
135135
setattr(self, k, v)
136136

137+
# Create instance for nested model
138+
# for direct assignment to nested model
139+
for f in self._meta.field_list.values():
140+
if isinstance(f, fields.NestedModel):
141+
setattr(self, f.name, f.nested_model())
142+
137143
# Get all the fields values from meta
138144
# which are attached with this mode
139145
# and convert them into corresponding db value

src/fireo/queries/create_query.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from fireo.fields import NestedModel
12
from fireo.queries import query_wrapper
23
from fireo.queries.base_query import BaseQuery
4+
from fireo.utils import utils
35

46

57
class CreateQuery(BaseQuery):
@@ -84,10 +86,32 @@ class User(Model):
8486
in this case it will be like this
8587
`{full_name: "Azeem", age=25}`
8688
"""
87-
return {
88-
f.db_column_name: f.get_value(self.query.get(f.name))
89-
for f in self.model._meta.field_list.values()
90-
}
89+
field_list = {}
90+
for f in self.model._meta.field_list.values():
91+
if isinstance(f, NestedModel):
92+
self._nested_field_list(f, field_list, f.name)
93+
else:
94+
field_list[f.db_column_name] = f.get_value(self.query.get(f.name))
95+
return field_list
96+
97+
def _nested_field_list(self, f, fl, *name):
98+
"""Get Nested Fields"""
99+
required_nested_model = f.raw_attributes.get('required')
100+
if required_nested_model is None or required_nested_model is False:
101+
ignore_required = True
102+
else:
103+
ignore_required = False
104+
nested_field_list = {}
105+
for n_f in f.nested_model._meta.field_list.values():
106+
if isinstance(n_f, NestedModel):
107+
n = (*name, n_f.name)
108+
self._nested_field_list(n_f, nested_field_list, *n)
109+
else:
110+
nested_field_list[n_f.db_column_name] = n_f.get_value(
111+
utils.get_nested(self.query, *name).get(n_f.name),
112+
ignore_required
113+
)
114+
fl[f.db_column_name] = nested_field_list
91115

92116
def _raw_exec(self):
93117
"""save model into firestore and return the document"""

src/fireo/queries/filter_query.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from fireo.database import db
2+
from fireo.fields.errors import FieldNotFound
23
from fireo.queries import query_wrapper
34
from fireo.queries.base_query import BaseQuery
45
from fireo.queries.delete_query import DeleteQuery
@@ -110,7 +111,32 @@ def parse_where(self):
110111
else:
111112
self.cursor_dict['filters'] = [w]
112113

113-
f_name = self.model._meta.get_field(name).db_column_name
114+
# Check it is nested model field
115+
if '.' in name:
116+
# m, f = name.split('.')
117+
# model_field = self.model._meta.get_field(m)
118+
# model_name = model_field.db_column_name
119+
# nested_model = model_field.nested_model
120+
# field_name = nested_model._meta.get_field(f).db_column_name
121+
# f_name = model_name + '.' + field_name
122+
model_names = []
123+
nested_model = None
124+
*models, field = name.split('.')
125+
for m in models:
126+
try:
127+
model_field = self.model._meta.get_field(m)
128+
except FieldNotFound:
129+
model_field = nested_model._meta.get_field(m)
130+
131+
nested_model = model_field.nested_model
132+
name = model_field.db_column_name
133+
134+
model_names.append(name)
135+
model_name = '.'.join(model_names)
136+
field_name = nested_model._meta.get_field(field).db_column_name
137+
f_name = model_name + '.' + field_name
138+
else:
139+
f_name = self.model._meta.get_field(name).db_column_name
114140
filters.append((f_name, op, val))
115141
return filters
116142

src/fireo/queries/update_query.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from fireo.fields import NestedModel
22
from fireo.queries import query_wrapper
33
from fireo.queries.base_query import BaseQuery
4+
from fireo.utils import utils
45

56

67
class UpdateQuery(BaseQuery):
@@ -51,25 +52,27 @@ class User(Model):
5152
# Check if it is nested model
5253
if isinstance(f, NestedModel):
5354
# Get nested model field
54-
for nested_f in f.nested_model._meta.field_list.values():
55-
v = nested_f.get_value(self.query.get(f.name+"."+nested_f.name), ignore_required=True)
56-
if v:
57-
# create the name with parent field name and child name
58-
# For example:
59-
# class User(Model):
60-
# address = TextField()
61-
# class Student(Model):
62-
# age = NumberField()
63-
# user = NestedModel(User)
64-
#
65-
# Then the field name for nested model will be "user.address"
66-
field_dict[f.db_column_name+"."+nested_f.db_column_name] = v
55+
self._nested_field_list(f, field_dict, f.name)
6756
else:
6857
v = f.get_value(self.query.get(f.name), ignore_required=True)
6958
if v:
7059
field_dict[f.db_column_name] = v
7160
return field_dict
7261

62+
def _nested_field_list(self, f, fl, *name):
63+
"""Get Nested Fields"""
64+
nested_field_list = {}
65+
for n_f in f.nested_model._meta.field_list.values():
66+
if isinstance(n_f, NestedModel):
67+
n = (*name, n_f.name)
68+
self._nested_field_list(n_f, nested_field_list, *n)
69+
else:
70+
nested_field_list[n_f.db_column_name] = n_f.get_value(
71+
utils.get_nested(self.query, *name).get(n_f.name),
72+
ignore_required=True
73+
)
74+
fl[f.db_column_name] = nested_field_list
75+
7376
def _raw_exec(self):
7477
"""Update document in firestore and return the document"""
7578
ref = self._doc_ref()

src/fireo/utils/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,12 @@ def get_id(key):
3131

3232

3333
def GeoPoint(latitude: float, longitude: float):
34-
return firestore.GeoPoint(latitude, longitude)
34+
return firestore.GeoPoint(latitude, longitude)
35+
36+
37+
def get_nested(dict, *args):
38+
if args and dict:
39+
element = args[0]
40+
if element:
41+
value = dict.get(element)
42+
return value if len(args) == 1 else get_nested(value, *args[1:])

src/tests/v020/test_cursor.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,10 @@ def test_parent_cursor_fetch():
9494

9595
for c in childs:
9696
assert utils.get_parent_doc(c.key) == parent_key
97-
assert c.age in [4,5,6]
97+
assert c.age in [4,5,6]
98+
99+
100+
def test_delete_all_cursor_fetch():
101+
CursorPages.collection.delete()
102+
CursorParentFetch.collection.delete()
103+
CursorChildFetch.collection.delete()

src/tests/v020/test_next_fetch.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,8 @@ def test_fetch_without_next():
9797
assert page.name in page_list
9898
index += 1
9999

100-
assert index == 6
100+
assert index == 6
101+
102+
103+
def test_delete_all_next_fetch():
104+
NextFetchModel.collection.delete()

0 commit comments

Comments
 (0)