diff --git a/NEWS.md b/NEWS.md index f2d0a60fba..85f1c7dc2e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -34,17 +34,18 @@ * add new functions to `GroupKey` API to make it more consistent with `DataFrameRow` ([#2308](https://github.com/JuliaData/DataFrames.jl/pull/2308)) * allow column renaming in joins - ([#2313](https://github.com/JuliaData/DataFrames.jl/pull/2313) + ([#2313](https://github.com/JuliaData/DataFrames.jl/pull/2313) and + ([#2398](https://github.com/JuliaData/DataFrames.jl/pull/2398)) * add `rownumber` to `DataFrameRow` ([#2356](https://github.com/JuliaData/DataFrames.jl/pull/2356)) * allow passing column name to specify the position where a new columns should be inserted in `insertcols!` ([#2365](https://github.com/JuliaData/DataFrames.jl/pull/2365)) -* allow `GroupedDataFrame`s to be indexed using a dictionary, which can use `Symbol` or string keys and +* allow `GroupedDataFrame`s to be indexed using a dictionary, which can use `Symbol` or string keys and are not dependent on the order of keys. ([#2281](https://github.com/JuliaData/DataFrames.jl/pull/2281)) * add `isapprox` method to check for approximate equality between two dataframes ([#2373](https://github.com/JuliaData/DataFrames.jl/pull/2373)) * add `columnindex` for `DataFrameRow` ([#2380](https://github.com/JuliaData/DataFrames.jl/pull/2380)) - + ## Deprecated * `DataFrame!` is now deprecated ([#2338](https://github.com/JuliaData/DataFrames.jl/pull/2338)) diff --git a/src/abstractdataframe/join.jl b/src/abstractdataframe/join.jl index 10738769d9..a5b55c52d7 100644 --- a/src/abstractdataframe/join.jl +++ b/src/abstractdataframe/join.jl @@ -63,10 +63,10 @@ Base.length(x::RowIndexMap) = length(x.orig) # table rows and the indices of rows in the result _rename_cols(old_names::AbstractVector{Symbol}, - rename::Union{Function, Symbol, AbstractString}, + renamecols::Union{Function, Symbol, AbstractString}, exclude::AbstractVector{Symbol} = Symbol[]) = Symbol[n in exclude ? n : - (rename isa Function ? Symbol(rename(string(n))) : Symbol(n, rename)) + (renamecols isa Function ? Symbol(renamecols(string(n))) : Symbol(n, renamecols)) for n in old_names] function compose_joined_table(joiner::DataFrameJoiner, kind::Symbol, @@ -449,7 +449,7 @@ end """ innerjoin(df1, df2; on, makeunique = false, - validate = (false, false), rename = identity => identity) + validate = (false, false), renamecols = identity => identity) innerjoin(df1, df2, dfs...; on, makeunique = false, validate = (false, false)) @@ -479,11 +479,11 @@ The order of rows in the result is undefined and may change in the future releas Can be a tuple or a pair, with the first element indicating whether to run check for `df1` and the second element for `df2`. By default no check is performed. -- `rename` : a `Pair` specifying how columns of left and right data frames should +- `renamecols` : a `Pair` specifying how columns of left and right data frames should be renamed in the resulting data frame. Each element of the pair can be a string or a `Symbol` can be passed in which case it is appended to the original column name; alternatively a function can be passed in which case it is applied - to each column name, which is passed to it as a `String`. Note that `rename` + to each column name, which is passed to it as a `String`. Note that `renamecols` does not affect `on` columns, whose names are always taken from the left data frame and left unchanged. @@ -535,7 +535,7 @@ julia> job2 = DataFrame(identifier = [1, 2, 4], Job = ["Lawyer", "Doctor", "Farm │ 2 │ 2 │ Doctor │ │ 3 │ 4 │ Farmer │ -julia> innerjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_right") +julia> innerjoin(name, job2, on = :ID => :identifier, renamecols = "_left" => "_right") 2×3 DataFrame │ Row │ ID │ Name_left │ Job_right │ │ │ Int64 │ String │ String │ @@ -543,7 +543,7 @@ julia> innerjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_righ │ 1 │ 1 │ John Doe │ Lawyer │ │ 2 │ 2 │ Jane Doe │ Doctor │ -julia> innerjoin(name, job2, on = [:ID => :identifier], rename = uppercase => lowercase) +julia> innerjoin(name, job2, on = [:ID => :identifier], renamecols = uppercase => lowercase) 2×3 DataFrame │ Row │ ID │ NAME │ job │ │ │ Int64 │ String │ String │ @@ -556,13 +556,14 @@ function innerjoin(df1::AbstractDataFrame, df2::AbstractDataFrame; on::Union{<:OnType, AbstractVector} = Symbol[], makeunique::Bool=false, validate::Union{Pair{Bool, Bool}, Tuple{Bool, Bool}}=(false, false), - rename::Pair=identity => identity) - if !all(x -> x isa Union{Function, AbstractString, Symbol}, rename) - throw(ArgumentError("rename keyword argument must be a `Pair`" * + renamecols::Pair=identity => identity) + if !all(x -> x isa Union{Function, AbstractString, Symbol}, renamecols) + throw(ArgumentError("renamecols keyword argument must be a `Pair`" * " containing functions, strings, or `Symbol`s")) end - return _join(df1, df2, on=on, kind=:inner, makeunique=makeunique, indicator=nothing, - validate=validate, left_rename=first(rename), right_rename=last(rename)) + return _join(df1, df2, on=on, kind=:inner, makeunique=makeunique, + indicator=nothing, validate=validate, + left_rename=first(renamecols), right_rename=last(renamecols)) end innerjoin(df1::AbstractDataFrame, df2::AbstractDataFrame, dfs::AbstractDataFrame...; @@ -574,7 +575,7 @@ innerjoin(df1::AbstractDataFrame, df2::AbstractDataFrame, dfs::AbstractDataFrame """ leftjoin(df1, df2; on, makeunique = false, indicator = nothing, - validate = (false, false), rename = identity => identity) + validate = (false, false), renamecols = identity => identity) Perform a left join of twodata frame objects and return a `DataFrame` containing the result. A left join includes all rows from `df1`. @@ -603,11 +604,11 @@ The order of rows in the result is undefined and may change in the future releas Can be a tuple or a pair, with the first element indicating whether to run check for `df1` and the second element for `df2`. By default no check is performed. -- `rename` : a `Pair` specifying how columns of left and right data frames should +- `renamecols` : a `Pair` specifying how columns of left and right data frames should be renamed in the resulting data frame. Each element of the pair can be a string or a `Symbol` can be passed in which case it is appended to the original column name; alternatively a function can be passed in which case it is applied - to each column name, which is passed to it as a `String`. Note that `rename` + to each column name, which is passed to it as a `String`. Note that `renamecols` does not affect `on` columns, whose names are always taken from the left data frame and left unchanged. @@ -658,7 +659,7 @@ julia> job2 = DataFrame(identifier = [1, 2, 4], Job = ["Lawyer", "Doctor", "Farm │ 2 │ 2 │ Doctor │ │ 3 │ 4 │ Farmer │ -julia> leftjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_right") +julia> leftjoin(name, job2, on = :ID => :identifier, renamecols = "_left" => "_right") 3×3 DataFrame │ Row │ ID │ Name_left │ Job_right │ │ │ Int64 │ String │ String? │ @@ -667,7 +668,7 @@ julia> leftjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_right │ 2 │ 2 │ Jane Doe │ Doctor │ │ 3 │ 3 │ Joe Blogs │ missing │ -julia> leftjoin(name, job2, on = [:ID => :identifier], rename = uppercase => lowercase) +julia> leftjoin(name, job2, on = [:ID => :identifier], renamecols = uppercase => lowercase) 3×3 DataFrame │ Row │ ID │ NAME │ job │ │ │ Int64 │ String │ String? │ @@ -681,18 +682,19 @@ function leftjoin(df1::AbstractDataFrame, df2::AbstractDataFrame; on::Union{<:OnType, AbstractVector} = Symbol[], makeunique::Bool=false, indicator::Union{Nothing, Symbol, AbstractString} = nothing, validate::Union{Pair{Bool, Bool}, Tuple{Bool, Bool}}=(false, false), - rename::Pair=identity => identity) - if !all(x -> x isa Union{Function, AbstractString, Symbol}, rename) - throw(ArgumentError("rename keyword argument must be a `Pair`" * + renamecols::Pair=identity => identity) + if !all(x -> x isa Union{Function, AbstractString, Symbol}, renamecols) + throw(ArgumentError("renamecols keyword argument must be a `Pair`" * " containing functions, strings, or `Symbol`s")) end - return _join(df1, df2, on=on, kind=:left, makeunique=makeunique, indicator=indicator, - validate=validate, left_rename=first(rename), right_rename=last(rename)) + return _join(df1, df2, on=on, kind=:left, makeunique=makeunique, + indicator=indicator, validate=validate, + left_rename=first(renamecols), right_rename=last(renamecols)) end """ rightjoin(df1, df2; on, makeunique = false, indicator = nothing, - validate = (false, false), rename = identity => identity) + validate = (false, false), renamecols = identity => identity) Perform a right join on two data frame objects and return a `DataFrame` containing the result. A right join includes all rows from `df2`. @@ -721,11 +723,11 @@ The order of rows in the result is undefined and may change in the future releas Can be a tuple or a pair, with the first element indicating whether to run check for `df1` and the second element for `df2`. By default no check is performed. -- `rename` : a `Pair` specifying how columns of left and right data frames should +- `renamecols` : a `Pair` specifying how columns of left and right data frames should be renamed in the resulting data frame. Each element of the pair can be a string or a `Symbol` can be passed in which case it is appended to the original column name; alternatively a function can be passed in which case it is applied - to each column name, which is passed to it as a `String`. Note that `rename` + to each column name, which is passed to it as a `String`. Note that `renamecols` does not affect `on` columns, whose names are always taken from the left data frame and left unchanged. @@ -776,7 +778,7 @@ julia> job2 = DataFrame(identifier = [1, 2, 4], Job = ["Lawyer", "Doctor", "Farm │ 2 │ 2 │ Doctor │ │ 3 │ 4 │ Farmer │ -julia> rightjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_right") +julia> rightjoin(name, job2, on = :ID => :identifier, renamecols = "_left" => "_right") 3×3 DataFrame │ Row │ ID │ Name_left │ Job_right │ │ │ Int64 │ String? │ String │ @@ -785,7 +787,7 @@ julia> rightjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_righ │ 2 │ 2 │ Jane Doe │ Doctor │ │ 3 │ 4 │ missing │ Farmer │ -julia> rightjoin(name, job2, on = [:ID => :identifier], rename = uppercase => lowercase) +julia> rightjoin(name, job2, on = [:ID => :identifier], renamecols = uppercase => lowercase) 3×3 DataFrame │ Row │ ID │ NAME │ job │ │ │ Int64 │ String? │ String │ @@ -796,21 +798,22 @@ julia> rightjoin(name, job2, on = [:ID => :identifier], rename = uppercase => lo ``` """ function rightjoin(df1::AbstractDataFrame, df2::AbstractDataFrame; - on::Union{<:OnType, AbstractVector} = Symbol[], - makeunique::Bool=false, indicator::Union{Nothing, Symbol, AbstractString} = nothing, + on::Union{<:OnType, AbstractVector} = Symbol[], makeunique::Bool=false, + indicator::Union{Nothing, Symbol, AbstractString} = nothing, validate::Union{Pair{Bool, Bool}, Tuple{Bool, Bool}}=(false, false), - rename::Pair=identity => identity) - if !all(x -> x isa Union{Function, AbstractString, Symbol}, rename) - throw(ArgumentError("rename keyword argument must be a `Pair`" * + renamecols::Pair=identity => identity) + if !all(x -> x isa Union{Function, AbstractString, Symbol}, renamecols) + throw(ArgumentError("renamecols keyword argument must be a `Pair`" * " containing functions, strings, or `Symbol`s")) end - return _join(df1, df2, on=on, kind=:right, makeunique=makeunique, indicator=indicator, - validate=validate, left_rename=first(rename), right_rename=last(rename)) + return _join(df1, df2, on=on, kind=:right, makeunique=makeunique, + indicator=indicator, validate=validate, + left_rename=first(renamecols), right_rename=last(renamecols)) end """ outerjoin(df1, df2; on, kind = :inner, makeunique = false, indicator = nothing, - validate = (false, false), rename = identity => identity) + validate = (false, false), renamecols = identity => identity) outerjoin(df1, df2, dfs...; on, kind = :inner, makeunique = false, validate = (false, false)) @@ -845,11 +848,11 @@ The order of rows in the result is undefined and may change in the future releas Can be a tuple or a pair, with the first element indicating whether to run check for `df1` and the second element for `df2`. By default no check is performed. -- `rename` : a `Pair` specifying how columns of left and right data frames should +- `renamecols` : a `Pair` specifying how columns of left and right data frames should be renamed in the resulting data frame. Each element of the pair can be a string or a `Symbol` can be passed in which case it is appended to the original column name; alternatively a function can be passed in which case it is applied - to each column name, which is passed to it as a `String`. Note that `rename` + to each column name, which is passed to it as a `String`. Note that `renamecols` does not affect `on` columns, whose names are always taken from the left data frame and left unchanged. @@ -907,7 +910,7 @@ julia> job2 = DataFrame(identifier = [1, 2, 4], Job = ["Lawyer", "Doctor", "Farm │ 2 │ 2 │ Doctor │ │ 3 │ 4 │ Farmer │ -julia> rightjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_right") +julia> rightjoin(name, job2, on = :ID => :identifier, renamecols = "_left" => "_right") 3×3 DataFrame │ Row │ ID │ Name_left │ Job_right │ │ │ Int64 │ String? │ String │ @@ -916,7 +919,7 @@ julia> rightjoin(name, job2, on = :ID => :identifier, rename = "_left" => "_righ │ 2 │ 2 │ Jane Doe │ Doctor │ │ 3 │ 4 │ missing │ Farmer │ -julia> rightjoin(name, job2, on = [:ID => :identifier], rename = uppercase => lowercase) +julia> rightjoin(name, job2, on = [:ID => :identifier], renamecols = uppercase => lowercase) 3×3 DataFrame │ Row │ ID │ NAME │ job │ │ │ Int64 │ String? │ String │ @@ -930,13 +933,14 @@ function outerjoin(df1::AbstractDataFrame, df2::AbstractDataFrame; on::Union{<:OnType, AbstractVector} = Symbol[], makeunique::Bool=false, indicator::Union{Nothing, Symbol, AbstractString} = nothing, validate::Union{Pair{Bool, Bool}, Tuple{Bool, Bool}}=(false, false), - rename::Pair=identity => identity) - if !all(x -> x isa Union{Function, AbstractString, Symbol}, rename) - throw(ArgumentError("rename keyword argument must be a `Pair`" * + renamecols::Pair=identity => identity) + if !all(x -> x isa Union{Function, AbstractString, Symbol}, renamecols) + throw(ArgumentError("renamecols keyword argument must be a `Pair`" * " containing functions, strings, or `Symbol`s")) end - return _join(df1, df2, on=on, kind=:outer, makeunique=makeunique, indicator=indicator, - validate=validate, left_rename=first(rename), right_rename=last(rename)) + return _join(df1, df2, on=on, kind=:outer, makeunique=makeunique, + indicator=indicator, validate=validate, + left_rename=first(renamecols), right_rename=last(renamecols)) end outerjoin(df1::AbstractDataFrame, df2::AbstractDataFrame, dfs::AbstractDataFrame...; diff --git a/test/join.jl b/test/join.jl index 4fdff2c253..c4b209ecd3 100644 --- a/test/join.jl +++ b/test/join.jl @@ -723,7 +723,7 @@ end @test outerjoin(df1, df2, on=[:a => :d, :b], validate=(false, false)) == [df1; df1] end -@testset "rename tests" begin +@testset "renamecols tests" begin df1 = DataFrame(id1=[1,2,3], id2=[1,2,3], x=1:3) df2 = DataFrame(id1=[1,2,4], ID2=[1,2,4], x=1:3) @@ -734,7 +734,7 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test innerjoin(df1, df2, on=:id1, - makeunique = mu, validate = vl => vr, rename = l => r) == + makeunique = mu, validate = vl => vr, renamecols = l => r) == DataFrame(id1=[1,2], id2_left=[1,2], x_left=[1,2], ID2_right=[1,2], x_right=[1,2]) end @@ -745,7 +745,7 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], - makeunique = mu, validate = vl => vr, rename = l => r) == + makeunique = mu, validate = vl => vr, renamecols = l => r) == DataFrame(id1=[1,2], id2=[1,2], x_left=[1,2], x_right=[1,2]) end @@ -756,7 +756,7 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test leftjoin(df1, df2, on=:id1, - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,3], id2_left=[1,2,3], x_left=[1,2,3], ID2_right=[1,2,missing], x_right=[1,2,missing]) end @@ -768,16 +768,16 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test leftjoin(df1, df2, on=[:id1, :id2 => :ID2], - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,3], id2=[1,2,3], x_left=[1,2,3], x_right=[1,2,missing]) end @test_throws ArgumentError leftjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:id1) + renamecols = "_left" => "_right", indicator=:id1) @test_throws ArgumentError leftjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:x_left) + renamecols = "_left" => "_right", indicator=:x_left) @test leftjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:ind) ≅ + renamecols = "_left" => "_right", indicator=:ind) ≅ DataFrame(id1=[1,2,3], id2=[1,2,3], x_left=[1,2,3], x_right=[1,2,missing], ind=["both", "both", "left_only"]) @@ -788,7 +788,7 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test rightjoin(df1, df2, on=:id1, - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,4], id2_left=[1,2,missing], x_left=[1,2,missing], ID2_right=[1,2,4], x_right=[1,2,3]) end @@ -800,16 +800,16 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test rightjoin(df1, df2, on=[:id1, :id2 => :ID2], - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,4], id2=[1,2,4], x_left=[1,2,missing], x_right=[1,2,3]) end @test_throws ArgumentError rightjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:id1) + renamecols = "_left" => "_right", indicator=:id1) @test_throws ArgumentError rightjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:x_left) + renamecols = "_left" => "_right", indicator=:x_left) @test rightjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:ind) ≅ + renamecols = "_left" => "_right", indicator=:ind) ≅ DataFrame(id1=[1,2,4], id2=[1,2,4], x_left=[1,2,missing], x_right=[1,2,3], ind=["both", "both", "right_only"]) @@ -821,7 +821,7 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test outerjoin(df1, df2, on=:id1, - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,3,4], id2_left=[1,2,3,missing], x_left=[1,2,3,missing], ID2_right=[1,2,missing,4], x_right=[1,2,missing,3]) end @@ -833,33 +833,33 @@ end r in ["_right", :_right, x -> x * "_right"], mu in [true, false], vl in [true, false], vr in [true, false] @test outerjoin(df1, df2, on=[:id1, :id2 => :ID2], - makeunique = mu, validate = vl => vr, rename = l => r) ≅ + makeunique = mu, validate = vl => vr, renamecols = l => r) ≅ DataFrame(id1=[1,2,3,4], id2=[1,2,3,4], x_left=[1,2,3,missing], x_right=[1,2,missing,3]) end @test_throws ArgumentError outerjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:id1) + renamecols = "_left" => "_right", indicator=:id1) @test_throws ArgumentError outerjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:x_left) + renamecols = "_left" => "_right", indicator=:x_left) @test outerjoin(df1, df2, on=[:id1, :id2 => :ID2], - rename = "_left" => "_right", indicator=:ind) ≅ + renamecols = "_left" => "_right", indicator=:ind) ≅ DataFrame(id1=[1,2,3,4], id2=[1,2,3,4], x_left=[1,2,3,missing], x_right=[1,2,missing,3], ind=["both", "both", "left_only", "right_only"]) df1.x .+= 10 df2.x .+= 100 - @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = (x -> :id1) => "_right") - @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = (x -> :id1) => "_right", makeunique=true) == + @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = (x -> :id1) => "_right") + @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = (x -> :id1) => "_right", makeunique=true) == DataFrame(id1=1:2, id2=1:2, id1_1=11:12, x_right=101:102) - @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => (x -> :id2)) - @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => (x -> :id2), makeunique=true) == + @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => (x -> :id2)) + @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => (x -> :id2), makeunique=true) == DataFrame(id1=1:2, id2=1:2, x_left=11:12, id2_1=101:102) - @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => "_left") - @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => "_left", makeunique=true) == + @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => "_left") + @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => "_left", makeunique=true) == DataFrame(id1=1:2, id2=1:2, x_left=11:12, x_left_1=101:102) df2.y = df2.x .+ 1 - @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => (x -> :newcol)) - @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], rename = "_left" => (x -> :newcol), makeunique=true) == + @test_throws ArgumentError innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => (x -> :newcol)) + @test innerjoin(df1, df2, on=[:id1, :id2 => :ID2], renamecols = "_left" => (x -> :newcol), makeunique=true) == DataFrame(id1=1:2, id2=1:2, x_left=11:12, newcol=101:102, newcol_1=102:103) end