A favourite feature of mine in the 0.20 Vyne release is the upgrade to the expressions syntax in Taxi to be able to more effectively describe relationships between different data types.

Data consumers, you get a raw deal. It’s kind of a take it or leave it deal with the systems that provide them with data. You either accept the structure that the producer has designed or you have to do a bunch of work yourself to reshape it to what suits you.

Taxi Expressions are a powerful tool to start giving power back to data consumers. You can quickly express an operation that you need right there in your query so the data is ready to go when you receive it.

Let’s take a simple example from one of the Vyne demos. We’ve got a flight aggregation service, and a pretty standard part of the data model is seat data for a flight.

We arrive at a triad of data points which are related, but useful in different ways.

These are (ignoring different seating classes for simplicity):

  • Total seats on the flight
  • Number of seats sold
  • Number of seats available to buy

Some of the various uses of these values might be:

  • A consumer facing site aggregator service can display how many seats are left to buy on a flight
  • The catering service might need to know how much food and drink to load on the plane via the number of seats sold
  • A report might be needed for airline management to show the profitability of the flight by using the seats sold and total seats available properties.

However, different systems might represent these fields in different ways. Perhaps we only store the total seats available and the number of seats sold.

Enter Taxi expressions, stage left.

Given our two base properties:

type TotalSeats inherits Int
type NumberOfSeatsSold inherits Int

We can then express the relationship between these two fields using a Taxi expression:

type NumberOfSeatsAvailable by TotalSeats - NumberOfSeatsSold

As a result, if we’re querying this data through Vyne, all our consumers have to do is ask for the data they need and Vyne will apply the expression in order to create that field from the data available in the source system.

find { Flight( FlightId == ‘QF009’) } as {
    seats: {
        total: TotalSeats
        left: NumberOfSeatsAvailable
    }
}

We get a number of benefits from doing this:

  • Cleaner code - Our code isn’t littered with transformation logic. We can request the data we want from the data layer and immediately apply the logic which is core to the consuming service
  • Flexibility - If our consuming service isn’t flexible (e.g. it’s a legacy system, or cost of change is high.) then we can immediately reshape the data without needed to make a change to the producing system
  • Observability & Lineage - By representing transformations in the data layer, we can clearly track how systems are manipulating data and how it’s flowing through our systems end to end. This is otherwise known as data lineage and there’s a number of ways Vyne makes this visible. The alternative is that this logic is obscured in the code of the consuming system.

This works equally well with operations on other types such as Dates and Booleans, and other arithmetic operations such as greater than, less than, and equality conditions.

It’s also just one of a number of features in Taxi that let query writers express how they want to receive data more accurately.

Check it out at taxilang.org