in objectModel/CSharp/Microsoft.CommonDataModel.ObjectModel/Persistence/PersistenceLayer.cs [291:489]
internal async Task<bool> SaveDocumentAsAsync(CdmDocumentDefinition doc, CopyOptions options, string newName, bool saveReferenced = false)
{
// Find out if the storage adapter is able to write.
string ns = StorageUtils.SplitNamespacePath(newName).Item1;
if (string.IsNullOrWhiteSpace(ns))
{
ns = doc.Namespace;
if (string.IsNullOrWhiteSpace(ns))
{
ns = this.Corpus.Storage.DefaultNamespace;
}
}
var adapter = this.Corpus.Storage.FetchAdapter(ns);
if (adapter == null)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistAdapterNotFoundForNamespace, ns);
return false;
}
else if (adapter.CanWrite() == false)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistAdapterWriteFailure, ns);
return false;
}
else
{
if (string.IsNullOrWhiteSpace(newName))
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistNullDocName);
return false;
}
// What kind of document is requested?
// Check file extensions using a case-insensitive ordinal string comparison.
string persistenceType;
if (Persistence.Syms.Utils.CheckIfSymsAdapter(adapter))
{
if (newName.Equals(SymsDatabases))
{
// Not supporting saving list of databases at once. May cause perf issue.
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistSymsUnsupportedManifest, newName);
return false;
}
if (!newName.EndWithOrdinalIgnoreCase(ManifestExtension)
&& !newName.EndWithOrdinalIgnoreCase(CdmExtension)
)
{
// syms support *.cdm and *.manifest.cdm only
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistSymsUnsupportedCdmConversion, newName);
return false;
}
persistenceType = Syms;
options.PersistenceTypeName = Syms;
}
else
{
if (newName.EndWithOrdinalIgnoreCase(ModelJsonExtension))
persistenceType = ModelJson;
else
persistenceType = CdmFolder;
}
if (persistenceType == ModelJson && !newName.EqualsWithOrdinalIgnoreCase(ModelJsonExtension))
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistFailure, newName, ModelJsonExtension);
return false;
}
// Save the object into a json blob.
ResolveOptions resOpt = new ResolveOptions() { WrtDoc = doc, Directives = new AttributeResolutionDirectiveSet() };
dynamic persistedDoc = null;
try
{
if (newName.EndWithOrdinalIgnoreCase(ModelJsonExtension) || newName.EndWithOrdinalIgnoreCase(ManifestExtension)
|| newName.EndWithOrdinalIgnoreCase(FolioExtension))
{
if (persistenceType == "CdmFolder")
{
persistedDoc = Persistence.CdmFolder.ManifestPersistence.ToData(doc as CdmManifestDefinition, resOpt, options);
}
else if (persistenceType == Syms)
{
persistedDoc = await ConvertManifestToSyms(doc as CdmManifestDefinition, adapter, newName, resOpt, options);
}
else
{
if (!newName.EqualsWithOrdinalIgnoreCase(ModelJsonExtension))
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistFailure, newName, ModelJsonExtension);
return false;
}
persistedDoc = await Persistence.ModelJson.ManifestPersistence.ToData(doc as CdmManifestDefinition, resOpt, options);
}
}
else if (newName.EndWithOrdinalIgnoreCase(CdmExtension))
{
if (persistenceType == "CdmFolder")
{
persistedDoc = Persistence.CdmFolder.DocumentPersistence.ToData(doc, resOpt, options);
}
else if (persistenceType == Syms)
{
persistedDoc = await ConvertDocToSymsTable(Corpus.Ctx, doc, adapter, newName, resOpt, options);
}
}
else
{
// Could not find a registered persistence class to handle this document type.
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistClassMissing, newName);
return false;
}
}
catch (Exception e)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistFilePersistError, newName, e.Message);
return false;
}
if (persistedDoc == null)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistFilePersistFailed, newName);
return false;
}
// turn the name into a path
string newPath = $"{doc.FolderPath}{newName}";
newPath = this.Ctx.Corpus.Storage.CreateAbsoluteCorpusPath(newPath, doc);
if (newPath.StartsWith($"{ns}:"))
newPath = newPath.Slice(ns.Length + 1);
// ask the adapter to make it happen
try
{
if (persistenceType == Syms)
{
if (newName.EndWithOrdinalIgnoreCase(ManifestExtension))
{
await Persistence.Syms.Utils.CreateOrUpdateSymsEntities(persistedDoc, adapter);
}
else if (newName.EndWithOrdinalIgnoreCase(CdmExtension))
{
TableEntity tableEntity = (TableEntity)persistedDoc;
await Persistence.Syms.Utils.CreateOrUpdateTableEntity(tableEntity, adapter);
}
}
else
{
var content = JsonConvert.SerializeObject(persistedDoc, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver() });
await adapter.WriteAsync(newPath, content);
}
doc._fileSystemModifiedTime = await adapter.ComputeLastModifiedTimeAsync(newPath);
// Write the adapter's config.
if (options.IsTopLevelDocument && persistenceType != Syms)
{
await this.Corpus.Storage.SaveAdaptersConfigAsync("/config.json", adapter);
// The next document won't be top level, so reset the flag.
options.IsTopLevelDocument = false;
}
}
catch (Exception e)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistFileWriteFailure, newName, e.Message);
return false;
}
// if we also want to save referenced docs, then it depends on what kind of thing just got saved
// if a model.json there are none. If a manifest or definition doc then ask the docs to do the right things
// definition will save imports, manifests will save imports, schemas, sub manifests
if (saveReferenced && persistenceType == CdmFolder)
{
if (await doc.SaveLinkedDocuments(options) == false)
{
Logger.Error((ResolveContext)this.Ctx, Tag, nameof(SaveDocumentAsAsync), doc.AtCorpusPath, CdmLogCode.ErrPersistSaveLinkedDocs, newName);
return false;
}
}
if (newName.EndWithOrdinalIgnoreCase(ManifestExtension))
{
foreach (var entity in (doc as CdmManifestDefinition).Entities)
{
(entity as CdmLocalEntityDeclarationDefinition).ResetLastFileModifiedOldTime();
}
foreach (var relationship in (doc as CdmManifestDefinition).Relationships)
{
(relationship as CdmE2ERelationship).ResetLastFileModifiedOldTime();
}
}
return true;
}
}