Skip to content

Commit

Permalink
initial support for dictionary access to rset lines
Browse files Browse the repository at this point in the history
  • Loading branch information
joamag committed Nov 27, 2014
1 parent f1a8790 commit 490d6b2
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 1 deletion.
68 changes: 67 additions & 1 deletion data/src/entity_manager/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4632,6 +4632,9 @@ class rset(list):
"""
Specialized list that provides a series of utilities
to handle a result set oriented chunk of data.
It provides features such as order and header management
useful for ordered management of large chunks of data.
"""

header_set = False
Expand Down Expand Up @@ -4894,7 +4897,7 @@ def set(self, line, name, value):
def map(self):
"""
Converts the current result set structure into a list
o maps with key values represented by the header names.
of maps with key values represented by the header names.
This is an expensive operation as all the lines composing
the result set data will be replicated as maps.
Expand Down Expand Up @@ -4941,6 +4944,36 @@ def map(self):
# result set structure to the caller method
return map_set

def add_h(self, name, nullify = False):
"""
Adds a new header to the current set, note that in case
the provided nullify parameter is provided the data is
changed so that such header is set to an invalid value.
Note that the "new" header is added to the end of the
current set of headers (default option).
@type name: String
@param name: The name of the header that is going to be
added (as a plain string).
@type nullify: bool
@param nullify: If the values in the data should be set
as invalid for the new header (avoid corruption).
"""

# retrieves the current header value (as a sequence) and
# adds the name name into it, recomputing the new header
# hash value from the length of the current header sequence
header = self.header()
header.append(name)
self.header_h[name] = len(header) - 1

# in case the nullify value was not set returns immediately
# otherwise invalidates the last values of the complete set
# of data lines/items (as expected)
if not nullify: return
for item in self.data(): item.append(None)

def rename_h(self, old, new):
"""
Renames the provided header name to a new one.
Expand Down Expand Up @@ -5029,6 +5062,21 @@ def extend_h(self, names):
header.extend(names)
self._hash_h()

def rdict_iter(self):
"""
Returns a generator like object that is able to percolate
over the complete set of elements in the rset providing
object like interactions with the contained sequences.
@rtype: Generator
@return: The generator that may be used to percolate over
the rset with an associative interaction with the values.
"""

# iterates over the complete set of lines of the current
# data yielding the created result dictionary for such line
for line in self.data(): yield rdict(self, line)

def _hash_h(self):
"""
Computes an hash map associating the index position
Expand All @@ -5044,6 +5092,24 @@ def _hash_h(self):
self.header_h[name] = index
index += 1

class rdict(dict):
"""
Specialized dictionary structure that provides a key
to value interaction on a line of a result set, this
allows for easy access at the cost of performance.
"""

def __init__(self, rset, line):
self.rset = rset
self.line = line
header = rset.header()
for key, value in zip(header, line):
dict.__setitem__(self, key, value)

def __setitem__(self, key, value):
if not key in self.rset.header_h: self.rset.add_h(key, nullify = True)
self.rset.set(self.line, key, value)

def load_serializers():
"""
Loads the various serializer objects according
Expand Down
47 changes: 47 additions & 0 deletions data/src/entity_manager/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

import colony

from . import structures
from . import exceptions
from . import test_mocks

Expand All @@ -50,6 +51,7 @@ class EntityManagerTest(colony.Test):
def get_bundle(self):
return (
EntityManagerBaseTestCase,
EntityManagerRsetTestCase
)

def set_up(self, test_case):
Expand Down Expand Up @@ -1499,3 +1501,48 @@ def test_normalize_options(self):
),
order_by = (("dogs.enemies.name", "descending"),)
))

class EntityManagerRsetTestCase(colony.ColonyTestCase):

@staticmethod
def get_description():
return "Entity Manager Rset Plugin test case"

def test_simple(self):
first_set = structures.rset([["First", 30]])
first_set.set_h(["name", "age"])

result = first_set.header()
self.assertEqual(result, ["name", "age"])

result = first_set.data()
self.assertEqual(result, [["First", 30]])

second_set = structures.rset([["Second", 24]])
second_set.set_h(["name", "age"])

first_set.join(second_set)

first_set.sort_set("age")

result = first_set.data()
self.assertEqual(result, [["Second", 24], ["First", 30]])

def test_rdict(self):
set = structures.rset([["First", 30], ["Second", 30]])
set.set_h(["name", "age"])

iterator = set.rdict_iter()
iterator = list(iterator)

first = iterator[0]
self.assertEqual(first["name"], "First")
self.assertEqual(first["age"], 30)

for line in iterator: line["salary"] = 100

result = set.header()
self.assertEqual(result, ["name", "age", "salary"])

result = set.data()
self.assertEqual(result, [["First", 30, 100], ["Second", 30, 100]])

0 comments on commit 490d6b2

Please sign in to comment.