diff --git a/sandbox/grist/engine.py b/sandbox/grist/engine.py index 1e2dae2e..b9cf0b21 100644 --- a/sandbox/grist/engine.py +++ b/sandbox/grist/engine.py @@ -388,9 +388,27 @@ class Engine(object): query_cols = [] if query: - query_cols = [(table.get_column(col_id), values) for (col_id, values) in six.iteritems(query)] - row_ids = [r for r in table.row_ids - if all((c.raw_get(r) in values) for (c, values) in query_cols)] + for col_id, values in six.iteritems(query): + col = table.get_column(col_id) + try: + # Try to use a set for speed. + values = set(values) + except TypeError: + # Values contains an unhashable value, leave it as a list. + pass + query_cols.append((col, values)) + row_ids = [] + for r in table.row_ids: + for (c, values) in query_cols: + try: + if c.raw_get(r) not in values: + break + except TypeError: + # values is a set but c.raw_get(r) is unhashable, so it's definitely not in values + break + else: + # No break, i.e. all columns matched + row_ids.append(r) for c in six.itervalues(table.all_columns): # pylint: disable=too-many-boolean-expressions diff --git a/sandbox/grist/test_engine.py b/sandbox/grist/test_engine.py index c99647b0..ae3a5756 100644 --- a/sandbox/grist/test_engine.py +++ b/sandbox/grist/test_engine.py @@ -557,6 +557,30 @@ class TestEngine(EngineTestCase): self.assertEqualDocData({'Address': data}, {'Address': testutil.table_data_from_rows('Address', col_names, [])}) + # Test unhashable values in the column and in the query + self.add_column('Address', 'list', type='Any', isFormula=True, + formula='[1] if $id == 21 else 2') + col_names.append('list') + + data = self.engine.fetch_table('Address', query={'list': [[1]]}) + self.assertEqualDocData({'Address': data}, + {'Address': testutil.table_data_from_rows('Address', col_names, [ + [ 21, "New York", "NY" , 1, [1]], + ])}) + + data = self.engine.fetch_table('Address', query={'list': [2]}) + self.assertEqualDocData({'Address': data}, + {'Address': testutil.table_data_from_rows('Address', col_names, [ + [ 22, "Albany", "NY" , 2, 2], + ])}) + + data = self.engine.fetch_table('Address', query={'list': [[1], 2]}) + self.assertEqualDocData({'Address': data}, + {'Address': testutil.table_data_from_rows('Address', col_names, [ + [ 21, "New York", "NY" , 1, [1]], + [ 22, "Albany", "NY" , 2, 2], + ])}) + def test_schema_restore_on_error(self): # Simulate an error inside a DocAction, and make sure we restore the schema (don't leave it in # inconsistent with metadata).