static void ValidateSourceDatabaseMapping(MetabaseState state, IReadOnlyDictionary <DatabaseId, DatabaseId> databaseMapping) { var allDatabaseIds = state.Cards.SelectMany(c => new[] { c.DatabaseId, c.DatasetQuery.DatabaseId }); var missingDatabaseIdsInMapping = allDatabaseIds.Where(x => databaseMapping.ContainsKey(x) == false).Distinct().ToList(); if (missingDatabaseIdsInMapping.Count > 0) { throw new Exception("Missing databases in mapping: " + string.Join(",", missingDatabaseIdsInMapping)); } }
/// <summary> /// Export Metabase data /// </summary> public static async Task <MetabaseState> Export(this MetabaseApi api, bool excludePersonalCollections) { var mappedCollections = await api.GetMappedCollections(excludePersonalCollections); var mappedCards = await api.GetMappedCards(mappedCollections.CollectionMapping); var mappedDashboards = await api.GetMappedDashboards(mappedCards.CardMapping, mappedCollections.Collections); var state = new MetabaseState { Cards = mappedCards.Cards.ToArray(), Dashboards = mappedDashboards.Dashboards.ToArray(), Collections = mappedCollections.Collections.ToArray(), }; return(state); }
/// <summary> /// Imports Metabase data. DELETES all current dashboards/questions/etc. /// </summary> /// <param name="api"></param> /// <param name="state"></param> /// <param name="databaseMapping"></param> /// <returns></returns> public static async Task Import(this MetabaseApi api, MetabaseState state, IReadOnlyDictionary <DatabaseId, DatabaseId> databaseMapping) { // firstly check that the database mapping is complete and correct await api.ValidateDatabaseMapping(state, databaseMapping); // now map/create collections then cards then dashboards Console.WriteLine("Creating collections..."); var collectionMapping = await api.MapAndCreateCollections(state.Collections); Console.WriteLine("Deleting all dashboards..."); await api.DeleteAllDashboards(); Console.WriteLine("Deleting all cards..."); await api.DeleteAllCards(); Console.WriteLine("Creating cards..."); var partialCardMapping = await state.Cards .Traverse(async cardFromState => { var source = cardFromState.Id; var target = await api.MapAndCreateCard(cardFromState, collectionMapping, databaseMapping); var mapping = new Mapping <CardId?>(source: source, target: target?.Id); return(mapping); }); var cardMapping = partialCardMapping .Where(x => x.Source.HasValue && x.Target.HasValue) .Select(x => new Mapping <CardId>(x.Source.Value, x.Target.Value)) .ToList(); Console.WriteLine("Creating dashboards..."); foreach (var dashboard in state.Dashboards) { await api.MapAndCreateDashboard(dashboard, cardMapping); } Console.WriteLine("Done importing"); }
static async Task ValidateDatabaseMapping(this MetabaseApi api, MetabaseState state, IReadOnlyDictionary <DatabaseId, DatabaseId> databaseMapping) { ValidateSourceDatabaseMapping(state, databaseMapping); await api.ValidateTargetDatabaseMapping(databaseMapping); }