# Runs

Exercise every run operation.

nominalexample_rundemo.m

```matlab
function results = nominalexample_rundemo(assetName)
%NOMINALEXAMPLE_RUNDEMO  Exercise every run operation.
%
%   nominalexample_rundemo                   % throwaway asset
%   nominalexample_rundemo("engine-3")       % under an existing asset
%
%   Needs credentials. Creates an asset, a dataset, and a run over them, then
%   closes it.
%
%   Covers: create with an explicit start, get by RID, adding and removing
%   an asset, a run from a tagged dataset with no asset, update, setting one
%   property, all accessors, finish, and searching for it. Not addDataset: a
%   run's data sources are its asset's, so there is nothing to attach.
%
%   See also NOMINAL.RUN, NOMINALEXAMPLE_ASSETDEMO,
%   NOMINALEXAMPLE_EVENTDEMO, NOMINALEXAMPLE_CONNECT

    arguments
        assetName (1,1) string = "nominal-matlab-demo-" + string(posixtime(datetime("now")))
    end

    client = nominalexample_connect();
    asset = client.getOrCreateAsset(assetName);
    % AttachExisting=false so a demo asset does not adopt someone else's
    % existing "telemetry" dataset.
    dataset = asset.getOrCreateDataset("telemetry", "tlm", AttachExisting=false);
    fprintf('Asset %s / dataset %s\n', asset.Name, dataset.Name);

    % --- create -------------------------------------------------------
    %
    % Started a minute ago so the window covers data already written. Omit
    % the argument to start now.
    %
    % Each mutation below returns a new object: openRun -> sharedRun ->
    % soloRun -> updatedRun -> notedRun -> finishedRun. Earlier objects keep reporting
    % their older state.
    runStartTime = datetime("now", TimeZone="UTC") - minutes(1);
    openRun = asset.run("matlab-demo-run", runStartTime);

    fprintf('Run "%s"\n', openRun.Name);
    fprintf('  rid    %s\n', openRun.Rid);
    fprintf('  number %d\n', openRun.Number);
    fprintf('  url    %s\n', openRun.Url);
    fprintf('  start  %s\n', string(openRun.StartTime));

    % An open run's EndTime is NaT. Test for it, since fprintf cannot format
    % string(NaT).
    if isnat(openRun.EndTime)
        fprintf('  end    (none yet - the run is open)\n');
    else
        fprintf('  end    %s\n', string(openRun.EndTime));
    end

    % --- fetch by RID -------------------------------------------------
    sameRunByRid = client.runByRid(openRun.Rid);
    fprintf('  refetched by rid, number matches: %d\n', ...
            sameRunByRid.Number == openRun.Number);

    % --- the run's data ------------------------------------------------
    %
    % A run's data sources are its asset's, live. The dataset above is already
    % on the run, and so is anything attached to the asset later. Nothing needs
    % attaching, and nominal.Run.addDataset cannot succeed for a run made with
    % asset.run().
    fprintf('  data sources come from the asset; nothing to attach\n');

    % --- more than one asset ------------------------------------------
    %
    % A run can span several assets, say a test chamber and the unit in it.
    % createAsset always makes a new asset, where getOrCreateAsset would reuse
    % one of the same name.
    chamber = client.createAsset(asset.Name + " chamber");
    sharedRun = openRun.addAsset(chamber);
    fprintf('  on %d assets after addAsset\n', numel(sharedRun.AssetRids));
    soloRun = sharedRun.removeAsset(chamber);
    fprintf('  on %d asset after removeAsset\n', numel(soloRun.AssetRids));

    % --- a run with no asset of its own -------------------------------
    %
    % For data with no physical system behind it, such as one run per
    % simulation execution: the run reads only the series with these tags,
    % and Nominal keeps it on a hidden asset.
    executionRun = client.createRun(asset.Name + " execution 7", dataset, ...
        Tags = dictionary(["model" "execution-id"], ["A" "7"]), ...
        StartTime = int64(0), EndTime = int64(60e9));
    fprintf('  from a dataset: %s to %s, %d visible asset(s) named after it\n', ...
            string(executionRun.StartTime), string(executionRun.EndTime), ...
            height(client.assets(executionRun.Name)));

    % --- update -------------------------------------------------------
    %
    % update accepts start and end times as well as these metadata fields.
    % Collections replace, they do not merge.
    updatedRun = soloRun.update( ...
        Description = "Created by the Nominal MATLAB demo", ...
        Labels      = ["matlab-demo" "smoke"], ...
        Properties  = struct(operator = "matlab", phase = "demo"));

    fprintf('  description: %s\n', updatedRun.Description);
    fprintf('  labels:      %s\n', join(updatedRun.Labels, " "));
    fprintf('  operator:    %s\n', updatedRun.property("operator"));

    % setProperty changes one key and keeps the rest. Properties is a
    % containers.Map of all of them.
    notedRun = updatedRun.setProperty("result", "pass");
    fprintf('  properties:  %s\n', strjoin(keys(notedRun.Properties), ", "));

    % --- close it -----------------------------------------------------
    %
    % No argument means end now.
    finishedRun = notedRun.finish();
    fprintf('  end    %s (closed)\n', string(finishedRun.EndTime));
    fprintf('  span   %s\n', string(finishedRun.EndTime - finishedRun.StartTime));

    % --- find it again ------------------------------------------------
    %
    % Every label and property given must match. StartAfter keeps this
    % search to runs from this demo.
    found = client.runs("matlab-demo-run", Labels = "smoke", ...
                        Properties = struct(result = "pass"), StartAfter = runStartTime);
    fprintf('  found by name, label and property: %d run(s)\n', height(found));

    % --- results ------------------------------------------------------
    %
    % Read from finishedRun, the only object that reflects every change.
    results = struct( ...
        'Rid',         finishedRun.Rid, ...
        'Name',        finishedRun.Name, ...
        'Number',      finishedRun.Number, ...
        'Url',         finishedRun.Url, ...
        'Description', finishedRun.Description, ...
        'Labels',      finishedRun.Labels, ...
        'StartTime',   finishedRun.StartTime, ...
        'EndTime',     finishedRun.EndTime, ...
        'DatasetRid',  dataset.Rid);

    % --- teardown -----------------------------------------------------
    %
    % Each object in the chain needs its own delete.
    delete(finishedRun);
    delete(notedRun);
    delete(updatedRun);
    delete(executionRun);
    delete(soloRun);
    delete(sharedRun);
    delete(chamber);
    delete(sameRunByRid);
    delete(openRun);
    delete(dataset);
    delete(asset);
    delete(client);

    nominalexample_publish(results, "nominalRun");
end
```

Source: [`matlab/examples/nominalexample_rundemo.m`](https://github.com/nominal-io/matlab-client-rs/blob/main/matlab/examples/nominalexample_rundemo.m)
