@@ -268,6 +268,117 @@ test_that("Union all keeps duplicates", {
268268 expect_equal(rel_df , expected_result )
269269})
270270
271+ test_that(" Inner join returns all inner relations" , {
272+ dbExecute(con , " CREATE OR REPLACE MACRO eq(a, b) AS a = b" )
273+ left <- rel_from_df(con , data.frame (left_a = c(1 , 2 , 3 ), left_b = c(1 , 1 , 2 )))
274+ right <- rel_from_df(con , data.frame (right_b = c(1 , 3 ), right_c = c(4 , 5 )))
275+ cond <- list (expr_function(" eq" , list (expr_reference(" left_b" ), expr_reference(" right_b" ))))
276+ rel2 <- rel_join(left , right , cond , " inner" )
277+ rel_df <- rel_to_altrep(rel2 )
278+ dim(rel_df )
279+ expected_result <- data.frame (left_a = c(1 , 2 ), left_b = c(1 , 1 ), right_b = c(1 , 1 ), right_c = c(4 , 4 ))
280+ expect_equal(rel_df , expected_result )
281+ })
282+
283+ test_that(" ASOF join works" , {
284+ dbExecute(con , " CREATE OR REPLACE MACRO gte(a, b) AS a >= b" )
285+ test_df1 <- duckdb ::: rel_from_df(con , data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )))
286+ test_df2 <- duckdb ::: rel_from_df(con , data.frame (event_ts = c(1 , 3 , 6 , 8 ), event_id = c(0 , 1 , 2 , 3 )))
287+ cond <- list (duckdb ::: expr_function(" gte" , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" event_ts" ))))
288+ rel <- duckdb ::: rel_join(test_df1 , test_df2 , cond , ref_type = " asof" )
289+ rel_proj <- duckdb ::: rel_project(rel , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" event_id" )))
290+ rel_df <- duckdb ::: rel_to_altrep(rel_proj )
291+ expected_result <- data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ), event_id = c(0 , 0 , 1 , 1 , 1 , 2 , 2 , 3 , 3 ))
292+ expect_equal(expected_result , rel_df )
293+ })
294+
295+ test_that(" LEFT ASOF join works" , {
296+ dbExecute(con , " CREATE OR REPLACE MACRO gte(a, b) AS a >= b" )
297+ test_df1 <- duckdb ::: rel_from_df(con , data.frame (ts = c(0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )))
298+ test_df2 <- duckdb ::: rel_from_df(con , data.frame (event_ts = c(2 , 4 , 6 , 8 ), event_id = c(0 , 1 , 2 , 3 )))
299+ cond <- list (duckdb ::: expr_function(" gte" , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" event_ts" ))))
300+ rel <- duckdb ::: rel_join(test_df1 , test_df2 , cond , join = " left" , ref_type = " asof" )
301+ rel_proj <- duckdb ::: rel_project(rel , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" event_ts" ), duckdb ::: expr_reference(" event_id" )))
302+ order <- duckdb ::: rel_order(rel_proj , list (duckdb ::: expr_reference(" ts" )))
303+ rel_df <- duckdb ::: rel_to_altrep(order )
304+ expected_result <- data.frame (ts = c(0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ), event_ts = c(NA , NA ,2 , 2 , 4 , 4 , 6 , 6 , 8 , 8 ), event_id = c(NA , NA , 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 ))
305+ expect_equal(expected_result , rel_df )
306+ })
307+
308+ test_that(" Positional cross join works" , {
309+ test_df1 <- duckdb ::: rel_from_df(con , data.frame (a = c(11 , 12 , 13 ), b = c(1 , 2 , 3 )))
310+ test_df2 <- duckdb ::: rel_from_df(con , data.frame (c = c(11 , 12 ), d = c(1 , 2 )))
311+ rel <- duckdb ::: rel_join(test_df1 , test_df2 , list (), join = " cross" , ref_type = " positional" )
312+ rel_df <- duckdb ::: rel_to_altrep(rel )
313+ expected_result <- data.frame (a = c(11 , 12 , 13 ), b = c(1 , 2 , 3 ), c = c(11 , 12 , NA ), d = c(1 , 2 , NA ))
314+ expect_equal(expected_result , rel_df )
315+ })
316+
317+ test_that(" regular positional join works" , {
318+ dbExecute(con , " CREATE OR REPLACE MACRO eq(a, b) AS a = b" )
319+ test_df1 <- duckdb ::: rel_from_df(con , data.frame (a = c(11 , 12 , 13 ), b = c(1 , 2 , 3 )))
320+ test_df2 <- duckdb ::: rel_from_df(con , data.frame (c = c(11 , 12 , 14 , 11 ), d = c(4 , 5 , 6 , 8 )))
321+ cond <- duckdb ::: expr_function(" eq" , list (duckdb ::: expr_reference(" a" ), duckdb ::: expr_reference(" c" )))
322+ rel <- duckdb ::: rel_join(test_df1 , test_df2 , list (cond ), ref_type = " positional" )
323+ rel_df <- duckdb ::: rel_to_altrep(rel )
324+ expected_result <- data.frame (a = c(11 , 12 ), b = c(1 , 2 ), c = c(11 , 12 ), d = c(4 , 5 ))
325+ expect_equal(expected_result , rel_df )
326+ })
327+
328+ test_that(" Invalid asof join condition throws error" , {
329+ dbExecute(con , " CREATE OR REPLACE MACRO neq(a, b) AS a <> b" )
330+ test_df1 <- rel_from_df(con , data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )))
331+ test_df2 <- rel_from_df(con , data.frame (begin = c(1 , 3 , 6 , 8 ), value = c(0 , 1 , 2 , 3 )))
332+ cond <- list (expr_function(" neq" , list (expr_reference(" ts" ), expr_reference(" begin" ))))
333+ expect_error(rel_join(test_df1 , test_df2 , cond , ref_type = " asof" ), " Binder Error" )
334+ })
335+
336+ test_that(" multiple inequality conditions for asof join throws error" , {
337+ dbExecute(con , " CREATE OR REPLACE MACRO gte(a, b) AS a >= b" )
338+ test_df1 <- duckdb ::: rel_from_df(con , data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )))
339+ test_df2 <- duckdb ::: rel_from_df(con , data.frame (begin = c(1 , 3 , 6 , 8 ), value = c(0 , 1 , 2 , 3 )))
340+ cond1 <- duckdb ::: expr_function(" gte" , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" begin" )))
341+ cond2 <- duckdb ::: expr_function(" gte" , list (duckdb ::: expr_reference(" ts" ), duckdb ::: expr_reference(" value" )))
342+ conds <- list (cond1 , cond2 )
343+ expect_error(rel_join(test_df1 , test_df2 , conds , ref_type = " asof" ), " Binder Error" )
344+ })
345+
346+
347+ test_that(" Inequality joins work" , {
348+ dbExecute(con , " CREATE OR REPLACE MACRO gte(a, b) AS a >= b" )
349+ timing_df <- rel_from_df(con , data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 )))
350+ events_df <- rel_from_df(con , data.frame (event_ts = c(1 , 3 , 6 , 8 ), event_id = c(0 , 1 , 2 , 3 )))
351+ cond <- list (expr_function(" gte" , list (expr_reference(" ts" ), expr_reference(" event_ts" ))))
352+ rel <- rel_inner_join(timing_df , events_df , cond )
353+ rel_proj <- rel_project(rel , list (expr_reference(" ts" ), expr_reference(" event_ts" )))
354+ rel_order <- rel_order(rel_proj , list (expr_reference(" ts" ), expr_reference(" event_ts" )))
355+ rel_df <- rel_to_altrep(rel_order )
356+ expected_result <- data.frame (ts = c(1 , 2 , 3 , 3 , 4 , 4 , 5 , 5 , 6 , 6 , 6 ), event_ts = c(1 , 1 , 1 , 3 , 1 , 3 , 1 , 3 , 1 , 3 , 6 ))
357+ expect_equal(expected_result , rel_df )
358+ })
359+
360+
361+ test_that(" Inequality join works to perform between operation" , {
362+ dbExecute(con , " CREATE OR REPLACE MACRO gt(a, b) AS a > b" )
363+ dbExecute(con , " CREATE OR REPLACE MACRO lt(a, b) AS a < b" )
364+ timing_df <- rel_from_df(con , data.frame (ts = c(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 )))
365+ events_df <- rel_from_df(con , data.frame (event_ts = c(1 , 3 , 6 , 8 ), event_id = c(0 , 1 , 2 , 3 )))
366+ lead <- expr_function(" lead" , list (expr_reference(" event_ts" )))
367+ window_lead <- expr_window(lead , offset_expr = expr_constant(1 ))
368+ expr_set_alias(window_lead , " lead" )
369+ proj_window <- rel_project(events_df , list (expr_reference(" event_ts" ), window_lead , expr_reference(" event_id" )))
370+ cond1 <- expr_function(" gt" , list (expr_reference(" ts" ), expr_reference(" event_ts" )))
371+ cond2 <- expr_function(" lt" , list (expr_reference(" ts" ), expr_reference(" lead" )))
372+ conds <- list (cond1 , cond2 )
373+ rel <- rel_inner_join(timing_df , proj_window , conds )
374+ rel_proj <- rel_project(rel , list (expr_reference(" ts" )))
375+ rel_order <- rel_order(rel_proj , list (expr_reference(" ts" )))
376+ rel_df <- rel_to_altrep(rel_order )
377+ expected_result <- data.frame (ts = c(2 , 4 , 5 , 7 ))
378+ expect_equal(expected_result , rel_df )
379+ })
380+
381+
271382# nobody should do this in reality. It's a pretty dumb idea
272383test_that(" we can union the same relation to itself" , {
273384 test_df_a2 <- rel_from_df(con , data.frame (a = c(' 1' , ' 2' ), b = c(' 3' , ' 4' )))
@@ -285,10 +396,10 @@ test_that("we throw an error when attempting to union all relations that are not
285396})
286397
287398test_that(" A union with different column types casts to the richer type" , {
288- test_df_a1 <- duckdb ::: rel_from_df(con , data.frame (a = c(1 )))
289- test_df_a2 <- duckdb ::: rel_from_df(con , data.frame (a = c(' 1' )))
290- rel <- duckdb ::: rel_union_all(test_df_a1 , test_df_a2 )
291- res <- duckdb ::: rapi_rel_to_df(rel )
399+ test_df_a1 <- rel_from_df(con , data.frame (a = c(1 )))
400+ test_df_a2 <- rel_from_df(con , data.frame (a = c(' 1' )))
401+ rel <- rel_union_all(test_df_a1 , test_df_a2 )
402+ res <- rapi_rel_to_df(rel )
292403 expected <- data.frame (a = c(' 1.0' , ' 1' ))
293404 expect_equal(class(res $ a ), class(expected $ a ))
294405 expect_equal(res $ a [1 ], expected $ a [1 ])
@@ -644,9 +755,8 @@ test_that("rel_to_sql works for row_number", {
644755 expect_equal(sub_str_sql , " SELECT row_number() OVER () AS ___row_number" )
645756})
646757
647-
648758test_that(" rel_from_table_function works" , {
649- rel <- duckdb ::: rel_from_table_function(duckdb ::: default_connection(), ' generate_series' , list (1L , 10L , 2L ))
759+ rel <- rel_from_table_function(default_connection(), ' generate_series' , list (1L , 10L , 2L ))
650760 df <- as.data.frame(rel )
651761 expect_equal(df $ generate_series , c(1 ,3 ,5 ,7 ,9 ))
652762})
0 commit comments