/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.test.it.qp; import com.foundationdb.qp.operator.Cursor; import com.foundationdb.qp.operator.Operator; import com.foundationdb.qp.row.Row; import com.foundationdb.qp.rowtype.AisRowType; import com.foundationdb.qp.rowtype.RowType; import com.foundationdb.qp.rowtype.Schema; import com.foundationdb.qp.rowtype.TableRowType; import org.junit.Test; import java.util.Collections; import java.util.HashSet; import java.util.Set; import static com.foundationdb.qp.operator.API.*; public class FilterIT extends OperatorITBase { @Override protected void setupPostCreateSchema() { super.setupPostCreateSchema(); Row[] dbWithOrphans = new Row[]{ row(customer, 1L, "northbridge"), row(customer, 2L, "foundation"), row(address, 1001L, 1L, "111 1111 st"), row(address, 1002L, 1L, "111 2222 st"), row(address, 2001L, 2L, "222 1111 st"), row(address, 2002L, 2L, "222 2222 st"), row(order, 11L, 1L, "ori"), row(order, 12L, 1L, "david"), row(order, 21L, 2L, "tom"), row(order, 22L, 2L, "jack"), row(item, 111L, 11L), row(item, 112L, 11L), row(item, 121L, 12L), row(item, 122L, 12L), row(item, 211L, 21L), row(item, 212L, 21L), row(item, 221L, 22L), row(item, 222L, 22L) }; use(dbWithOrphans); } // Test argument validation @Test(expected = IllegalArgumentException.class) public void testNullKeepTypes() { filter_Default(groupScan_Default(coi), null); } @Test(expected = IllegalArgumentException.class) public void testEmptyKeepTypes() { filter_Default(groupScan_Default(coi), Collections.<RowType>emptySet()); } // Test operator execution (former Cut tests) @Test public void testCutBelowCustomer() { Operator plan = filter_Default(groupScan_Default(coi), removeDescendentTypes(customerRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(customerRowType, 1L, "northbridge"), row(customerRowType, 2L, "foundation") }; compareRows(expected, cursor); } @Test public void testCutBelowOrder() { Operator plan = filter_Default(groupScan_Default(coi), removeDescendentTypes(orderRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(customerRowType, 1L, "northbridge"), row(orderRowType, 11L, 1L, "ori"), row(orderRowType, 12L, 1L, "david"), row(addressRowType, 1001L, 1L, "111 1111 st"), row(addressRowType, 1002L, 1L, "111 2222 st"), row(customerRowType, 2L, "foundation"), row(orderRowType, 21L, 2L, "tom"), row(orderRowType, 22L, 2L, "jack"), row(addressRowType, 2001L, 2L, "222 1111 st"), row(addressRowType, 2002L, 2L, "222 2222 st") }; compareRows(expected, cursor); } @Test public void testCutBelowItem() { Operator plan = filter_Default(groupScan_Default(coi), removeDescendentTypes(itemRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(customerRowType, 1L, "northbridge"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(addressRowType, 1001L, 1L, "111 1111 st"), row(addressRowType, 1002L, 1L, "111 2222 st"), row(customerRowType, 2L, "foundation"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(addressRowType, 2001L, 2L, "222 1111 st"), row(addressRowType, 2002L, 2L, "222 2222 st") }; compareRows(expected, cursor); } @Test public void testCutBelowAddress() { Operator plan = filter_Default(groupScan_Default(coi), removeDescendentTypes(addressRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(customerRowType, 1L, "northbridge"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(addressRowType, 1001L, 1L, "111 1111 st"), row(addressRowType, 1002L, 1L, "111 2222 st"), row(customerRowType, 2L, "foundation"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(addressRowType, 2001L, 2L, "222 1111 st"), row(addressRowType, 2002L, 2L, "222 2222 st") }; compareRows(expected, cursor); } // Test operator execution (former extract tests) @Test public void testExtractRoot() { Operator plan = filter_Default(groupScan_Default(coi), typeAndDescendents(customerRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(customerRowType, 1L, "northbridge"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(addressRowType, 1001L, 1L, "111 1111 st"), row(addressRowType, 1002L, 1L, "111 2222 st"), row(customerRowType, 2L, "foundation"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(addressRowType, 2001L, 2L, "222 1111 st"), row(addressRowType, 2002L, 2L, "222 2222 st"), }; compareRows(expected, cursor); } @Test public void testExtractLeaf() { Operator plan = filter_Default(groupScan_Default(coi), typeAndDescendents(itemRowType)); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), }; compareRows(expected, cursor); } @Test public void testExtractSiblings() { Set<RowType> keepTypes = new HashSet<>(); keepTypes.addAll(typeAndDescendents(addressRowType)); keepTypes.addAll(typeAndDescendents(orderRowType)); Operator plan = filter_Default(groupScan_Default(coi), keepTypes); Cursor cursor = cursor(plan, queryContext, queryBindings); Row[] expected = new Row[]{ row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(addressRowType, 1001L, 1L, "111 1111 st"), row(addressRowType, 1002L, 1L, "111 2222 st"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(addressRowType, 2001L, 2L, "222 1111 st"), row(addressRowType, 2002L, 2L, "222 2222 st"), }; compareRows(expected, cursor); } // No test for cursor lifecycle needed -- tested in several other operator ITs, including // GroupScanIT.testCursor. private Set<TableRowType> removeDescendentTypes(AisRowType type) { Set<TableRowType> keepTypes = type.schema().userTableTypes(); keepTypes.removeAll(Schema.descendentTypes(type, keepTypes)); return keepTypes; } private Set<RowType> typeAndDescendents(RowType type) { Set<RowType> keepTypes= new HashSet<>(); keepTypes.addAll(Schema.descendentTypes(type, schema.userTableTypes())); keepTypes.add(type); return keepTypes; } }