Example #1
0
File: table.js Project: aq/metabase
export async function loadTableAndForeignKeys(tableId) {
    let [table, foreignKeys] = await Promise.all([
        MetabaseApi.table_query_metadata({ tableId }),
        MetabaseApi.table_fks({ tableId })
    ]);

    await augmentTable(table);

    return {
        table,
        foreignKeys
    };
}
Example #2
0
 const putData = async () => {
   // make sure we don't send all the computed metadata
   // there may be more that I'm missing?
   const slimDatabase = _.omit(database, "tables", "tables_lookup");
   const updatedDatabase = await MetabaseApi.db_update(slimDatabase);
   return normalize(updatedDatabase, DatabaseSchema);
 };
Example #3
0
        const putData = async () => {
            // make sure we don't send all the computed metadata
            const slimTable = _.omit(table, "fields", "fields_lookup", "aggregation_options", "breakout_options", "metrics", "segments");

            const updatedTable = await MetabaseApi.table_update(slimTable);
            return normalize(updatedTable, TableSchema);
        };
Example #4
0
    return async function(dispatch, getState) {
        if (databaseId) {
            try {
                const database = await MetabaseApi.db_get({"dbId": databaseId});
                dispatch.action(INITIALIZE_DATABASE, database)

                // If the new scheduling toggle isn't set, run the migration
                if (database.details["let-user-control-scheduling"] == undefined) {
                    dispatch(migrateDatabaseToNewSchedulingSettings(database))
                }
            } catch (error) {
                if (error.status == 404) {
                    //$location.path('/admin/databases/');
                } else {
                    console.error("error fetching database", databaseId, error);
                }
            }
        } else {
            const newDatabase = {
                name: '',
                engine: Object.keys(MetabaseSettings.get('engines'))[0],
                details: {},
                created: false
            }
            dispatch.action(INITIALIZE_DATABASE, newDatabase);
        }
    }
Example #5
0
 return async function(dispatch, getState) {
     try {
         return await MetabaseApi.db_list();
     } catch(error) {
         console.error("error fetching databases", error);
     }
 };
Example #6
0
  return async function(dispatch, getState) {
    if (database.details["let-user-control-scheduling"]) {
      try {
        dispatch.action(VALIDATE_DATABASE_STARTED);
        const { valid } = await MetabaseApi.db_validate({ details: database });

        if (valid) {
          dispatch.action(SET_DATABASE_CREATION_STEP, {
            // NOTE Atte Keinänen: DatabaseSchedulingForm needs `editingDatabase` with `schedules` so I decided that
            // it makes sense to set the value of editingDatabase as part of SET_DATABASE_CREATION_STEP
            database: {
              ...database,
              is_full_sync: true,
              schedules: DEFAULT_SCHEDULES,
            },
            step: DB_EDIT_FORM_SCHEDULING_TAB,
          });
        } else {
          dispatch.action(VALIDATE_DATABASE_FAILED, {
            error: {
              data: {
                message: t`Couldn't connect to the database. Please check the connection details.`,
              },
            },
          });
        }
      } catch (error) {
        dispatch.action(VALIDATE_DATABASE_FAILED, { error });
      }
    } else {
      // Skip the scheduling step if user doesn't need precise control over sync and scan
      dispatch(createDatabase(database));
    }
  };
Example #7
0
      async function getFKCount(card, queryResult, fk) {
        let fkQuery = createQuery("query");
        fkQuery.database = card.dataset_query.database;
        fkQuery.query.source_table = fk.origin.table_id;
        fkQuery.query.aggregation = ["count"];
        fkQuery.query.filter = [
          "AND",
          ["=", fk.origin.id, getObjectDetailIdValue(queryResult.data)],
        ];

        let info = { status: 0, value: null };

        try {
          let result = await MetabaseApi.dataset(fkQuery);
          if (
            result &&
            result.status === "completed" &&
            result.data.rows.length > 0
          ) {
            info["value"] = result.data.rows[0][0];
          } else {
            // $FlowFixMe
            info["value"] = "Unknown";
          }
        } catch (error) {
          console.error("error getting fk count", error, fkQuery);
        } finally {
          info["status"] = 1;
        }

        return info;
      }
