From addeedd07d76cf52477fb5f4adf4972b2c682033 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 05:52:14 +0200 Subject: [PATCH 01/12] fix: use collection save metadata store option --- code/+openminds/@Collection/Collection.m | 2 +- tools/tests/unitTests/CollectionTest.m | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/code/+openminds/@Collection/Collection.m b/code/+openminds/@Collection/Collection.m index e7d3616a..1eebea87 100644 --- a/code/+openminds/@Collection/Collection.m +++ b/code/+openminds/@Collection/Collection.m @@ -385,7 +385,7 @@ function updateLinks(obj) outputPaths = tempStore.save(instances); elseif ~isempty(options.MetadataStore) - outputPaths = obj.MetadataStore.save(instances); + outputPaths = options.MetadataStore.save(instances); elseif ~isempty(obj.MetadataStore) % Use configured store diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index e4c82691..4f7a3adf 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -337,6 +337,17 @@ function testSaveInstances(testCase) % Verify that instances are loaded testCase.verifyEqual(length(instances), expectedNumDocuments); end + + function testSaveUsesMethodMetadataStoreOption(testCase) + collection = openminds.Collection(organizationWithOneId()); + filePath = "method-store-option.jsonld"; + metadataStore = openminds.internal.FileMetadataStore(filePath); + + outputPath = collection.save("", "MetadataStore", metadataStore); + + testCase.verifyEqual(outputPath, filePath); + testCase.verifyTrue(isfile(filePath)); + end % % function testGetBlankNodeIdentifier(testCase) % % % Test the getBlankNodeIdentifier method From 70833d6effb35d7d0bf412f0f7707f59cf0aa495 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 05:53:07 +0200 Subject: [PATCH 02/12] fix: load homogeneous graph instances separately --- .../+internal/+store/loadInstances.m | 14 +++++++++++++- tools/tests/unitTests/CollectionTest.m | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/code/internal/+openminds/+internal/+store/loadInstances.m b/code/internal/+openminds/+internal/+store/loadInstances.m index e347834f..04ae2971 100644 --- a/code/internal/+openminds/+internal/+store/loadInstances.m +++ b/code/internal/+openminds/+internal/+store/loadInstances.m @@ -25,10 +25,10 @@ % Produce a cell array of instances represented as structs if isscalar(str) structInstances = jsonld2struct(str); - if ~iscell(structInstances); structInstances={structInstances};end else structInstances = cellfun(@jsonld2struct, str, 'UniformOutput', false); end + structInstances = normalizeStructInstances(structInstances); % Create instance objects instances = cell(size(structInstances)); @@ -75,6 +75,18 @@ end end +function structInstances = normalizeStructInstances(structInstances) +%normalizeStructInstances Return one cell element per serialized instance. + + if iscell(structInstances) + structInstances = cellfun(@normalizeStructInstances, ... + structInstances, 'UniformOutput', false); + structInstances = [structInstances{:}]; + else + structInstances = num2cell(reshape(structInstances, 1, [])); + end +end + function resolveLinks(instance, instanceIds, instanceCollection) %resolveLinks Resolve linked types, i.e replace an @id with the actual % instance object. diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 4f7a3adf..001388e1 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -317,6 +317,24 @@ function testLoadInstances(testCase) % Verify that instances are loaded testCase.verifyEqual(length(instances), expectedNumDocuments); end + + function testLoadHomogeneousGraphAsSeparateInstances(testCase) + firstContact = openminds.core.ContactInformation( ... + "email", "first@example.org"); + secondContact = openminds.core.ContactInformation( ... + "email", "second@example.org"); + + filePath = "homogeneous-graph.jsonld"; + openminds.internal.FileMetadataStore(filePath).save( ... + [firstContact, secondContact]); + + newCollection = openminds.Collection(); + newCollection.load(filePath); + + testCase.verifyEqual(length(newCollection), 2); + testCase.verifyTrue(newCollection.isKey(firstContact.id)); + testCase.verifyTrue(newCollection.isKey(secondContact.id)); + end function testSaveInstances(testCase) % Tests saving instances with MetadataStore From 4fb4b2ec40cb16b874dd4c1a4a32b6cb3511589c Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 05:53:51 +0200 Subject: [PATCH 03/12] fix: load collection constructor paths individually --- code/+openminds/@Collection/Collection.m | 8 ++++++-- tools/tests/unitTests/CollectionTest.m | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/code/+openminds/@Collection/Collection.m b/code/+openminds/@Collection/Collection.m index 1eebea87..29fe3ed4 100644 --- a/code/+openminds/@Collection/Collection.m +++ b/code/+openminds/@Collection/Collection.m @@ -584,11 +584,15 @@ function initializeFromInstances(obj, instance) % Initialize from file(s) if all( cellfun(isFilePath, instance) ) - obj.load(instance{:}) + for i = 1:numel(instance) + obj.load(instance{i}) + end % Initialize from folder elseif all( cellfun(isFolderPath, instance) ) - obj.load(instance{:}) + for i = 1:numel(instance) + obj.load(instance{i}) + end % Initialize from instance(s) elseif all( cellfun(isMetadata, instance) ) diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 001388e1..1489bbe5 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -295,6 +295,24 @@ function testSaveToMultipleFiles(testCase) testCase.verifyTrue(newCollection.isKey(person.id)); testCase.verifyTrue(newCollection.isKey(org.id)); end + + function testCreateCollectionFromMultipleFiles(testCase) + firstContact = openminds.core.ContactInformation( ... + "email", "first@example.org"); + secondContact = openminds.core.ContactInformation( ... + "email", "second@example.org"); + + firstFilePath = "first-contact.jsonld"; + secondFilePath = "second-contact.jsonld"; + openminds.internal.FileMetadataStore(firstFilePath).save(firstContact); + openminds.internal.FileMetadataStore(secondFilePath).save(secondContact); + + collection = openminds.Collection(firstFilePath, secondFilePath); + + testCase.verifyEqual(length(collection), 2); + testCase.verifyTrue(collection.isKey(firstContact.id)); + testCase.verifyTrue(collection.isKey(secondContact.id)); + end function testLoadInstances(testCase) % Test the loadInstances static method From 02a797fd3ed95fe29e8541df6effe131b6bfc068 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 05:54:50 +0200 Subject: [PATCH 04/12] fix: save recursive folder store documents --- .../+internal/FolderMetadataStore.m | 23 ++++++++++++------- tools/tests/unitTests/CollectionTest.m | 18 +++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/code/internal/+openminds/+internal/FolderMetadataStore.m b/code/internal/+openminds/+internal/FolderMetadataStore.m index 64d918f5..58b40759 100644 --- a/code/internal/+openminds/+internal/FolderMetadataStore.m +++ b/code/internal/+openminds/+internal/FolderMetadataStore.m @@ -98,7 +98,8 @@ % Save each document to a separate file outputPaths = cell(size(serializedDocuments)); for i = 1:numel(serializedDocuments) - instance = instances{i}; + instance = openminds.internal.serializer.jsonld2struct( ... + serializedDocuments{i}); % Build file path using unified method filePath = obj.buildFilepath(instance); @@ -180,13 +181,7 @@ % Flat: /root/Person_123.jsonld % Nested: /root/person/123.jsonld - % Get instance type and ID information - className = class(instance); - classNameParts = strsplit(className, '.'); - typeName = classNameParts{end}; - - % Get instance ID and make it filesystem-safe - instanceId = string(instance.id); + [typeName, instanceId] = getTypeNameAndId(instance); if startsWith(instanceId, "http") idParts = strsplit(instanceId, '/'); safeId = idParts{end}; @@ -212,3 +207,15 @@ end end end + +function [typeName, instanceId] = getTypeNameAndId(instance) + if isstruct(instance) + typeNameParts = strsplit(instance.at_type, '/'); + typeName = typeNameParts{end}; + instanceId = string(instance.at_id); + else + classNameParts = strsplit(class(instance), '.'); + typeName = classNameParts{end}; + instanceId = string(instance.id); + end +end diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 1489bbe5..5b42a3f5 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -296,6 +296,24 @@ function testSaveToMultipleFiles(testCase) testCase.verifyTrue(newCollection.isKey(org.id)); end + function testFolderStoreSavesRecursiveLinkedDocuments(testCase) + identifier = openminds.core.ORCID( ... + "identifier", "https://orcid.org/0000-0000-0000-0000"); + person = openminds.core.Person("digitalIdentifier", identifier); + + folderPath = "recursive-folder-store"; + metadataStore = openminds.internal.FolderMetadataStore( ... + folderPath, "RecursionDepth", 1); + + outputPaths = metadataStore.save(person); + + files = dir(fullfile(folderPath, "*.jsonld")); + testCase.verifyEqual(numel(outputPaths), 2); + testCase.verifyEqual(numel(files), 2); + testCase.verifyTrue(any(contains(string(outputPaths), "Person_"))); + testCase.verifyTrue(any(contains(string(outputPaths), "ORCID_"))); + end + function testCreateCollectionFromMultipleFiles(testCase) firstContact = openminds.core.ContactInformation( ... "email", "first@example.org"); From af2ea40906866da0abd0e0473c52ece5bfc4080f Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 05:55:32 +0200 Subject: [PATCH 05/12] fix: return empty collection contents --- code/+openminds/@Collection/Collection.m | 5 +++++ tools/tests/unitTests/CollectionTest.m | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/code/+openminds/@Collection/Collection.m b/code/+openminds/@Collection/Collection.m index 29fe3ed4..500d4d93 100644 --- a/code/+openminds/@Collection/Collection.m +++ b/code/+openminds/@Collection/Collection.m @@ -257,6 +257,11 @@ function remove(obj, instance) function instances = getAll(obj) % getAll - Get all instances of collection + if obj.NumNodes == 0 + instances = {}; + return + end + instances = obj.Nodes.values(); % For older MATLAB releases, the instances might be nested a diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 5b42a3f5..6253d647 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -184,6 +184,14 @@ function testGet(testCase) ommtest.oneoffs.organizationName(retrievedOrg), ... ommtest.oneoffs.organizationName(org)); end + + function testGetAllEmptyCollection(testCase) + collection = openminds.Collection(); + + instances = collection.getAll(); + + testCase.verifyEqual(instances, {}); + end function testHasType(testCase) % Test the hasType method From 36a5b6eae621386f870b2edd06d0f16c676d4af0 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 06:16:42 +0200 Subject: [PATCH 06/12] fix: save scalar folder store documents --- .../+openminds/+internal/FolderMetadataStore.m | 3 +++ tools/tests/unitTests/CollectionTest.m | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/code/internal/+openminds/+internal/FolderMetadataStore.m b/code/internal/+openminds/+internal/FolderMetadataStore.m index 58b40759..5808910b 100644 --- a/code/internal/+openminds/+internal/FolderMetadataStore.m +++ b/code/internal/+openminds/+internal/FolderMetadataStore.m @@ -94,6 +94,9 @@ % Serialize instances to individual documents serializedDocuments = obj.Serializer.serialize(instances); + if ~iscell(serializedDocuments) + serializedDocuments = {serializedDocuments}; + end % Save each document to a separate file outputPaths = cell(size(serializedDocuments)); diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 6253d647..abe1ab87 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -322,6 +322,20 @@ function testFolderStoreSavesRecursiveLinkedDocuments(testCase) testCase.verifyTrue(any(contains(string(outputPaths), "ORCID_"))); end + function testFolderStoreSavesScalarInstance(testCase) + contact = openminds.core.ContactInformation( ... + "email", "contact@example.org"); + folderPath = "scalar-folder-store"; + metadataStore = openminds.internal.FolderMetadataStore(folderPath); + + outputPaths = metadataStore.save(contact); + + testCase.verifyEqual(numel(outputPaths), 1); + testCase.verifyTrue(isfile(outputPaths{1})); + testCase.verifyTrue(contains(string(outputPaths{1}), ... + "ContactInformation_")); + end + function testCreateCollectionFromMultipleFiles(testCase) firstContact = openminds.core.ContactInformation( ... "email", "first@example.org"); From 5c66a74695ce248a7bdc9725a1a6b58c99188c84 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 06:17:20 +0200 Subject: [PATCH 07/12] fix: save empty collections --- code/+openminds/@Collection/Collection.m | 4 ++++ tools/tests/unitTests/CollectionTest.m | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/code/+openminds/@Collection/Collection.m b/code/+openminds/@Collection/Collection.m index 500d4d93..115aec81 100644 --- a/code/+openminds/@Collection/Collection.m +++ b/code/+openminds/@Collection/Collection.m @@ -331,6 +331,10 @@ function remove(obj, instance) end function updateLinks(obj) + if obj.NumNodes == 0 + return + end + allInstances = obj.Nodes.values; if isa(obj.Nodes, 'containers.Map') allInstances = [allInstances{:}]; diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index abe1ab87..b0c61ffb 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -192,6 +192,16 @@ function testGetAllEmptyCollection(testCase) testCase.verifyEqual(instances, {}); end + + function testSaveEmptyCollection(testCase) + collection = openminds.Collection(); + filePath = "empty-collection.jsonld"; + + outputPath = collection.save(filePath); + + testCase.verifyEqual(outputPath, filePath); + testCase.verifyTrue(isfile(filePath)); + end function testHasType(testCase) % Test the hasType method From 0d5687f9770790a2f024fdecb9831084cd898a70 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 06:19:53 +0200 Subject: [PATCH 08/12] fix: preserve unresolved graph links --- .../+internal/+store/loadInstances.m | 2 ++ tools/tests/unitTests/CollectionTest.m | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/code/internal/+openminds/+internal/+store/loadInstances.m b/code/internal/+openminds/+internal/+store/loadInstances.m index 04ae2971..2cd2a466 100644 --- a/code/internal/+openminds/+internal/+store/loadInstances.m +++ b/code/internal/+openminds/+internal/+store/loadInstances.m @@ -124,6 +124,8 @@ function resolveLinks(instance, instanceIds, instanceCollection) % Check if instance is a controlled instance if startsWith(instanceId, "https://openminds.ebrains.eu/instances/") resolvedInstances{j} = openminds.instanceFromIRI(instanceId); + else + resolvedInstances{j} = linkedInstances(j); end end end diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index b0c61ffb..1b3a6f4c 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -403,6 +403,32 @@ function testLoadHomogeneousGraphAsSeparateInstances(testCase) testCase.verifyTrue(newCollection.isKey(firstContact.id)); testCase.verifyTrue(newCollection.isKey(secondContact.id)); end + + function testLoadPreservesPartiallyUnresolvedLinks(testCase) + firstIdentifier = openminds.core.ORCID( ... + "identifier", "https://orcid.org/0000-0000-0000-0001"); + secondIdentifier = openminds.core.ORCID( ... + "identifier", "https://orcid.org/0000-0000-0000-0002"); + person = openminds.core.Person( ... + "digitalIdentifier", [firstIdentifier, secondIdentifier]); + + serializer = openminds.internal.serializer.JsonLdSerializer( ... + "OutputMode", "single", ... + "RecursionDepth", 0); + filePath = "partial-graph.jsonld"; + openminds.internal.utility.filewrite( ... + filePath, serializer.serialize({person, firstIdentifier})); + + instances = openminds.internal.store.loadInstances(filePath); + loadedPerson = instances{1}; + loadedIdentifiers = loadedPerson.digitalIdentifier; + + testCase.verifyEqual(numel(loadedIdentifiers), 2); + testCase.verifyEqual(loadedIdentifiers(1).Instance.id, ... + firstIdentifier.id); + testCase.verifyEqual(loadedIdentifiers(2).Instance.id, ... + secondIdentifier.id); + end function testSaveInstances(testCase) % Tests saving instances with MetadataStore From 057409be01d746de3d4ae4c8b7bfb0d8461b5ebf Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 06:21:10 +0200 Subject: [PATCH 09/12] fix: load expanded jsonld properties --- .../+internal/+serializer/jsonld2struct.m | 9 +++++++-- tools/tests/unitTests/SerializationTest.m | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/code/internal/+openminds/+internal/+serializer/jsonld2struct.m b/code/internal/+openminds/+internal/+serializer/jsonld2struct.m index e8811a29..319a8889 100644 --- a/code/internal/+openminds/+internal/+serializer/jsonld2struct.m +++ b/code/internal/+openminds/+internal/+serializer/jsonld2struct.m @@ -1,9 +1,14 @@ function structInstance = jsonld2struct(jsonInstance) %Convert metadata instance(s) from JSON-LD text strings to struct arrays - vocabBaseUri = "https://openminds.ebrains.eu/vocab/"; + vocabBaseUri = [ + "https://openminds.ebrains.eu/vocab/" + "https://openminds.om-i.org/props/" + ]; - jsonInstance = strrep(jsonInstance, vocabBaseUri, ''); + for i = 1:numel(vocabBaseUri) + jsonInstance = strrep(jsonInstance, vocabBaseUri(i), ''); + end structInstance = openminds.internal.utility.json.decode(jsonInstance); if isfield(structInstance, 'at_graph') diff --git a/tools/tests/unitTests/SerializationTest.m b/tools/tests/unitTests/SerializationTest.m index da24a0f1..d30ba327 100644 --- a/tools/tests/unitTests/SerializationTest.m +++ b/tools/tests/unitTests/SerializationTest.m @@ -96,5 +96,19 @@ function testInstanceWithLinkedArray(testCase) testCase.verifyLength(str, 3) testCase.verifyClass(str{1}, 'char') end + + function testExpandedJsonLdFileRoundTrip(testCase) + contact = openminds.core.ContactInformation( ... + "email", "contact@example.org"); + filePath = "expanded-contact.jsonld"; + metadataStore = openminds.internal.FileMetadataStore( ... + filePath, ... + "PropertyNameSyntax", "expanded"); + + metadataStore.save(contact); + loadedInstances = metadataStore.load(); + + testCase.verifyEqual(loadedInstances{1}.email, contact.email); + end end end From d1a7dbdd25a6e0be63b758aa1807b1746dc680e3 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 08:26:23 +0200 Subject: [PATCH 10/12] fix: preserve jsonld literal iri values --- .../+openminds/+internal/+serializer/jsonld2struct.m | 4 +++- tools/tests/unitTests/SerializationTest.m | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/code/internal/+openminds/+internal/+serializer/jsonld2struct.m b/code/internal/+openminds/+internal/+serializer/jsonld2struct.m index 319a8889..a214af54 100644 --- a/code/internal/+openminds/+internal/+serializer/jsonld2struct.m +++ b/code/internal/+openminds/+internal/+serializer/jsonld2struct.m @@ -7,7 +7,9 @@ ]; for i = 1:numel(vocabBaseUri) - jsonInstance = strrep(jsonInstance, vocabBaseUri(i), ''); + propertyKeyPattern = sprintf('"%s([^"]+)"\\s*:', ... + regexptranslate('escape', vocabBaseUri(i))); + jsonInstance = regexprep(jsonInstance, propertyKeyPattern, '"$1":'); end structInstance = openminds.internal.utility.json.decode(jsonInstance); diff --git a/tools/tests/unitTests/SerializationTest.m b/tools/tests/unitTests/SerializationTest.m index d30ba327..00360b96 100644 --- a/tools/tests/unitTests/SerializationTest.m +++ b/tools/tests/unitTests/SerializationTest.m @@ -110,5 +110,17 @@ function testExpandedJsonLdFileRoundTrip(testCase) testCase.verifyEqual(loadedInstances{1}.email, contact.email); end + + function testJsonLdCompactionPreservesLiteralValues(testCase) + contact = openminds.core.ContactInformation( ... + "email", "https://openminds.om-i.org/props/contact@example.org"); + filePath = string(tempname) + ".jsonld"; + metadataStore = openminds.internal.FileMetadataStore(filePath); + + metadataStore.save(contact); + loadedInstances = metadataStore.load(); + + testCase.verifyEqual(loadedInstances{1}.email, contact.email); + end end end From 7b591207af461d86a7d62b66935e0273ed8646c9 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Wed, 29 Apr 2026 08:27:39 +0200 Subject: [PATCH 11/12] fix: save folder documents without identifiers --- .../+openminds/+internal/FolderMetadataStore.m | 14 ++++++++++---- tools/tests/unitTests/CollectionTest.m | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/code/internal/+openminds/+internal/FolderMetadataStore.m b/code/internal/+openminds/+internal/FolderMetadataStore.m index 5808910b..18543ab1 100644 --- a/code/internal/+openminds/+internal/FolderMetadataStore.m +++ b/code/internal/+openminds/+internal/FolderMetadataStore.m @@ -105,7 +105,7 @@ serializedDocuments{i}); % Build file path using unified method - filePath = obj.buildFilepath(instance); + filePath = obj.buildFilepath(instance, i); % Write to file openminds.internal.utility.filewrite(filePath, serializedDocuments{i}); @@ -162,7 +162,7 @@ end methods (Access = private) - function instanceFilePath = buildFilepath(obj, instance) + function instanceFilePath = buildFilepath(obj, instance, documentIndex) %buildFilepath Build complete filepath for an instance % % Creates the appropriate file path based on the store's Nested property. @@ -185,7 +185,9 @@ % Nested: /root/person/123.jsonld [typeName, instanceId] = getTypeNameAndId(instance); - if startsWith(instanceId, "http") + if ismissing(instanceId) || instanceId == "" + safeId = sprintf('%04d', documentIndex); + elseif startsWith(instanceId, "http") idParts = strsplit(instanceId, '/'); safeId = idParts{end}; else @@ -215,7 +217,11 @@ if isstruct(instance) typeNameParts = strsplit(instance.at_type, '/'); typeName = typeNameParts{end}; - instanceId = string(instance.at_id); + if isfield(instance, 'at_id') + instanceId = string(instance.at_id); + else + instanceId = string(missing); + end else classNameParts = strsplit(class(instance), '.'); typeName = classNameParts{end}; diff --git a/tools/tests/unitTests/CollectionTest.m b/tools/tests/unitTests/CollectionTest.m index 1b3a6f4c..67e59d7f 100644 --- a/tools/tests/unitTests/CollectionTest.m +++ b/tools/tests/unitTests/CollectionTest.m @@ -346,6 +346,23 @@ function testFolderStoreSavesScalarInstance(testCase) "ContactInformation_")); end + function testFolderStoreSavesInstanceWithoutIdentifier(testCase) + contact = openminds.core.ContactInformation( ... + "email", "contact@example.org"); + folderPath = "identifier-free-folder-store"; + metadataStore = openminds.internal.FolderMetadataStore( ... + folderPath, "IncludeIdentifier", false); + + outputPaths = metadataStore.save(contact); + serializedDocument = fileread(outputPaths{1}); + + testCase.verifyEqual(numel(outputPaths), 1); + testCase.verifyTrue(isfile(outputPaths{1})); + testCase.verifyTrue(contains(string(outputPaths{1}), ... + "ContactInformation_0001")); + testCase.verifyFalse(contains(serializedDocument, '"@id"')); + end + function testCreateCollectionFromMultipleFiles(testCase) firstContact = openminds.core.ContactInformation( ... "email", "first@example.org"); From 11f1509d1836d4ad133ed452b2732b7f96683699 Mon Sep 17 00:00:00 2001 From: Run tests by ehennestad Date: Wed, 29 Apr 2026 06:35:44 +0000 Subject: [PATCH 12/12] Update code issues and tests badges --- .github/badges/code_issues.svg | 2 +- .github/badges/tests.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/badges/code_issues.svg b/.github/badges/code_issues.svg index e9c29599..f7c6c0de 100644 --- a/.github/badges/code_issues.svg +++ b/.github/badges/code_issues.svg @@ -1 +1 @@ -code issuescode issues22 \ No newline at end of file +code issuescode issues44 \ No newline at end of file diff --git a/.github/badges/tests.svg b/.github/badges/tests.svg index 4e32f161..39a04e41 100644 --- a/.github/badges/tests.svg +++ b/.github/badges/tests.svg @@ -1 +1 @@ -teststests568 passed568 passed \ No newline at end of file +teststests711 passed711 passed \ No newline at end of file