package tests::DlfQueryTest; use strict; use base qw/ tests::TestStoreFixture Lire::Test::TestCase /; use Lire::DlfQuery; use Lire::DlfSchema; use Lire::ExtendedSchema; sub new { my $self = shift()->SUPER::new( @_ ); $self->init(); $self; } sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->set_up_test_schema(); $Lire::DlfSchema::SCHEMA_CACHE{'test-extended2'} = new Lire::ExtendedSchema( 'id' => 'test-extended2', 'base-schema' => 'test-derived', 'module' => 'MyModule' ); $self->{'query'} = new Lire::DlfQuery( 'test' ); return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); delete $Lire::DlfSchema::SCHEMA_CACHE{'test-extended2'}; $self->tear_down_test_store() if $self->{'store'}; $self->{'query'}->release(); return; } sub test_new { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_isa( 'Lire::DlfQuery', $query ); $self->assert_num_equals( 0, $query->{'_limit'} ); $self->assert_null( $query->{'_sort_spec'}, "'_sort_spec' attribute should be undef" ); $self->assert_null( $query->{'_order_by'}, "'_order_by' attribute should be undef" ); $self->assert_deep_equals( [], $query->{'_fields'} ); $self->assert_deep_equals( {}, $query->{'_field_refs'} ); $self->assert_deep_equals( [], $query->{'_filter_params'}); $self->assert_null( $query->{'_parent'}, "new query should have NULL parent" ); $self->assert_deep_equals( [], $query->{'_nested_queries'} ); $self->assert_null( $query->{'_filter_clause'}, "filter_clause attribute should be undef" ); $self->assert_str_equals( 'test', $query->{'_stream_name'} ); } sub test_new_bad_params { my $self = $_[0]; $self->assert_dies( qr/missing 'stream_name' parameter/, sub { new Lire::DlfQuery() } ); $self->assert_dies( qr/there is no schema 'wawa'/, sub { new Lire::DlfQuery( 'wawa' ) } ); } sub test__schema_has_field { my $self = $_[0]; $self->assert( $self->{'query'}->_schema_has_field( 'time_start' ) ); $self->assert( ! $self->{'query'}->_schema_has_field( 'dirname' ) ); $self->{'query'}{'_joined_streams'} = [ 'test-extended' ]; $self->assert( $self->{'query'}->_schema_has_field( 'dirname' ) ); } sub test__field_by_name { my $self = $_[0]; my $query = $self->{'query'}; $query->_add_field ('file', 'simple'); $self->assert_deep_equals ( { 'field' => 'file', 'type' => 'simple', 'alias' => undef }, $query->_field_by_name('file') ); $query->_add_field ('sum()', 'aggr', 'count'); $self->assert_deep_equals ( { 'field' => 'sum()', 'type' => 'aggr', 'alias' => 'count' }, $query->_field_by_name('count') ); } sub test__add_field { my $self = $_[0]; my $query = $self->{'query'}; $query->_add_field( 'time_start', 'simple' ); $self->assert( exists $query->{'_field_refs'}{'time_start'} ); $self->assert_deep_equals( [ { 'field' => 'time_start', 'alias' => undef, 'type' => 'simple' } ], $query->{'_fields'} ); $query->_add_field( 'count()', 'aggr', 'nrecords' ); $self->assert( exists $query->{'_field_refs'}{'nrecords'} ); $self->assert_deep_equals( [ { 'field' => 'time_start', 'alias' => undef, 'type' => 'simple' }, { 'field' => 'count()', 'alias' => 'nrecords', 'type' => 'aggr' } ], $query->{'_fields'} ); } sub test__add_field_bad_params { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_dies( qr/missing 'field' parameter/, sub { $query->_add_field() } ); $self->assert_dies( qr/missing 'type' parameter/, sub { $query->_add_field( 'a_field' ) } ); $self->assert_dies( qr/field name should contain only alphanumeric characters: 'a field'/, sub { $query->_add_field( 'a field', 'simple' ) } ); $self->assert_dies( qr/field name should contain only alphanumeric characters: 'sum\(\)'/, sub { $query->_add_field( 'sum()', 'aggr' ) } ); $self->assert_dies( qr/type should be 'simple', 'group', 'aggr': 'zoinzoin'/, sub { $query->_add_field( 'wawa', 'zoinzoin' ) } ); $self->assert_dies( qr/no field 'wawa' in 'test' schema/, sub { $query->_add_field( 'wawa', 'simple' ) } ); $self->assert_dies( qr/'nrecords' is already defined in the query/, sub { $query->_add_field( 'sum()', 'aggr', 'nrecords' ); $query->_add_field( 'sum()', 'aggr', 'nrecords' ) } ); } sub test__add_field_with_nested_query { my $self = $_[0]; my $query = $self->{'query'}; my $nested1 = $query->create_nested_query(); my $nested2 = $query->create_nested_query(); my $nested3 = $nested1->create_nested_query(); $query->_add_field( 'lr_timegroup(time_start)', 'group', 'period' ); $self->assert_dies( qr/'period' is already defined in the query/, sub { $nested1->_add_field( 'lr_timegroup(time_start)', 'group', 'period' ) } ); $self->assert_dies( qr/'period' is already defined in the query/, sub { $nested2->_add_field( 'lr_timegroup(time_start)', 'group', 'period' ) } ); $self->assert_dies( qr/'period' is already defined in the query/, sub { $nested3->_add_field( 'lr_timegroup(time_start)', 'group', 'period' ) } ); $nested1->_add_field( 'connection_id', 'simple' ); $self->assert_dies( qr/'connection_id' is already defined in the query/, sub { $query->_add_field( 'connection_id', 'simple' ) } ); $nested2->_add_field( 'connection_id', 'simple' ); $nested3->_add_field( 'file', 'simple' ); $self->assert_dies( qr/'file' is already defined in the query/, sub { $nested1->_add_field( 'file', 'simple' ) } ); } sub test_add_field { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'time_start' ); $self->assert_deep_equals( { 'field' => 'time_start', 'alias' => undef, 'type' => 'simple' }, $query->_field_by_name( 'time_start' ) ); $query->add_field( 'file', 'file_size/1024' ); $self->assert_deep_equals( { 'field' => 'file_size/1024', 'alias' => 'file', 'type' => 'simple' }, $query->_field_by_name( 'file' ) ); } sub test_add_field_after_add_group { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'connection_id' ); $self->assert_dies( qr/calls to add_field\(\) and add_group_field\(\) can't be mixed on the same Lire::DlfQuery/, sub { $query->add_field( 'file' ) } ); } sub test_add_field_with_create_nested_query { my $self = $_[0]; my $query = $self->{'query'}; my $nested = $query->create_nested_query(); $self->assert_dies( qr/can't add simple field to a query containing nested queries/, sub { $query->add_field( 'file' ) } ); $nested->add_field( 'file' ); $self->assert( defined $nested->_field_by_name( "file" ), "field 'file' wasn't added" ); } sub test_no_subqueries_on_simple_queries { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'file' ); $self->assert_dies( qr/can't create a nested query on query containing simple fields/, sub { $query->create_nested_query() } ); } sub test__fields_of_type { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'connection_id' ); $self->assert_deep_equals( [ { 'field' => 'connection_id', 'type' => 'simple', 'alias' => undef } ], $query->_fields_of_type('simple') ); $self->assert_deep_equals( [], $query->_fields_of_type('group+aggr') ); $self->assert_deep_equals( [ ], $query->_fields_of_type('group') ); $self->assert_deep_equals( [ ], $query->_fields_of_type('aggr') ); } sub test__fields_of_type_group { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'connection_id' ); $self->assert_deep_equals( [ { 'field' => 'connection_id', 'type' => 'group', 'alias' => undef } ], $query->_fields_of_type('group') ); } sub test__fields_of_type_group_aggr { my $self = $_[0]; my $query = $self->{'query'}; $query->add_aggr_field( 'nrecords', 'count(*)' ); $query->add_group_field( 'connection_id' ); $self->assert_deep_equals( [ { 'field' => 'count(*)', 'type' => 'aggr', 'alias' => 'nrecords' }, { 'field' => 'connection_id', 'type' => 'group', 'alias' => undef }, ], $query->_fields_of_type('group+aggr') ); } sub test__fields_of_type_bad_params { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_dies( qr/type should be 'simple', 'group', 'aggr' or 'group\+aggr': 'nosuchtype/, sub { $query->_fields_of_type('nosuchtype') } ); } sub test_add_group_field { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'connection_id' ); $self->assert_deep_equals( { 'field' => 'connection_id', 'alias' => undef, 'type' => 'group' }, $query->_field_by_name( 'connection_id' ) ); $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $self->assert_deep_equals( { 'field' => 'lr_timegroup(time_start)', 'alias' => 'period', 'type' => 'group' }, $query->_field_by_name( 'period' ) ); } sub test_group_fields { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_deep_equals( [], $query->group_fields() ); $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); my $nested = $query->create_nested_query(); $nested->add_group_field( 'connection_id' ); $nested->add_aggr_field( 'nrecords', 'count()' ); $self->assert_deep_equals( ['period' ], $query->group_fields() ); $self->assert_deep_equals( ['period', 'connection_id' ], $nested->group_fields() ); } sub test_aggr_fields { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_deep_equals( [], $query->aggr_fields() ); $query->add_group_field( 'connection_id' ); $query->add_aggr_field( 'bytes', 'sum(file_size)' ); my $nested = $query->create_nested_query(); $nested->add_aggr_field( 'nrecords', 'count()' ); $self->assert_deep_equals( [ 'bytes', 'nrecords' ], $query->aggr_fields() ); $self->assert_deep_equals( [ 'nrecords' ], $nested->aggr_fields() ); } sub test_fields { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_deep_equals( [], $query->fields() ); $query->add_field( 'connection_id' ); $query->add_field( 'k', 'file_size/1024' ); $self->assert_deep_equals( [ 'connection_id', 'k' ], $query->fields() ); } sub test_field_def { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'connection_id' ); my $nested1 = $self->{'query'}->create_nested_query(); $nested1->add_aggr_field( 'nrecords', 'count()' ); my $nested2 = $self->{'query'}->create_nested_query(); $nested2->add_field( 'user' ); $nested2->add_field( 'file' ); $self->assert_dies( qr/no field 'time_start' defined in the query/, sub { $query->field_def( 'time_start' ) } ); $self->assert_str_equals( 'user', $query->field_def( 'user' ) ); $self->assert_str_equals( 'file', $query->field_def( 'file' ) ); $self->assert_str_equals( 'connection_id', $query->field_def( 'connection_id' ) ); $self->assert_str_equals( 'count()', $query->field_def( 'nrecords' ) ); $self->assert_dies( qr/no field 'file' defined in the query/, sub { $nested1->field_def( 'file' ) } ); $self->assert_str_equals( 'connection_id', $nested1->field_def( 'connection_id' ) ); $self->assert_str_equals( 'count()', $nested1->field_def( 'nrecords' ) ); $self->assert_dies( qr/no field 'nrecords' defined in the query/, sub { $nested2->field_def( 'nrecords' ) } ); $self->assert_str_equals( 'connection_id', $nested2->field_def( 'connection_id' ) ); $self->assert_str_equals( 'user', $nested2->field_def( 'user' ) ); $self->assert_str_equals( 'file', $nested2->field_def( 'file' ) ); } sub test__query_subtree_from_root { my $self = $_[0]; my $query = $self->{'query'}; my $nested1 = $query->create_nested_query(); my $nested2 = $query->create_nested_query(); my $nested3 = $nested1->create_nested_query(); $self->assert_deep_equals( [ $query, $nested1, $nested3, $nested2 ], $query->_query_subtree_from_root() ); $self->assert_deep_equals( [ $query, $nested1, $nested3 ], $nested1->_query_subtree_from_root() ); $self->assert_deep_equals( [ $query, $nested2 ], $nested2->_query_subtree_from_root() ); $self->assert_deep_equals( [ $query, $nested1, $nested3 ], $nested3->_query_subtree_from_root() ); } sub test_add_group_after_add_field { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'file' ); $self->assert_dies( qr/calls to add_field\(\) and add_group_field\(\) can't be mixed on the same Lire::DlfQuery/, sub { $query->add_group_field( 'connection_id' ) } ); } sub test_add_aggr_field { my $self = $_[0]; my $query = $self->{'query'}; $query->add_aggr_field( "requests", "count()" ); $self->assert_str_equals( 'aggr', $query->_field_by_name( 'requests' )->{'type'} ); $self->assert_dies( qr/missing 'aggregate' parameter/, sub { $query->add_aggr_field( "requests" ) } ); } sub test_set_sort_spec { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'time_start' ); $query->add_group_field( 'connection_id' ); $query->add_group_field( 'transfer-complete' ); my $nested = $query->create_nested_query(); $nested->add_aggr_field( 'downloads', "count()" ); $query->set_sort_spec( '-time_start' ); $self->assert_str_equals( '-time_start', $query->{'_sort_spec'} ); $self->assert_str_equals( 'time_start DESC', $query->{'_order_by'} ); $query->set_sort_spec( undef ); $self->assert_null( $query->{'_sort_spec'}, "'_sort_spec' attribute should have been cleared" ); $self->assert_null( $query->{'_order_by'}, "'_order_by' attribute should have been cleared" ); $query->set_sort_spec( '' ); $self->assert_null( $query->{'_sort_spec'}, "'_sort_spec' attribute should still be cleared" ); $self->assert_null( $query->{'_order_by'}, "'_order_by' attribute should still be cleared" ); $query->set_sort_spec( 'connection_id -time_start' ); $self->assert_str_equals( 'connection_id -time_start', $query->{'_sort_spec'} ); $self->assert_str_equals( 'connection_id, time_start DESC', $query->{'_order_by'} ); $query->set_sort_spec( 'transfer-complete' ); $self->assert_str_equals( '"transfer-complete"', $query->{'_order_by'} ); $query->set_sort_spec( '-transfer-complete' ); $self->assert_str_equals( '"transfer-complete" DESC', $query->{'_order_by'} ); $query->set_sort_spec( '-downloads' ); $self->assert_str_equals( 'downloads DESC', $query->{'_order_by'} ); $self->assert_dies( qr/field 'bad_field' unavailable for sorting/, sub { $query->set_sort_spec( 'bad_field' ); } ); } sub test__is_valid_sort_field { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'connection_id' ); my $nested1 = $query->create_nested_query(); $nested1->add_aggr_field( 'downloads', "count()" ); my $nested2 = $nested1->create_nested_query(); $nested2->add_field( 'user' ); $self->assert_num_equals( 0, $query->_is_valid_sort_field( 'bad_field' ) ); $self->assert_num_equals( 0, $query->_is_valid_sort_field( 'user' ) ); $self->assert_num_equals( 1, $query->_is_valid_sort_field( 'connection_id')); $self->assert_num_equals( 1, $query->_is_valid_sort_field( 'downloads')); $self->assert_num_equals( 0, $nested1->_is_valid_sort_field( 'bad_field' ) ); $self->assert_num_equals( 0, $nested1->_is_valid_sort_field( 'user' ) ); $self->assert_num_equals( 1, $nested1->_is_valid_sort_field( 'connection_id')); $self->assert_num_equals( 1, $nested1->_is_valid_sort_field( 'downloads')); $self->assert_num_equals( 0, $nested2->_is_valid_sort_field( 'bad_field' ) ); $self->assert_num_equals( 0, $nested2->_is_valid_sort_field( 'downloads')); $self->assert_num_equals( 1, $nested2->_is_valid_sort_field( 'user' ) ); $self->assert_num_equals( 1, $nested2->_is_valid_sort_field( 'connection_id')); } sub test_set_sort_spec_and_set_order_by_clause_interaction { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'time_start'); $query->set_sort_spec( 'time_start' ); $query->set_order_by_clause( 'connection_id' ); $self->assert_null( $query->{'_sort_spec'}, "'_sort_spec' attribute should have been cleared" ); } sub test_set_order_by_clause { my $self = $_[0]; my $query = $self->{'query'}; $query->set_order_by_clause( 'time_start DESC' ); $self->assert_str_equals( 'time_start DESC', $query->{'_order_by'} ); $query->set_order_by_clause( undef ); $self->assert_null( $query->{'_order_by'}, "order_by attribute should have been cleared" ); $query->set_order_by_clause( '' ); $self->assert_null( $query->{'_order_by'}, "order_by attribute should still be cleared" ); } sub test_set_limit { my $self = $_[0]; my $query = $self->{'query'}; $query->set_limit( 50 ); $self->assert_num_equals( 50, $query->{'_limit'} ); $query->set_limit( undef ); $self->assert_num_equals( 0, $query->{'_limit'} ); $query->set_limit( 20 ); $query->set_limit( 0 ); $self->assert_num_equals( 0, $query->{'_limit'} ); $self->assert_dies( qr/'limit' parameter should be an integer: 'some text'/, sub { $query->set_limit( 'some text' ) } ); } sub test_set_filter_clause { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_dies( qr/invalid number of parameters: filter clause contains 0 placeholders while 1 values provided/, sub { $query->set_filter_clause( undef, '' ); } ); $self->assert_dies( qr/invalid number of parameters: filter clause contains 1 placeholders while 0 values provided/, sub { $query->set_filter_clause( 'time_start > ?' ); } ); $self->assert_dies( qr/invalid number of parameters: filter clause contains 1 placeholders while 2 values provided/, sub { $query->set_filter_clause( 'time_start > ?', 1, 2 ); } ); $query->set_filter_clause( 'time_start = 0' ); $self->assert_str_equals( 'time_start = 0', $query->{'_filter_clause'} ); $self->assert_deep_equals( [], $query->{'_filter_params'}); $query->set_filter_clause( 'time_start > ?', 0 ); $self->assert_str_equals( 'time_start > ?', $query->{'_filter_clause'} ); $self->assert_deep_equals( [ 0 ], $query->{'_filter_params'}); $query->set_filter_clause( undef ); $self->assert_null( $query->{'_filter_clause'}, "filter_clause attribute should have been cleared" ); $self->assert_deep_equals( [], $query->{'_filter_params'}); $query->set_filter_clause( '' ); $self->assert_null( $query->{'_filter_clause'}, "filter_clause attribute should still be cleared" ); $self->assert_deep_equals( [], $query->{'_filter_params'}); } sub test_sql_params { my $self = $_[0]; my $query = $self->{'query'}; $query->set_filter_clause( 'time_start = 0' ); $self->assert_deep_equals( [], $query->sql_params() ); $query->set_filter_clause( 'time_start = ?', '12345678' ); $self->assert_deep_equals( [ '12345678' ], $query->sql_params() ); my $nested = $query->create_nested_query(); $nested->set_filter_clause( 'user IN ?', "( 'wdankers', 'flacoste' )" ); $self->assert_deep_equals( [ '12345678', "( 'wdankers', 'flacoste' )"], $nested->sql_params() ); my $nested2 = $nested->create_nested_query(); $nested2->set_filter_clause( 'file LIKE ? ', "%.mpg" ); $self->assert_deep_equals( [ '12345678', "( 'wdankers', 'flacoste' )", '%.mpg' ], $nested2->sql_params() ); } sub test_join_stream { my $self = $_[0]; $self->assert_deep_equals( [], $self->{'query'}{'_joined_streams'} ); $self->assert_dies( qr/there is no schema: 'bad_schema'/, sub { $self->{'query'}->join_stream( 'bad_schema' ) } ); $self->assert_dies( qr/cannot join 'test-derived' with 'test'/, sub { $self->{'query'}->join_stream( 'test-derived') } ); my $nested = $self->{'query'}->create_nested_query(); $self->assert_dies( qr/can only join streams on root query/, sub { $nested->join_stream( 'test-extended' ) } ); $self->{'query'}->join_stream( 'test-extended' ); $self->assert_deep_equals( [ 'test-extended' ], $self->{'query'}{'_joined_streams'} ); $self->assert_deep_equals( [ 'test', 'test-extended' ], $self->{'query'}->joined_streams() ); $self->assert_dies( qr/'test-extended' is already joined/, sub { $self->{'query'}->join_stream( 'test-extended' )}); my $query = new Lire::DlfQuery( 'test-extended' ); $self->assert_dies( qr/'test-extended' is already joined/, sub { $query->join_stream( 'test-extended' )}); } sub test_execute { my $self = $_[0]; $self->set_up_test_store(); my $query = $self->{'query'}; $query->add_field( 'user' ); $query->add_field( 'file' ); $self->assert_dies( qr/missing 'store' parameter/, sub { $query->execute () } ); my $result = $query->execute( $self->{'store'} ); $self->assert_isa( 'Lire::DlfResult', $result ); } sub test_execute_summary { my $self = $_[0]; $self->set_up_test_store(); my $query = $self->{'query'}; $query->add_group_field( 'user' ); $query->add_aggr_field( 'downloads', 'count()' ); $self->assert_dies( qr/missing 'store' parameter/, sub { $query->execute_summary () } ); my $result = $query->execute_summary( $self->{'store'} ); $self->assert_isa( 'Lire::DlfResult', $result ); my $summary = $result->next_row(); $self->assert( ! $result->next_row(), "only one row should be returned by summary on top-level query" ); } sub test_execute_no_stream { my $self = $_[0]; $self->set_up_test_store(); my $query = new Lire::DlfQuery( 'test' ); $query->{'_joined_streams'} = [ 'test-extended' ]; $self->assert_dies( qr/store doesn't contain a 'test-extended' stream/, sub { $query->execute_summary( $self->{'store'} ) } ); $self->assert_dies( qr/store doesn't contain a 'test-extended' stream/, sub { $query->execute( $self->{'store'} ) } ); } sub test__sql_select_clause_quoting { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( "connection_id" ); $query->add_group_field( "transfer-complete" ); $query->add_group_field( "total-requests", "count()" ); $query->add_group_field( "period", "lr_timegroup(time_start)" ); $self->assert_str_equals( <_sql_select_clause() . "\n"); SELECT connection_id, "transfer-complete", count() AS "total-requests", lr_timegroup(time_start) AS period ESQL } sub test__sql_from_clause { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_str_equals( "FROM dlf_test", $query->_sql_from_clause() ); $query->{'_stream_name'} = "test-extended"; $self->assert_str_equals( 'FROM dlf_test, "dlf_test-extended"', $query->_sql_from_clause() ); $query->{'_stream_name'} = 'test'; $query->{'_joined_streams'} = [ "test-extended" ]; $self->assert_str_equals( 'FROM dlf_test, "dlf_test-extended"', $query->_sql_from_clause() ); $query->{'_stream_name'} = 'test-derived'; $query->{'_joined_streams'} = [ "test-extended" ]; $self->assert_str_equals( 'FROM "dlf_test-derived", "dlf_test-derived_links", "dlf_test-extended"', $query->_sql_from_clause() ); $query->{'_joined_streams'} = [ "test" ]; $self->assert_str_equals( 'FROM "dlf_test-derived", "dlf_test-derived_links", dlf_test', $query->_sql_from_clause() ); $query->{'_joined_streams'} = []; $self->assert_str_equals( 'FROM "dlf_test-derived"', $query->_sql_from_clause() ); $query->{'_joined_streams'} = [ 'test-extended2' ]; $self->assert_str_equals( 'FROM "dlf_test-derived", "dlf_test-extended2"', $query->_sql_from_clause() ); } sub test__sql_group_by_clause_quoting { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( "connection_id" ); $query->add_group_field( "transfer-complete" ); $query->add_group_field( "total-requests", "count()" ); $query->add_group_field( "period", "lr_timegroup(time_start)" ); $self->assert_str_equals( q{GROUP BY connection_id, "transfer-complete", "total-requests", period}, $query->_sql_group_by_clause() ); } sub test__as_sql { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->add_group_field( 'client_host' ); $query->add_aggr_field( 'requests', 'count()' ); $query->add_aggr_field( 'bytes', 'sum(file_size)' ); $query->set_order_by_clause( "period, bytes DESC" ); $query->set_filter_clause( "file = ?", "index.html" ); $query->set_limit( 5 ); $self->assert_str_equals ( <_as_sql() ); SELECT lr_timegroup(time_start) AS period, client_host, count() AS requests, sum(file_size) AS bytes FROM dlf_test WHERE file = ? GROUP BY period, client_host ORDER BY period, bytes DESC LIMIT 5 SQLS } sub test__sql_select_fields { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'file' ); my $nquery1 = $query->create_nested_query(); $nquery1->add_group_field( 'connection_id' ); $nquery1->add_aggr_field( 'bytes', 'sum(file_size)' ); my $nquery2 = $query->create_nested_query(); $nquery2->add_aggr_field( 'requests', 'count(*)' ); $nquery2->add_field( 'connection_id' ); $self->assert_deep_equals( [ { 'field' => 'file', 'type' => 'group', 'alias' => undef }, { 'field' => 'sum(file_size)', 'type' => 'aggr', 'alias' => 'bytes' }, { 'field' => 'count(*)', 'type' => 'aggr', 'alias' => 'requests' }, ], $query->_sql_select_fields() ); $self->assert_deep_equals( [ { 'field' => 'sum(file_size)', 'type' => 'aggr', 'alias' => 'bytes' }, { 'field' => 'count(*)', 'type' => 'aggr', 'alias' => 'requests' }, ], $query->_sql_select_fields( 1 ) ); $self->assert_deep_equals( [ { 'field' => 'connection_id', 'type' => 'simple', 'alias' => undef }, ], $nquery2->_sql_select_fields() ); $self->assert_deep_equals( [ { 'field' => 'count(*)', 'type' => 'aggr', 'alias' => 'requests' }, ], $nquery2->_sql_select_fields(1) ); } sub test__sql_where_clause { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_null( $query->_sql_where_clause() ); $query->{'_filter_clause'} = 'time_stamp = ?'; $self->assert_str_equals( 'WHERE time_stamp = ?', $query->_sql_where_clause() ); my $sub = $query->create_nested_query(); $self->assert_str_equals( 'WHERE time_stamp = ?', $sub->_sql_where_clause() ); $sub->{'_filter_clause'} = 'connection_id LIKE ?'; $self->assert_str_equals( 'WHERE time_stamp = ?', $query->_sql_where_clause() ); $self->assert_str_equals( 'WHERE time_stamp = ? AND connection_id LIKE ?', $sub->_sql_where_clause() ); $query->{'_stream_name'} = 'test-extended'; $self->assert_str_equals( 'WHERE dlf_test.dlf_id = "dlf_test-extended".dlf_id AND time_stamp = ?', $query->_sql_where_clause() ); } sub test__sql_where_join_elements { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_deep_equals( [], $query->_sql_where_join_elements() ); $query->{'_stream_name'} = 'test-extended'; $self->assert_deep_equals( [ 'dlf_test.dlf_id = "dlf_test-extended".dlf_id' ], $query->_sql_where_join_elements() ); $query->{'_stream_name'} = 'test'; $query->{'_joined_streams'} = [ 'test-extended' ]; $self->assert_deep_equals( [ 'dlf_test.dlf_id = "dlf_test-extended".dlf_id' ], $query->_sql_where_join_elements() ); $query->{'_stream_name'} = 'test-derived'; $query->{'_joined_streams'} = [ 'test', 'test-extended', 'test-extended2' ]; $self->assert_deep_equals( [ '"dlf_test-derived".dlf_id = "dlf_test-derived_links".src_id', '"dlf_test-derived_links".link_id = dlf_test.dlf_id', '"dlf_test-derived_links".link_id = "dlf_test-extended".dlf_id', '"dlf_test-derived".dlf_id = "dlf_test-extended2".dlf_id' ], $query->_sql_where_join_elements() ); $query->{'_joined_streams'} = [ 'test-extended2' ]; $self->assert_deep_equals( [ '"dlf_test-derived".dlf_id = "dlf_test-extended2".dlf_id' ], $query->_sql_where_join_elements() ); } sub test__as_sql_with_nested_query { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->add_aggr_field( 'nrecords', 'count()' ); $query->set_filter_clause( 'time_start > ?', "123456789" ); $query->set_order_by_clause( "period" ); my $nquery1 = $query->create_nested_query(); $nquery1->add_group_field( 'connection_id' ); $nquery1->add_aggr_field( 'bytes', 'sum(file_size)' ); $nquery1->set_order_by_clause( "bytes DESC" ); my $nquery2 = $query->create_nested_query(); $nquery2->add_group_field( "file" ); $nquery2->add_aggr_field( "downloads", "count()" ); $nquery2->set_filter_clause( 'file = ?', "index.html" ); $self->assert_str_equals( <_as_sql() ); SELECT lr_timegroup(time_start) AS period, count() AS nrecords, sum(file_size) AS bytes, count() AS downloads FROM dlf_test WHERE time_start > ? GROUP BY period ORDER BY period SQLS $self->assert_str_equals( <_as_sql() ); SELECT lr_timegroup(time_start) AS period, connection_id, sum(file_size) AS bytes FROM dlf_test WHERE time_start > ? GROUP BY period, connection_id ORDER BY period, bytes DESC SQLS $self->assert_str_equals( <_as_sql() ); SELECT lr_timegroup(time_start) AS period, file, count() AS downloads FROM dlf_test WHERE time_start > ? AND file = ? GROUP BY period, file ORDER BY period SQLS } sub test__as_sql_select_only { my $self = $_[0]; my $query = $self->{'query'}; $query->add_field( 'requests', 'count()' ); $query->add_field( 'bytes', 'sum(file_size)' ); $self->assert_str_equals ( <_as_sql() ); SELECT count() AS requests, sum(file_size) AS bytes FROM dlf_test SQLS } sub test__as_summary_sql { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->add_group_field( 'client_host' ); $query->add_aggr_field( 'requests', 'count()' ); $query->add_aggr_field( 'bytes', 'sum(file_size)' ); $query->set_order_by_clause( "period, bytes DESC" ); $query->set_filter_clause( "file = ?", "index.html" ); $query->set_limit( 5 ); $self->assert_str_equals ( <_as_summary_sql() ); SELECT count() AS requests, sum(file_size) AS bytes FROM dlf_test WHERE file = ? SQLS } sub test__as_summary_sql_nested_query { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->add_aggr_field( 'nrecords', 'count()' ); $query->set_filter_clause( 'time_start > ?', 123456789 ); $query->set_order_by_clause( "period" ); my $nquery1 = $query->create_nested_query(); $nquery1->add_group_field( 'connection_id' ); $nquery1->add_aggr_field( 'bytes', 'sum(file_size)' ); $nquery1->set_order_by_clause( "bytes DESC" ); my $nquery2 = $query->create_nested_query(); $nquery2->add_group_field( "file" ); $nquery2->add_aggr_field( "downloads", "count()" ); $nquery2->set_filter_clause( 'file = ?', "index.html" ); $self->assert_str_equals( <_as_summary_sql() ); SELECT count() AS nrecords, sum(file_size) AS bytes, count() AS downloads FROM dlf_test WHERE time_start > ? SQLS $self->assert_str_equals( <_as_summary_sql() ); SELECT lr_timegroup(time_start) AS period, sum(file_size) AS bytes FROM dlf_test WHERE time_start > ? GROUP BY period ORDER BY period SQLS $self->assert_str_equals( <_as_summary_sql() ); SELECT lr_timegroup(time_start) AS period, count() AS downloads FROM dlf_test WHERE time_start > ? AND file = ? GROUP BY period ORDER BY period SQLS } sub test__as_summary_sql_no_where { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->add_group_field( 'client_host' ); $query->add_aggr_field( 'requests', 'count()' ); $query->add_aggr_field( 'bytes', 'sum(file_size)' ); $query->set_order_by_clause( "period, bytes DESC" ); $query->set_limit( 5 ); $self->assert_str_equals ( <_as_summary_sql() ); SELECT count() AS requests, sum(file_size) AS bytes FROM dlf_test SQLS } sub test__as_sql_simple_field_nested_query { my $self = $_[0]; my $query = $self->{'query'}; $query->add_group_field( 'period', 'lr_timegroup(time_start)' ); $query->set_order_by_clause( 'period' ); my $nquery = $query->create_nested_query(); $nquery->add_field( 'time_start' ); $nquery->add_field( 'user' ); $nquery->add_field( 'file' ); $nquery->add_field( 'time_taken' ); $self->assert_str_equals ( <_as_sql() ); SELECT lr_timegroup(time_start) AS period, time_start, user, file, time_taken FROM dlf_test ORDER BY period SQLS } sub test_create_nested_query { my $self = $_[0]; my $query = $self->{'query'}; $self->assert_null( $query->{'_parent'}, "new query should have NULL parent" ); $self->assert_deep_equals( [], $query->{'_nested_queries'} ); my $nested = $self->{'query'}->create_nested_query(); $self->assert_isa( 'Lire::DlfQuery', $nested ); $self->assert_str_equals( $query->{'_stream_name'}, $nested->{'_stream_name'} ); $self->assert_str_equals( $query, $nested->{'_parent'} ); $self->assert_deep_equals( [ $nested ], $query->{'_nested_queries'} ); } sub test_release { my $self = $_[0]; my $query = $self->{'query'}; my $nested = $query->create_nested_query(); $query->release(); $self->assert_null( $nested->{'_parent'}, "_parent attribute of nested queries should be undef" ); } sub test__root_query { my $self = $_[0]; $self->assert_str_equals( $self->{'query'}, $self->{'query'}->_root_query() ); my $nested = $self->{'query'}->create_nested_query(); $self->assert_str_equals( $self->{'query'}, $nested->_root_query() ); my $nested2 = $nested->create_nested_query(); $self->assert_str_equals( $self->{'query'}, $nested2->_root_query() ); } sub test__sql_order_by_clause { my $self = $_[0]; my $query = $self->{'query'}; my $clause = $query->_sql_order_by_clause(); $self->assert_null( $clause, '_sql_order_by_clause() should be undef' ); $query->{'_order_by'} = 'connection_id, user'; $self->assert_str_equals( 'ORDER BY connection_id, user', $query->_sql_order_by_clause() ); my $squery = $query->create_nested_query(); $self->assert_str_equals( 'ORDER BY connection_id, user', $squery->_sql_order_by_clause() ); $squery->{'_order_by'} = 'file DESC'; $self->assert_str_equals( 'ORDER BY connection_id, user, file DESC', $squery->_sql_order_by_clause() ); $query->{'_order_by'} = undef; $self->assert_str_equals( 'ORDER BY file DESC', $squery->_sql_order_by_clause() ); } 1;