Example #1
0
        /// <inheritdoc/>
        public async Task <ArangoStructure> GetStructureAsync(ArangoHandle db,
                                                              CancellationToken cancellationToken = default)
        {
            var snapshot = new ArangoStructure();

            var collectionsInfos = await _arango.Collection.ListAsync(db);

            var graphs = await _arango.Graph.ListAsync(db);

            var analyzers = await _arango.Analyzer.ListAsync(db);

            var viewInfos = await _arango.View.ListAsync(db);

            var functions = await _arango.Function.ListAsync(db);

            foreach (var cinfo in collectionsInfos)
            {
                var collection = await _arango.Collection.GetAsync(db, cinfo.Name);

                var indices = await _arango.Index.ListAsync(db, collection.Name);

                foreach (var idx in indices)
                {
                    idx.Id = null;
                }

                var c = new ArangoCollectionIndices
                {
                    Collection = collection,
                    Indices    = indices.ToList()
                };

                snapshot.Collections.Add(c);
            }

            var analyzerToPatch = analyzers.Where(x => x.Name.Contains("::")).ToList();

            foreach (var a in analyzerToPatch)
            {
                var idx = a.Name.IndexOf("::", StringComparison.Ordinal);
                a.Name = a.Name.Substring(idx + 2);
            }

            snapshot.Analyzers = analyzerToPatch;

            foreach (var g in graphs)
            {
                if (g.ExtensionData?.ContainsKey("_key") == true)
                {
                    g.ExtensionData.Remove("_key");
                }
                if (g.ExtensionData?.ContainsKey("_id") == true)
                {
                    g.ExtensionData.Remove("_id");
                }
                if (g.ExtensionData?.ContainsKey("_rev") == true)
                {
                    g.ExtensionData.Remove("_rev");
                }

                if (g.ExtensionData != null)
                {
                    g.Options ??= new ArangoGraphOptions();

                    // Normalize graph options for standalone / cluster

                    if (g.ExtensionData?.ContainsKey("numberOfShards") == true)
                    {
                        g.Options.NumberOfShards = (int)(long)g.ExtensionData["numberOfShards"];
                        g.ExtensionData.Remove("numberOfShards");

                        if (g.Options.NumberOfShards == 1)
                        {
                            g.Options.NumberOfShards = null;
                        }
                    }

                    if (g.ExtensionData?.ContainsKey("replicationFactor") == true)
                    {
                        g.Options.ReplicationFactor = g.ExtensionData["replicationFactor"];
                        g.ExtensionData.Remove("replicationFactor");

                        if (g.Options.ReplicationFactor is long r1 && r1 == 1)
                        {
                            g.Options.ReplicationFactor = null;
                        }

                        if (g.Options.ReplicationFactor is int r2 && r2 == 1)
                        {
                            g.Options.ReplicationFactor = null;
                        }
                    }

                    if (g.ExtensionData?.ContainsKey("minReplicationFactor") == true)
                    {
                        g.Options.WriteConcern = (int)(long)g.ExtensionData["minReplicationFactor"];
                        g.ExtensionData.Remove("minReplicationFactor");

                        if (g.Options.WriteConcern == 1)
                        {
                            g.Options.WriteConcern = null;
                        }
                    }

                    if (g.ExtensionData?.ContainsKey("smartGraphAttribute") == true)
                    {
                        g.Options.SmartGraphAttribute = (string)g.ExtensionData["smartGraphAttribute"];
                        g.ExtensionData.Remove("smartGraphAttribute");
                    }
                }
            }

            snapshot.Graphs = graphs.ToList();

            foreach (var viewinfo in viewInfos)
            {
                var v = await _arango.View.GetPropertiesAsync(db, viewinfo.Name);

                if (v.ExtensionData?.ContainsKey("id") == true)
                {
                    v.ExtensionData.Remove("id");
                }
                if (v.ExtensionData?.ContainsKey("globallyUniqueId") == true)
                {
                    v.ExtensionData.Remove("globallyUniqueId");
                }
                if (v.ExtensionData?.ContainsKey("error") == true)
                {
                    v.ExtensionData.Remove("error");
                }
                if (v.ExtensionData?.ContainsKey("code") == true)
                {
                    v.ExtensionData.Remove("code");
                }

                if (v.PrimarySort != null)
                {
                    foreach (var sort in v.PrimarySort)
                    {
                        sort.Direction = (bool)sort.ExtensionData["asc"]
                            ? ArangoSortDirection.Asc
                            : ArangoSortDirection.Desc;
                        sort.ExtensionData.Remove("asc");
                    }
                }

                snapshot.Views.Add(v);
            }

            snapshot.Functions = functions.ToList();

            return(snapshot);
        }
