top of page
  • Nikos Mitrakis

Dadela: a new business-oriented data generation language

This article was originally published on Nerd@Work blog of Enrico Murru.


Dadela (pronounced dadèla) is a new programming language, designed with the intention to improve the way we generate data:

  • It’s business-oriented (not object-oriented): it can be used by a user without programming skills (e.g. a tester or a business analyst)

  • The language specifications is a project initiative on GitHub.

  • It was originally designed for Forceea data factory framework.

In Dadela we use the following language elements:

  • The Environment is the system (programming language or application) that hosts Dadela’s components and capabilities, sets the execution limitations and defines the integration details for sources and destinations

  • A component is a language element. There are various components: attributes, variables, lists, entity definitions, templates and operations

  • A repository is a physical (e.g. a file) or a virtual (e.g. a database record) storage for the components

  • A library is a special repository, containing templates and lists

  • A template is a blueprint for creating records of an entity

  • An entity is a database table or a matrix. It can be a Salesforce SObject, an Oracle table, an Excel worksheet, etc

  • An operation is a process that creates/inserts records or exports records in text format (JSON) or CSV).

  • A source is a one-way integration between an external database and the Environment for retrieving records. A destination has the opposite direction (from the Environment to an external entity for inserting/exporting records.

Lists play a key role in Dadela. A list is something like (item1, item2, item3), using a comma to separate the list items. In fact, all repository components can be considered as list items. Some examples:

number x: 100, # a numerical variable
list myList: (100, 200, 300), # a list
template BigAccounts: ( ... ), # a template
entity Account: ( ... ), # an entity definition 

Lists may contain other lists or variables. Variables are referenced using @ and lists with !

number myVar1: 100,
number myVar2: 1 + myVar1, # myVar2 = 101
list myList1: (one, two, three),
string five: five, # @five = "five"
list myList2: (!myList1, four, @five), # myList2 = {one, two, three, four, five} 

Of course, comments are inserted with #.

We don’t have the space to go deeper, but you’ve got the idea: the main usage of variables is to assign the same value to different components, facilitating the construction of entity definitions.

Create a template

The best way to understand a new language is “by example”. So, let’s suppose I am a business user trying to create and insert records for Opportunities, in order to prepare data for User Acceptance Testing (UAT).

In my Environment I’ll create a new repository (a library), with the name “SalesTemplates” and a template in the library for the “Opportunity” entity.

Repository: SalesTemplates

template BigOpportunities: (
    Name: copy field(AccountId) from(Description),
    Name: static value(" - "),
    Name: serial type(number) from(1) step(1) scale(0) format(000),
    Amount: random type(number) from(1M) to(10M) scale(-3),
    StageName: random type(picklist) except(Closed Won, Closed Lost)

Let’s “translate” the above, line by line:

template BigOpportunities: ( 
  • start the definition of a template called “BigOpportunities” and execute the following steps for each generated record

Name: copy field(AccountId) from(Name), 
  • for the values of the Opportunity field “Name”

  • find the Account record which is related to the lookup Opportunity field “AccountId” (the AccountId field stores the ID of a related Account record)

  • get the value of the (Account) field “Description” from this record

Name: static value(" - "), 
  • for the values of the Opportunity field “Name”

  • add the string ” – ” after the previous value

 Name: serial type(number) from(1) step(1) scale(0) format(000), 
  • for the values of the Opportunity field “Name”

  • get serial numbers starting from 1, adding 1, with rounding to 0 decimal points

  • format the result like 001, 002, 003, …

  • add the result after the previous value

 Amount: random type(number) from(1M) to(10M) scale(-3), 
  • for the values of the Opportunity field “Amount”

  • get random numbers, with minimum number 1,000,000, with maximum number 10,000,000, with rounding to 1,000

StageName: random type(picklist) except(Closed Won, losed Lost), 
  • for the values of the Opportunity field “StageName”

  • get any value from the picklist values of this field, except from “Closed Won” and “Closed Lost”

  • end the field definitions of this template

Field definitions

Dadela has many field definitions, in 4 types (commands):


  • These definitions copy the value of another field or the value of a field from a related (lookup) record


  • Static definitions just display a string, number, date/datetime or boolean value


The serial definitions create serial values for

  • numbers

  • dates and datetimes

  • lists


The random definitions create random values for

  • numbers, booleans and strings

  • dates and datetimes

  • lists and picklists

  • lookup fields

  • emails

  • phone numbers

  • URLs

  • addresses (street, postal code, city, province, country)

  • first and last names

  • text sentences

Create the entity definition

Now, let’s continue our example. In our Environment, we create a new repository, with the name “MyEntities”.

Repository: MyEntities

language: French, 
locality: France (North Europe, Europe, EU),  

entity Account: (
    records: 100,
    alias: BigAccounts,

    Rating: random type(picklist) except(Hot),
    Phone: random type(phone) format("(30) 210 dD-00-DD"),
    Industry: random type(picklist),
    Type: random type(list) value(Prospect, Customer - Direct, Customer - Channel), 
    # addresses
    ShippingStreet: random type(street) group(shipping),
    ShippingPostalCode: random type(postalcode) group(shipping),
    ShippingCity: random type(city) group(shipping),
    ShippingState: random type(state) group(shipping),
    ShippingCountry: random type(country) group(shipping)

entity Opportunity: (
    template: SalesTemplates.BigOpportunities,
    records: 200,
    alias: MyBigOpportunities,
    virtual MyField: random type(list) value(Closed Won, Closed Lost),
    StageName: copy from(MyField)

Let’s “translate” again:

language: French, 
  • the default language of names (first/last) and addresses in this repository will be “French”

locality: France (North Europe, Europe, EU), 
  • the default geographic area (locality) in this repository will be “France”, which will be a member of other localities (“North Europe”, “Europe” and “EU”)

entity Account: ( ... ), 
  • set the field definitions for accounts

  • with the default number of records to be 100

  • with random values for the fields Rating, Phone, Industry and Type

  • with random “real” addresses from France, in French

entity Opportunity: ( template: SalesTemplates.BigOpportunities, 
  • use the field definitions from template “BigOpportunities” in repository “SalesTemplates”

virtual MyField: random type(list) value(Closed Won, Closed Lost), 
  • define a “virtual” field: a virtual field is like a variable

StageName: copy from(MyField) 
  • get the value of the virtual field (we used this for demonstration purposes – in a real situation, we use more than one virtual fields to construct a field definition)

Note that the definition for the field “Amount” will be the same as the definition in the template (this is the purpose of a template, after all).

Of course, we could have defined a list for the stages inside the entity definition, or it could be a list in the repository or in a library, e.g.

entity Opportunity: (
    list stages: (Closed Won, Closed Lost),
    StageName: random type(list) value(!stages)


The next step is to generate and store our data.


If we want to insert the records into a “database”:

  • We configure a destination on our Environment. This destination could be a Salesforce org, or a SQL Server database.

  • We use an insert operation:

insert MyBigOpportunities: (
    destination(MySalesforceOrg1) group(MyGroupA)

The (optional) group parameter assigns a “tag” to the inserted records. This grouping is very helpful when we use the inserted records for further processing.


Another solution could be the create operation:

create MyBigOpportunities: (group(MyGroupA)), 

Now we just generate the opportunity records and we can insert or export them later.


And finally, for exporting to JSON or CSV:

export MyBigOpportunities: (
    type(json) group(MyGroupA)

No magic here! The Environment will export our opportunities in JSON format.


We had a very short introduction to the syntax and capabilities of Dadela. If you are interested to learn more, you can find all the details on GitHub.

Closing this article, I’d like to remind that the language specifications are open for discussion and contribution to the further development and application of the language..


bottom of page