Example #8
0
    const putData = async () => {
      // make sure we don't send all the computed metadata
      // there may be more that I'm missing?
      const slimField = _.omit(field, "operators_lookup");

      const updatedField = await MetabaseApi.field_update(slimField);
      return normalize(updatedField, FieldSchema);
    };
Example #9
0
 return async function(dispatch, getState) {
     try {
         let call = await MetabaseApi.db_sync_schema({"dbId": databaseId});
         MetabaseAnalytics.trackEvent("Databases", "Manual Sync");
         return call;
     } catch(error) {
         console.log('error syncing database', error);
     }
 };
Example #10
0
 return async function(dispatch, getState) {
   try {
     let call = await MetabaseApi.db_discard_values({ dbId: databaseId });
     MetabaseAnalytics.trackEvent("Databases", "Manual Sync");
     return call;
   } catch (error) {
     console.log("error syncing database", error);
   }
 };
Example #11
0
 return async function(dispatch, getState) {
     let result = await MetabaseApi.dataset_duration(datasetQuery);
     return {
         id: card.id,
         result: {
             fast_threshold: DATASET_USUALLY_FAST_THRESHOLD,
             ...result
         }
     };
 };
Example #12
0
 return async function(dispatch, getState) {
   try {
     let sampleDataset = await MetabaseApi.db_add_sample_dataset();
     MetabaseAnalytics.trackEvent("Databases", "Add Sample Data");
     return sampleDataset;
   } catch (error) {
     console.error("error adding sample dataset", error);
     return error;
   }
 };
Example #13
0
 return async (dispatch, getState) => {
   try {
     await dispatch(fetchTableMetadata(tableId));
     // TODO: finish moving this to metadata duck:
     const foreignKeys = await MetabaseApi.table_fks({ tableId });
     return { foreignKeys };
   } catch (error) {
     console.error("error getting table metadata", error);
     return {};
   }
 };
Example #14
0
 getData: async () => {
   const remapping = await MetabaseApi.field_remapping({
     value,
     fieldId,
     remappedFieldId,
   });
   if (remapping) {
     // FIXME: should this be field.id (potentially the FK) or fieldId (always the PK)?
     dispatch(addRemappings(field.id, [remapping]));
   }
 },
    afterAll(async () => {
      const store = await createTestStore();
      store.dispatch(initializeDatabase(1));
      await store.waitForActions([INITIALIZE_DATABASE]);
      const sampleDatasetDb = getEditingDatabase(store.getState());

      await MetabaseApi.db_update({
        ...sampleDatasetDb,
        name: "Sample Dataset",
      });
    });
Example #16
0
 return async function(dispatch, getState) {
     try {
         dispatch.action(DELETE_DATABASE_STARTED, { databaseId })
         dispatch(push('/admin/databases/'));
         await MetabaseApi.db_delete({"dbId": databaseId});
         MetabaseAnalytics.trackEvent("Databases", "Delete", isDetailView ? "Using Detail" : "Using List");
         dispatch.action(DELETE_DATABASE, { databaseId })
     } catch(error) {
         console.log('error deleting database', error);
         dispatch.action(DELETE_DATABASE_FAILED, { databaseId, error })
     }
 };
Example #17
0
 return async function(dispatch, getState) {
   try {
     let call = await MetabaseApi.field_discard_values({ fieldId });
     MetabaseAnalytics.trackEvent(
       "Data Model",
       "Manual Discard Field Values",
     );
     return call;
   } catch (error) {
     console.log("error discarding field values", error);
   }
 };
Example #18
0
    return async function(dispatch, getState) {
        try {
            dispatch.action(UPDATE_DATABASE_STARTED, { database })
            const savedDatabase = await MetabaseApi.db_update(database);
            MetabaseAnalytics.trackEvent("Databases", "Update", database.engine);

            dispatch.action(UPDATE_DATABASE, { database: savedDatabase })
            setTimeout(() => dispatch.action(CLEAR_FORM_STATE), 3000);
        } catch (error) {
            MetabaseAnalytics.trackEvent("Databases", "Update Failed", database.engine);
            dispatch.action(UPDATE_DATABASE_FAILED, { error });
        }
    };
