def test_intersection(self): self.assertJson(query.intersection(), '{"intersection":[]}') self.assertJson(query.intersection(query.index("widget")), '{"intersection":{"index":"widget"}}') self.assertJson( query.intersection(query.index("widget"), query.index("things")), '{"intersection":[{"index":"widget"},{"index":"things"}]}')
def build_document_set_intersection( table: sql.Table, filter_group: typing.Optional[sql.FilterGroup]) -> QueryExpression: """Build FQL match query based on intersection of filtered results from given group. Params: ------- table: A Table object associated with a Fauna collection. filter_group: A group of filters representing an intersection of filtered results. Returns: -------- FQL query expression that matches on the same conditions as the Table's filters. """ filter_group_filters = [] if filter_group is None else filter_group.filters group_filter_names = [ sql_filter.name for sql_filter in filter_group_filters ] filters = [ sql_filter for sql_filter in table.filters if sql_filter.name in group_filter_names ] if not any(filters): return q.intersection(q.match(q.index(index_name(table.name)))) document_sets = [ _define_match_set(query_filter) for query_filter in filters ] return q.intersection(*document_sets)
def _fetch_column_info_refs(table_name: str, column_name: str): convert_to_collection_ref_set = functools.partial( fql.convert_to_ref_set, "information_schema_columns_") return q.intersection( convert_to_collection_ref_set( q.range( q.match( q.index( fql.index_name( "information_schema_columns_", column_name="table_name_", index_type=fql.IndexType.VALUE, ))), table_name, table_name, ), ), convert_to_collection_ref_set( q.range( q.match( q.index( fql.index_name( "information_schema_columns_", column_name="name_", index_type=fql.IndexType.VALUE, )), ), column_name, column_name, ), ), )
def _build_intersecting_query( filter_group: sql.FilterGroup, acc_query: typing.Optional[QueryExpression], table: sql.Table, direction: str, ) -> QueryExpression: opposite_direction = "left" if direction == "right" else "right" document_set = build_document_set_intersection(table, filter_group) if acc_query is None: intersection = document_set else: intersection = q.intersection(acc_query, document_set) next_table = getattr(table, f"{direction}_join_table") if next_table is None or table.has_columns: return intersection next_join_key = getattr(table, f"{direction}_join_key") assert next_join_key is not None if next_join_key.name == "ref": next_foreign_key = getattr(next_table, f"{opposite_direction}_join_key") assert next_foreign_key is not None return _build_intersecting_query( filter_group, q.join( intersection, q.index( index_name( next_table.name, column_name=next_foreign_key.name, index_type=IndexType.REF, )), ), next_table, direction, ) return _build_intersecting_query( filter_group, q.join( intersection, q.index( index_name( table.name, index_type=IndexType.REF, foreign_key_name=next_join_key.name, )), ), next_table, direction, )
def test_intersection(self): n_value = 102 m_value = 202 ref_nm = self._create(n=n_value, m=m_value)["ref"] self._create(n=n_value) self._create(m=m_value) q = query.intersection(query.match(self.n_index_ref, n_value), query.match(self.m_index_ref, m_value)) self.assertEqual(self._set_to_list(q), [ref_nm])
def join_collections(sql_query: sql.SQLQuery) -> QueryExpression: """Join together multiple collections to return their documents in the response. Params: ------- sql_query: SQLQuery object with information about the query params. Returns: -------- An FQL query expression for joined and filtered documents. """ tables = sql_query.tables order_by = sql_query.order_by from_table = tables[0] to_table = tables[-1] table_with_columns = next(table for table in tables if table.has_columns) if (order_by is not None and order_by.columns[0].table_name != table_with_columns.name): raise exceptions.NotSupportedError( "Fauna uses indexes for both joining and ordering of results, " "and we currently can only sort the principal table " "(i.e. the one whose columns are being selected or modified) in the query. " "You can sort on a column from the principal table, query one table at a time, " "or remove the ordering constraint.") if not any(sql_query.filter_groups): raise exceptions.NotSupportedError( "Joining tables without cross-table filters via the WHERE clause is not supported. " "Selecting columns from multiple tables is not supported either, " "so there's no performance gain from joining tables without cross-table conditions " "for filtering query results.") assert from_table.left_join_table is None intersection_queries = [] for filter_group in sql_query.filter_groups: intersection_query = q.intersection(*[ _build_intersecting_query(filter_group, None, table, direction) for table, direction in [(from_table, "right"), (to_table, "left")] ]) intersection_queries.append(intersection_query) return q.union(*intersection_queries)
def get_products(name=None, category=None, sort_by=None, size=5, after=None, before=None): sortDic = { "price_asc": q.index('products_sort_by_price_asc'), "price_desc": q.index('products_sort_by_price_desc'), "name_asc": q.index('products_sort_by_name_asc'), 'created_at_asc': q.index('products_sort_by_created_asc') } matches = [] if(name): matches.append(q.match(q.index('products_search_by_name'), name)) if(category): matches.append(q.match( q.index('products_search_by_category'), q.ref(q.collection('categories'), category) )) if(len(matches) == 0): matches.append(q.documents(q.collection('products'))) return fauna.query( q.map_( lambda _, ref: q.get(ref), q.paginate( q.join( q.intersection(matches), sortDic[sort_by or 'name_asc'] ), size=size, after=after, before=before ) ) )