Example #2
0
        /// <inheritdoc/>
        public async Task ApplyStructureAsync(ArangoHandle db, ArangoStructure update,
                                              ArangoMigrationOptions options = null)
        {
            options ??= new ArangoMigrationOptions();

            var current = await GetStructureAsync(db);

            foreach (var targetCollection in update.Collections ?? new List <ArangoCollectionIndices>())
            {
                var currentCollection =
                    current.Collections.SingleOrDefault(x => x.Collection.Name == targetCollection.Collection.Name);

                if (currentCollection == null)
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Collection,
                        State  = ArangoMigrationState.Create,
                        Name   = targetCollection.Collection.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Collection.CreateAsync(db, targetCollection.Collection);
                    }

                    foreach (var idx in targetCollection.Indices)
                    {
                        options.Notify?.Invoke(new ArangoMigrationNotification
                        {
                            Object = ArangoMigrationObject.Index,
                            State  = ArangoMigrationState.Create,
                            Name   = idx.Name
                        });

                        if (!options.DryRun)
                        {
                            await _arango.Index.CreateAsync(db, targetCollection.Collection.Name, idx);
                        }
                    }
                }
                else
                {
                    // No collection updates supported

                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Collection,
                        State  = ArangoMigrationState.Identical,
                        Name   = targetCollection.Collection.Name
                    });

                    foreach (var targetIndex in targetCollection.Indices)
                    {
                        var currentIndex = currentCollection.Indices.SingleOrDefault(x => x.Name == targetIndex.Name);

                        if (currentIndex == null)
                        {
                            options.Notify?.Invoke(new ArangoMigrationNotification
                            {
                                Object = ArangoMigrationObject.Index,
                                State  = ArangoMigrationState.Create,
                                Name   = targetIndex.Name
                            });

                            if (!options.DryRun)
                            {
                                await _arango.Index.CreateAsync(db, targetCollection.Collection.Name, targetIndex);
                            }
                        }
                        else
                        {
                            if (!targetIndex.Deduplicate.HasValue)
                            {
                                targetIndex.Deduplicate = true;
                            }
                            if (!targetIndex.Sparse.HasValue)
                            {
                                targetIndex.Sparse = false;
                            }
                            if (!targetIndex.Unique.HasValue)
                            {
                                targetIndex.Unique = false;
                            }

                            if (!Compare(currentIndex, targetIndex))
                            {
                                options.Notify?.Invoke(new ArangoMigrationNotification
                                {
                                    Object = ArangoMigrationObject.Index,
                                    State  = ArangoMigrationState.Update,
                                    Name   = targetIndex.Name
                                });

                                if (!options.DryRun)
                                {
                                    await _arango.Index.DropAsync(db,
                                                                  targetCollection.Collection.Name + "/" + targetIndex.Name);

                                    await _arango.Index.CreateAsync(db, targetCollection.Collection.Name, targetIndex);
                                }
                            }
                            else
                            {
                                options.Notify?.Invoke(new ArangoMigrationNotification
                                {
                                    Object = ArangoMigrationObject.Index,
                                    State  = ArangoMigrationState.Identical,
                                    Name   = targetIndex.Name
                                });
                            }
                        }
                    }
                }
            }

            foreach (var targetGraph in update.Graphs ?? new List <ArangoGraph>())
            {
                var currentGraph =
                    current.Graphs.SingleOrDefault(x => x.Name == targetGraph.Name);

                if (currentGraph == null)
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Graph,
                        State  = ArangoMigrationState.Create,
                        Name   = targetGraph.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Graph.CreateAsync(db, targetGraph);
                    }
                }
                else if (!Compare(currentGraph, targetGraph))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Graph,
                        State  = ArangoMigrationState.Update,
                        Name   = targetGraph.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Graph.DropAsync(db, targetGraph.Name);

                        await _arango.Graph.CreateAsync(db, targetGraph);
                    }
                }
                else
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Graph,
                        State  = ArangoMigrationState.Identical,
                        Name   = targetGraph.Name
                    });
                }
            }

            foreach (var targetAnalyzer in update.Analyzers ?? new List <ArangoAnalyzer>())
            {
                var currentAnalyzer =
                    current.Analyzers.SingleOrDefault(x => x.Name == targetAnalyzer.Name);

                if (currentAnalyzer == null)
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Analyzer,
                        State  = ArangoMigrationState.Create,
                        Name   = targetAnalyzer.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Analyzer.CreateAsync(db, targetAnalyzer);
                    }
                }
                else if (!Compare(currentAnalyzer, targetAnalyzer))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Analyzer,
                        State  = ArangoMigrationState.Update,
                        Name   = targetAnalyzer.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Analyzer.DeleteAsync(db, currentAnalyzer.Name, true);

                        await _arango.Analyzer.CreateAsync(db, currentAnalyzer);
                    }
                }
                else
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Analyzer,
                        State  = ArangoMigrationState.Identical,
                        Name   = targetAnalyzer.Name
                    });
                }
            }

            foreach (var targetView in update.Views ?? new List <ArangoView>())
            {
                var currentView =
                    current.Views.SingleOrDefault(x => x.Name == targetView.Name);

                if (currentView == null)
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.View,
                        State  = ArangoMigrationState.Create,
                        Name   = targetView.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.View.CreateAsync(db, targetView);
                    }
                }
                else if (!Compare(currentView, targetView))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.View,
                        State  = ArangoMigrationState.Update,
                        Name   = targetView.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.View.DropAsync(db, targetView.Name);

                        await _arango.View.CreateAsync(db, targetView);
                    }
                }
                else
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.View,
                        State  = ArangoMigrationState.Identical,
                        Name   = targetView.Name
                    });
                }
            }

            foreach (var targetFunction in update.Functions ?? new List <ArangoFunctionDefinition>())
            {
                var currentFunction =
                    current.Functions.SingleOrDefault(x => x.Name == targetFunction.Name);

                if (currentFunction == null)
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Function,
                        State  = ArangoMigrationState.Create,
                        Name   = targetFunction.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Function.CreateAsync(db, targetFunction);
                    }
                }
                else if (!Compare(currentFunction, targetFunction))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Function,
                        State  = ArangoMigrationState.Update,
                        Name   = targetFunction.Name
                    });


                    if (!options.DryRun)
                    {
                        await _arango.Function.RemoveAsync(db, targetFunction.Name);

                        await _arango.Function.CreateAsync(db, targetFunction);
                    }
                }
                else
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Function,
                        State  = ArangoMigrationState.Identical,
                        Name   = targetFunction.Name
                    });
                }
            }

            // drop

            if (options.DropExcess)
            {
                foreach (var currentView in current.Views
                         .Where(x => update.Views.All(y => y.Name != x.Name)))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.View,
                        State  = ArangoMigrationState.Delete,
                        Name   = currentView.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.View.DropAsync(db, currentView.Name);
                    }
                }

                foreach (var currentAnalyzer in current.Analyzers
                         .Where(x => update.Analyzers.All(y => y.Name != x.Name)))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Analyzer,
                        State  = ArangoMigrationState.Delete,
                        Name   = currentAnalyzer.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Analyzer.DeleteAsync(db, currentAnalyzer.Name);
                    }
                }

                foreach (var currentGraph in current.Graphs
                         .Where(x => update.Graphs.All(y => y.Name != x.Name)))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Graph,
                        State  = ArangoMigrationState.Delete,
                        Name   = currentGraph.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Graph.DropAsync(db, currentGraph.Name);
                    }
                }

                foreach (var currentCollection in current.Collections
                         .Where(x => update.Collections.All(y => y.Collection.Name != x.Collection.Name)))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Collection,
                        State  = ArangoMigrationState.Delete,
                        Name   = currentCollection.Collection.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Collection.DropAsync(db, currentCollection.Collection.Name);
                    }
                }

                foreach (var currentFunction in current.Functions
                         .Where(x => update.Functions.All(y => y.Name != x.Name)))
                {
                    options.Notify?.Invoke(new ArangoMigrationNotification
                    {
                        Object = ArangoMigrationObject.Function,
                        State  = ArangoMigrationState.Delete,
                        Name   = currentFunction.Name
                    });

                    if (!options.DryRun)
                    {
                        await _arango.Function.RemoveAsync(db, currentFunction.Name);
                    }
                }
            }
        }