Example #19
0
 const getData = async () => {
   const tableMetadata = await MetabaseApi.table_query_metadata({
     tableId,
   });
   const fkTableIds = _.chain(tableMetadata.fields)
     .filter(field => field.target)
     .map(field => field.target.table_id)
     .uniq()
     .value();
   const fkTables = await Promise.all(
     fkTableIds.map(tableId =>
       MetabaseApi.table_query_metadata({ tableId }),
     ),
   );
   return normalize([tableMetadata].concat(fkTables), [TableSchema]);
 };
Example #20
0
    return async (dispatch, getState) => {
        const state = getState();
        const parameters = getParameters(state);

        // if we got a query directly on the action call then use it, otherwise take whatever is in our current state
        card = card || state.qb.card;
        parameterValues = parameterValues || state.qb.parameterValues || {};

        const cardIsDirty = isCardDirty(card, state.qb.originalCard);

        card = {
            ...card,
            dataset_query: applyParameters(card, parameters, parameterValues)
        };

        if (shouldUpdateUrl) {
            dispatch(updateUrl(card, { dirty: cardIsDirty }));
        }

        let cancelQueryDeferred = defer();
        const startTime = new Date();

        // make our api call
        function onQuerySuccess(queryResult) {
            dispatch(queryCompleted(card, queryResult));
        }

        function onQueryError(error) {
            dispatch(queryErrored(startTime, error));
        }

        // use the CardApi.query if the query is saved and not dirty so users with view but not create permissions can see it.
        if (card && card.id && !isDirty(state) && dirty !== true) {
            CardApi.query({ cardId: card.id, parameters: card.dataset_query.parameters }, { cancelled: cancelQueryDeferred.promise }).then(onQuerySuccess, onQueryError);
        } else {
            MetabaseApi.dataset(card.dataset_query, { cancelled: cancelQueryDeferred.promise }).then(onQuerySuccess, onQueryError);
        }

        MetabaseAnalytics.trackEvent("QueryBuilder", "Run Query", card.dataset_query.type);

        // HACK: prevent SQL editor from losing focus
        try { ace.edit("id_sql").focus() } catch (e) {}

        return cancelQueryDeferred;
    };
Example #21
0
    return async function (dispatch, getState) {
        try {
            dispatch.action(CREATE_DATABASE_STARTED, {})
            const createdDatabase = await MetabaseApi.db_create(database);
            MetabaseAnalytics.trackEvent("Databases", "Create", database.engine);

            // update the db metadata already here because otherwise there will be a gap between "Adding..." status
            // and seeing the db that was just added
            await dispatch(fetchDatabases())

            dispatch.action(CREATE_DATABASE)
            dispatch(push('/admin/databases?created=' + createdDatabase.id));
        } catch (error) {
            console.error("error creating a database", error);
            MetabaseAnalytics.trackEvent("Databases", "Create Failed", database.engine);
            dispatch.action(CREATE_DATABASE_FAILED, { error })
        }
    };
Example #22
0
    return async (dispatch, getState) => {
      // if we already have the metadata loaded for the given table then we are done
      const { qb: { databaseFields } } = getState();
      try {
        let fields;
        if (databaseFields[dbId]) {
          fields = databaseFields[dbId];
        } else {
          fields = await MetabaseApi.db_fields({ dbId: dbId });
        }

        return {
          id: dbId,
          fields: fields,
        };
      } catch (error) {
        console.error("error getting database fields", error);
        return {};
      }
    };
Example #23
0
 const getData = () => MetabaseApi.field_values({ fieldId });
Example #24
0
 const getData = async () => {
   const databaseMetadata = await MetabaseApi.db_metadata({ dbId });
   return normalize(databaseMetadata, DatabaseSchema);
 };
Example #25
0
 const putData = async () => {
   return await MetabaseApi.field_dimension_update({
     fieldId,
     ...dimension,
   });
 };
Example #26
0
 const putData = async () => {
   return await MetabaseApi.field_dimension_delete({ fieldId });
 };
Example #27
0
 fkTableIds.map(tableId =>
   MetabaseApi.table_query_metadata({ tableId }),
Example #28
0
 const getData = async () =>
   normalize(await MetabaseApi.field_get({ fieldId }), FieldSchema);
Example #29
0
 const getData = async () => {
   const tables = await MetabaseApi.table_list();
   return normalize(tables, [TableSchema]);
 };
Example #30
0
 const putData = async () => {
   return await MetabaseApi.field_values_update({
     fieldId,
     values: fieldValuePairs,
   });
 };