Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/badges/tests.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 55 additions & 41 deletions code/+openminds/@Collection/Collection.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

% Todo: Validation.
% - Linked subject states should have same subject
% - Add method to update links for specified instances

% Need mechanism to check if embedded nodes are added to the collection

Expand All @@ -51,7 +52,7 @@
NumNodes
NumTypes
end

properties (SetAccess = protected)
% Nodes - Dictionary storing instances as values with identifiers
% as keys
Expand All @@ -66,11 +67,11 @@

properties (SetAccess = protected)
LinkResolver

% MetadataStore - Optional metadata store for saving/loading
MetadataStore openminds.interface.MetadataStore = openminds.internal.FileMetadataStore.empty
end

methods % Constructor
function obj = Collection(instance, options)
% Create an instance of an openMINDS collection
Expand All @@ -97,7 +98,7 @@
% creates a collection with the specified metadata store. If no
% instances are provided, the collection will automatically load
% instances from the store.

% collection = openminds.Collection(..., NameA, ValueA, ... )
% also specifies optional name value pairs when creating the
% collection.
Expand All @@ -106,7 +107,7 @@
% - Name : A name for the collection
% - Description : A description of the collection
% - MetadataStore : A metadata store for saving/loading instances

arguments (Repeating)
instance % openminds.abstract.Schema
end
Expand All @@ -126,13 +127,13 @@
obj.Nodes = containers.Map;
obj.TypeMap = containers.Map;
end

obj.initializeFromInstances(instance)

obj.Name = options.Name;
obj.Description = options.Description;
obj.MetadataStore = options.MetadataStore;

% Auto-load from MetadataStore if provided and no instances given
if isempty(instance) && ~isempty(obj.MetadataStore)
obj.load();
Expand All @@ -148,7 +149,7 @@
numNodes = length(obj.Nodes);
end
end

function numTypes = get.NumTypes(obj)
if isa(obj.TypeMap, 'dictionary')
numTypes = numEntries(obj.TypeMap);
Expand Down Expand Up @@ -190,16 +191,19 @@ function add(obj, instance, options)
end
arguments
options.AddSubNodesOnly = false;
options.AbortIfNodeExists = true;
end

for i = 1:numel(instance)
thisInstance = instance{i};
for j = 1:numel(thisInstance) % If thisInstance is an array
obj.addNode(thisInstance(j), "AddSubNodesOnly", options.AddSubNodesOnly);
obj.addNode(thisInstance(j), ...
"AddSubNodesOnly", options.AddSubNodesOnly, ...
"AbortIfNodeExists", options.AbortIfNodeExists);
end
end
end

function tf = contains(obj, instance)
% Todo:work for arrays
tf = false;
Expand All @@ -210,10 +214,10 @@ function add(obj, instance, options)
end
end
end

function remove(obj, instance)
% remove - Remove metadata instance from the collection

if isstring(instance) || ischar(instance)
instanceId = instance;
elseif openminds.utility.isInstance(instance)
Expand Down Expand Up @@ -250,11 +254,11 @@ function remove(obj, instance)
instance = instance{1};
end
end

function instances = getAll(obj)
% getAll - Get all instances of collection
instances = obj.Nodes.values();

% For older MATLAB releases, the instances might be nested a
% cell array, need to unnest if that's the case:
if iscell(instances{1})
Expand All @@ -269,11 +273,11 @@ function remove(obj, instance)
end

tf = false;

if obj.NumNodes == 0
return
end

typeKeys = obj.TypeMap.keys;
tf = any( endsWith(typeKeys, "."+type) ); %i.e ".Person"
end
Expand All @@ -293,10 +297,10 @@ function remove(obj, instance)
if obj.NumNodes == 0
return
end

instanceKeys = obj.getInstanceKeysForType(type);
if isempty(instanceKeys); return; end

if isa(obj.Nodes, 'dictionary')
instances = obj.Nodes(instanceKeys);
else
Expand Down Expand Up @@ -327,6 +331,10 @@ function updateLinks(obj)
allInstances = [allInstances{:}];
end

if iscolumn(allInstances)
allInstances = reshape(allInstances, 1, []);
end

