Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow polymorph objects #46

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
*.pyc
*.pyo
*.egg-info
*.code-workspace
.idea
dist
build/
doc/_build/
venv/
.vscode/
debug.py
46 changes: 25 additions & 21 deletions odata/navproperty.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,25 @@ def __init__(self, name, entitycls, collection=False, foreign_key=None):
def __repr__(self):
return u'<NavigationProperty to {0}>'.format(self.entitycls)

def instances_from_data(self, raw_data):
def instances_from_data(self, raw_data, connection):
if self.is_collection:
return [self.entitycls.__new__(self.entitycls, from_data=d) for d in raw_data]
return [self.instance_from_data(d, connection) for d in raw_data['value']] if raw_data['value'] else []
else:
return self.entitycls.__new__(self.entitycls, from_data=raw_data)

return self.instance_from_data(raw_data, connection) if raw_data else None

def instance_from_data(self, raw_data, connection): # mwa: this needs to be seperated form navproperty
entitycls = self._getClass_by_response_type(self.entitycls, raw_data.get('@odata.type'))
e = entitycls.__new__(entitycls, from_data=raw_data)
es = e.__odata__
es.connection = connection
return e

def _getClass_by_response_type(self, matched_class, odata_type):
if not odata_type: return matched_class
for subclass in matched_class.__subclasses__():
if subclass.__odata_type__ == odata_type[1:]: return self._getClass_by_response_type(subclass, odata_type)
return matched_class

def _get_parent_cache(self, instance):
es = instance.__odata__
ic = es.nav_cache
Expand Down Expand Up @@ -102,20 +115,11 @@ def __get__(self, instance, owner):

parent_url += '/'
url = urljoin(parent_url, self.name)

if self.is_collection:
if 'collection' not in cache:
raw_data = connection.execute_get(url)
if raw_data:
cache['collection'] = self.instances_from_data(raw_data['value'])
else:
cache['collection'] = []
return cache['collection']
else:
if 'single' not in cache:
raw_data = connection.execute_get(url)
if raw_data:
cache['single'] = self.instances_from_data(raw_data)
else:
cache['single'] = None
return cache['single']
cache_type = 'collection' if self.is_collection else 'single'

try:
return cache[cache_type]
except KeyError:
raw_data = connection.execute_get(url)
cache[cache_type] = self.instances_from_data(raw_data, connection)
return cache[cache_type]
2 changes: 1 addition & 1 deletion odata/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __iter__(self):
for row in value:
yield self._create_model(row)

if '@odata.nextLink' in data:
if '@odata.nextLink' in data and not '$top' in options.keys(): #do not load next page on userpaging
url = urljoin(self.entity.__odata_url_base__, data['@odata.nextLink'])
options = {} # we get all options in the nextLink url
else:
Expand Down