Last week I was working on a Power BI custom data connector for a customer and I came across a problem that has been bothering me for a while. The “Invoke Custom Function” button is a very powerful feature (see here for how to use it) and I was doing something very similar in my code, but after you click it and expand the table column it returns, you always have to set the data types on the new columns that appear – even if the function you have invoked returns a table with data types set on columns. I wanted to avoid this extra step. I knew it was possible because some data sources like SQL Server give you typed columns when you expand a table column; I also saw that TripPin custom data connector tutorial aims to cover this topic… soon. Luckily it wasn’t too hard to work out.
Imagine you have the following function:
(x as number, y as number) as table => let Addition = x + y, Multiplication = x * y, Output = #table( type table [Operation=text, Result=number], { {"Addition", Addition}, {"Multiplication", Multiplication} }) in Output
It takes two numbers and returns a table with two columns and two rows showing the sum and the product of the two numbers. If the function is called AddAndMult, then the following expression:
AddAndMult(5, 6)
…returns the following table:
Notice that the function returns a table with data types set for the columns: Operation is a text column and Result is a number column. I’ve done this by specifying a table type in the first parameter of the #table() function as described here.
Now, here’s a query that calls the function on a table containing several rows using the Invoke Custom Function button:
let Source = #table( type table[x=number, y=number], { {4,7}, {8,2}, {1,9} }), #"Invoked Custom Function" = Table.AddColumn( Source, "AddAndMult", each AddAndMult([x], [y])), #"Expanded AddAndMult" = Table.ExpandTableColumn( #"Invoked Custom Function", "AddAndMult", {"Operation", "Result"}, {"AddAndMult.Operation", "AddAndMult.Result"}) in #"Expanded AddAndMult"
This is the table returned by the Source step:
This is what the Invoked Custom Function step looks like:
And this is what the Expanded AddAndMult step looks like:
In the last two screenshots the ABC123 icon in the column headers show that they are set to use the Any data type; the columns returned by calling the function have lost their data types.
The key to solving this problem is using the optional fourth parameter of the Table.AddColumn() function, which allows you to set a data type for the column that function adds to a table. Altering the Invoked Custom Function step of the previous query to do this, setting the new column to be a table type like so:
#"Invoked Custom Function" = Table.AddColumn( Source, "AddAndMult", each AddAndMult([x], [y]), type table [Operation=text, Result=number] ),
…means the Invoked Custom Function step now returns a column of type table, with the appropriate icon in the top left column:
…and once the AddAndMult column is expanded, the new columns have the desired data types set: