internal async Task SaveDocumentAsAsync()

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;
            }
        }