for instance = allInstances
obj.addNode(instance{1}, ...
'AddSubNodesOnly', true, ...
Expand Down Expand Up @@ -360,22 +368,22 @@ function updateLinks(obj)
% ------
%
% outputPaths (cell): A list of the file paths created.

arguments
obj openminds.Collection
savePath (1,1) string = ""
options.MetadataStore openminds.interface.MetadataStore = openminds.internal.FileMetadataStore.empty
% options.SaveFormat = "jsonld" Implement if more formats are supported
end

% Update links before saving
obj.updateLinks()
instances = obj.getAll();

if savePath ~= ""
tempStore = openminds.internal.store.createTemporaryStore(savePath);
outputPaths = tempStore.save(instances);

elseif ~isempty(options.MetadataStore)
outputPaths = obj.MetadataStore.save(instances);

Expand All @@ -387,7 +395,7 @@ function updateLinks(obj)
error('openminds:Collection:NoSavePath', ...
'Either provide savePath or configure a MetadataStore');
end

if ~nargout
clear outputPaths
end
Expand Down Expand Up @@ -436,7 +444,7 @@ function load(obj, loadPath, options)
error('openminds:Collection:PathNotFound', 'Path not found: %s', loadPath);
end
end

for i = 1:numel(instances)
if openminds.utility.isInstance(instances{i})
obj.addNode(instances{i});
Expand Down Expand Up @@ -469,13 +477,13 @@ function load(obj, loadPath, options)
% --------
% collection : openminds.Collection
% A new collection loaded with instances from the store

arguments
metadataStore (1,1) openminds.interface.MetadataStore
options.Name (1,1) string = ""
options.Description (1,1) string = ""
end

% Create collection with the metadata store
collection = openminds.Collection('MetadataStore', metadataStore, ...
'Name', options.Name, 'Description', options.Description);
Expand All @@ -493,14 +501,18 @@ function load(obj, loadPath, options)
end

wasAdded = false;

if isempty(instance.id)
instance.id = obj.getBlankNodeIdentifier();
end

% Do not add openminds controlled term instances
if startsWith(instance.id, "https://openminds.ebrains.eu/instances/")
return
% Do not add openminds controlled term instances if disabled in
% preferences
if startsWith(instance.id, "https://openminds.ebrains.eu/instances/") ...
|| startsWith(instance.id, "https://openminds.om-i.org/instances/")
if ~openminds.getpref('AddControlledInstanceToCollection')
return
end
end

if obj.NumNodes > 0
Expand All @@ -511,7 +523,10 @@ function load(obj, loadPath, options)
end
end
end


% Add subnodes first
obj.addSubNodes(instance)

if ~options.AddSubNodesOnly
obj.Nodes(instance.id) = {instance};
wasAdded = true;
Expand All @@ -529,13 +544,12 @@ function load(obj, loadPath, options)
obj.TypeMap(instanceType) = {string(instance.id)};
end
end

obj.addSubNodes(instance)

if ~nargout
clear wasAdded
end
end

% Add sub node instances (linked types) to the Node container.
function addSubNodes(obj, instance)
% Add links.
Expand All @@ -552,7 +566,7 @@ function addSubNodes(obj, instance)
obj.addNode(embeddedInstances{i}, 'AddSubNodesOnly', true);
end
end

function identifier = getBlankNodeIdentifier(obj)
fmt = '_:%06d';
identifier = length(obj) + 1;
Expand All @@ -567,19 +581,19 @@ function initializeFromInstances(obj, instance)
isFilePath = @(x) (ischar(x) || isstring(x)) && isfile(x);
isFolderPath = @(x) (ischar(x) || isstring(x)) && isfolder(x);
isMetadata = @(x) openminds.utility.isInstance(x);

% Initialize from file(s)
if all( cellfun(isFilePath, instance) )
obj.load(instance{:})

% Initialize from folder
elseif all( cellfun(isFolderPath, instance) )
obj.load(instance{:})

% Initialize from instance(s)
elseif all( cellfun(isMetadata, instance) )
obj.add(instance{:});

else
ME = MException(...
'OPENMINDS_MATLAB:Collection:InvalidInstanceSpecification', ...
Expand All @@ -597,7 +611,7 @@ function initializeFromInstances(obj, instance)

if obj.NumTypes > 0
typeKeys = obj.TypeMap.keys;

isMatch = strcmp(typeKeys, instanceType.ClassName);
if any(isMatch)
if isa(obj.TypeMap, 'dictionary')
Expand All @@ -615,9 +629,9 @@ function initializeFromInstances(obj, instance)
instanceKeys = {};
return
end

existingKeys = obj.Nodes.keys();

% Sanity check, make sure all keys exist in Nodes dictionary
assert( all( ismember( instanceKeys, existingKeys ) ), ...
'TypeMap has too many keys' )
Expand Down
1 change: 1 addition & 0 deletions code/+openminds/getpref.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
[ ...
"PropertyDisplayMode", ...
"DocLinkTarget", ...
"AddControlledInstanceToCollection", ...
"" ...
])...
} = ""
Expand Down
2 changes: 1 addition & 1 deletion code/+openminds/instanceFromIRI.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
end

[typeEnum, instanceName] = openminds.utility.parseInstanceIRI(IRI);

if contains(typeEnum.ClassName, "controlledterms")
instance = feval(typeEnum.ClassName, IRI);
else
Expand Down
2 changes: 1 addition & 1 deletion code/+openminds/setpref.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
end

pref = openminds.utility.Preferences.getSingleton;

prefNames = fieldnames(prefValues);
for i = 1:numel(prefNames)
preferenceName = prefNames{i};
Expand Down
4 changes: 2 additions & 2 deletions code/+openminds/startup.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function startup(version)
%
% This function ensures that only one version of openMINDS schema classes
% are on MATLAB's search path.

arguments
version (1,1) openminds.internal.utility.VersionNumber ...
{openminds.mustBeValidVersion(version)} = "latest"
Expand All @@ -14,7 +14,7 @@ function startup(version)
% NB: Assumes this function is located in code/+openminds:
codePath = fileparts( fileparts( mfilename('fullpath') ) );
addpath( fullfile(codePath, 'internal') )

% Run internal function that correctly configures the search path
openminds.selectOpenMindsVersion(version)
fprintf(['Added classes for version "%s" of the openMINDS metadata model ' ...
Expand Down
2 changes: 1 addition & 1 deletion code/+openminds/toolboxversion.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
contentsFile = fullfile(rootPath, 'Contents.m');

fileStr = fileread(contentsFile);

% First try to get a version with a sub-patch version number
matchedStr = regexp(fileStr, 'Version \d*\.\d*\.\d*.\d*(?= )', 'match');

Expand Down
Loading
Loading