Skip to content

Model CSV plugin

Adds an import CSV { … } block to the model language, so a model can take its objects from .csv files instead of listing them one by one. A spreadsheet of two hundred tasks becomes a model without two hundred hand-written objects.

At a glance

Plugin idmodel-csv-service
Display nameModel CSV
DescriptionLanguage support for the CSV import contribution to the model language
Default URL/plugin/model-csv
Sourceapp/packages/service-model-csv, app/packages/language-model-csv
Depends onThe Model and Metamodel plugins; the data files are usually CSV files

Only started by the development compose file

infra/docker-compose-dev.yaml builds this service and lists it in DEFAULT_PLUGIN_URLS. docker-compose.yaml and docker-compose-prod.yaml do not, so a production deployment has to add the service and register /plugin/model-csv itself.

Languages contributed

Language idNameExtensionTextual editorGraphical editorGenerated
model-csvModel CSV

The model-csv language

A generated language with no file extension and no editor, following the same pattern as the config contribution plugins: it exists so the import block can be parsed as a language in its own right when the model service asks for the imported data to be computed.

Contribution plugins contributed

Target languageWhat it adds
modelThe import CSV { … } block
Contribution plugin idmodel-csv
Short namecsv
Additional keywordsimport, CSV, from
Exported typesnone

The import block

mdeo-model
using "./tasks.mm"

import CSV {
    Task from "./tasks.csv"
    Employee from "./employees.csv"
}

Each entry maps one metamodel class to one CSV file. The class is a cross-reference into the metamodel named by using, so it is completed and validated in the editor like any other class name.

The same class may be imported from several files; the rows are appended.

How rows become objects

The rules below are applied by the plugin's request handler when the model service computes the model's data.

One row, one object. The header row names properties of the class; each following row becomes one object. Objects are named <Class>_<n>, numbered from zero across all files importing that class.

Values are converted to the declared type. A cell is read according to the property's type in the metamodel:

Property typeCell
int, longParsed as an integer; a value that does not parse is kept as text
float, doubleParsed as a decimal; a value that does not parse is kept as text
booleantrue (case-insensitive) is true, everything else is false
enumThe cell is the entry name, e.g. BLUE
Everything elseText

An empty cell becomes null.

References use the _id column. A reference column holds the _id value of the target row, and several targets are separated by ;:

csv
_id,name,assignee
t1,Design,e1
t2,Build,e1;e2

_id is only a lookup key for the import — it does not become a property of the object.

Problems are warnings, not errors. The import never fails, it records what it could not do:

SituationResult
Class not in the metamodelThe entry is skipped
File with only a headerThe entry is skipped
Column matching no propertyThe column is ignored
Row shorter than the headerMissing cells treated as blank
Row longer than the headerExtra cells ignored
Reference to an unknown _idThe link is dropped

The warnings travel back to the model service in the warnings field of the response, but nothing surfaces them yet — a malformed row currently shows up as a missing or oddly-valued object rather than as a message in the editor.

Server-side capabilities

KeyContents
astThe serialised AST of the import block

The plugin answers the model plugin's request for imported objects. The model service hands over the text of the import CSV block together with a description of the metamodel's classes; this plugin parses that text, reads the referenced .csv files itself, and returns instances and links which the model service merges into the model data the execution services consume.

Class names arrive as plain reference text rather than as resolved references, because the metamodel document is not loaded in this service — the model service has already validated them.

Released under the terms of the repository licence.