Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add query when mapping #40

Merged
merged 2 commits into from
Mar 24, 2025
Merged

Feat/add query when mapping #40

merged 2 commits into from
Mar 24, 2025

Conversation

MaryKilewe
Copy link
Contributor

@MaryKilewe MaryKilewe commented Mar 24, 2025

Summary by Sourcery

Adds functionality to map CSV headers to base variables, allowing users to define mappings between CSV data and a base repository. It also includes testing and saving functionalities for these mappings.

New Features:

  • Introduces the ability to map CSV headers to base variables.
  • Implements testing functionality to validate the created mappings.
  • Adds functionality to save the created mappings.
  • Introduces a new component TestCsvMappings to test the mappings

Tests:

  • Adds TestCsvMappings component to test the mappings

Copy link
Contributor

sourcery-ai bot commented Mar 24, 2025

Reviewer's Guide by Sourcery

This pull request introduces functionality to map CSV headers to base variables, test the mappings, and save them. It includes a new component, TestCsvMappings, for testing the mappings and displays any issues found. It also updates the CsvApiSelectorForm to fetch and display CSV headers instead of database tables. New queries and mutations are added for fetching CSV headers, saving mappings, and testing mappings.

Sequence diagram for handling CSV header selection

sequenceDiagram
  participant CsvApiSelectorForm
  participant handleTableSelect
  participant setFormData

  CsvApiSelectorForm->>handleTableSelect: handleTableSelect(csvHeaderSelected, basevariable)
  handleTableSelect->>setFormData: Updates formData with selected CSV header
  setFormData-->>CsvApiSelectorForm: Updates form data
Loading

Sequence diagram for testing CSV mappings

sequenceDiagram
  participant TestCsvMappings
  participant useTestCsvMappings
  participant API

  TestCsvMappings->>useTestCsvMappings: useTestCsvMappings(formData, baselookup, conn_type)
  useTestCsvMappings->>API: POST /flatfile_mapper/test/{conn_type}/mapped_variables/{baselookup}
  API-->>useTestCsvMappings: Returns test results
  useTestCsvMappings-->>TestCsvMappings: Returns test results
  TestCsvMappings->>TestCsvMappings: Displays test results
Loading

Sequence diagram for saving CSV mappings

sequenceDiagram
  participant CsvApiSelectorForm
  participant useSaveCsvMappings
  participant API

  CsvApiSelectorForm->>useSaveCsvMappings: useSaveCsvMappings(formData, baselookup, conn_type)
  useSaveCsvMappings->>API: POST /flatfile_mapper/add/{conn_type}/mapped_variables/{baselookup}
  API-->>useSaveCsvMappings: Returns save status
  useSaveCsvMappings-->>CsvApiSelectorForm: Returns save status
Loading

File-Level Changes

Change Details Files
Refactor CsvApiSelectorForm to fetch and display CSV headers for mapping.
  • Modify CsvApiSelectorForm to accept a conn_type prop.
  • Update getDatabaseColumns to use fetchSourceCsvHeaders with conn_type.
  • Adjust handleTableSelect to map base variables to CSV headers.
  • Modify the UI to display CSV headers instead of database tables.
  • Remove primary table selection components.
  • Update the test mappings component to TestCsvMappings and pass the conn_type prop.
src/pages/mapper/selector-form/CsvApiSelectorForm.js
Implement TestCsvMappings component for testing CSV mappings.
  • Create a new TestCsvMappings component.
  • Implement logic for testing and saving CSV mappings.
  • Update the component to display issues with mappings and recommended solutions.
  • Add functionality to save the mappings.
  • Adjust the success alert to check if the testing response data array has any values, and if so, display an error.
src/pages/mapper/test-mappings/TestCsvMappings.js
Update CsvAndApiMapper to pass conn_type to CsvApiSelectorForm.
  • Pass the conn_type from sourceSystemData to CsvApiSelectorForm.
src/pages/mapper/CsvAndApiMapper.js
Introduce new queries and mutations for CSV API mapper.
  • Add fetchSourceCsvHeaders query to fetch CSV headers based on connection type.
  • Implement useSaveCsvMappings mutation for saving CSV mappings.
  • Implement useTestCsvMappings mutation for testing CSV mappings.
src/store/csv-api-mapper/queries.js
src/store/csv-api-mapper/mutations.js
Update TestQueryMappings to display an error if the testing response data array has any values.
  • Adjust the success alert to check if the testing response data array has any values, and if so, display an error.
src/pages/mapper/test-mappings/TestQueryMappings.js
Update TestMappings to display an error if the testing response data array has any values.
  • Adjust the success alert to check if the testing response data array has any values, and if so, display an error.
src/pages/mapper/test-mappings/TestMappings.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @MaryKilewe - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider creating a shared component for the alert messages to avoid repetition.
  • The testing and saving logic in TestCsvMappings.js could be simplified by extracting common operations into helper functions.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

queryFn: fetchSourceSystemInfo,
refetchInterval: 1800000, // refresh every 30min

});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Dynamic query keys for useQuery hooks.

Several useQuery hooks (e.g., useGetBaseVariables, useGetMappedBaseVariables, useGetRepositoryLoadedData) use static query keys like ['baseRepo']. To avoid potential caching conflicts when baseRepo changes, consider including the variable in the query key (e.g., ['baseRepo', baseRepo]).

Suggested implementation:

export const useGetBaseVariables  = (baseRepo) => useQuery({
    queryKey: ['baseRepo', baseRepo],
export const useGetMappedBaseVariables  = (baseRepo) => useQuery({
    queryKey: ['baseRepo', baseRepo],

@@ -0,0 +1,94 @@
import {API_URL} from "../../constants";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider creating a query hook factory to avoid repeated fetching logic and reduce overall complexity in the file by centralizing shared logic and reducing boilerplate code for each query hook..

The repeated fetching logic and query hook creation adds extra boilerplate and increases the file’s complexity. You can reduce duplication by creating a single query hook factory that wraps the fetch/transform code. For example:

const createQueryHook = <T, Args extends any[]>(
  queryKey: (args: Args) => any[],
  getUrl: (...args: Args) => string,
  transform?: (data: any) => T,
  refetchInterval = 1800000
) => {
  return (...args: Args) => useQuery({
    queryKey: queryKey(args),
    queryFn: async () => {
      const res = await fetch(getUrl(...args));
      const jsonData = await res.json();
      return transform ? transform(jsonData) : jsonData;
    },
    refetchInterval
  });
};

Now you can replace, for example, useGetBaseVariables with:

export const useGetBaseVariables = createQueryHook(
  ([baseRepo]) => ['baseRepo', baseRepo],
  (baseRepo) => `${API_URL}/dictionary_mapper/base_variables/${baseRepo}`,
  (data) => data?.data ?? null
);

Repeat similar patterns for the other query hooks. This way, you centralize the shared logic and reduce complexity while keeping functionality intact.

@@ -0,0 +1,65 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider creating a reusable helper function and a generic mutation hook factory to avoid code duplication in API calls and mutation logic, improving maintainability and reducing complexity

You can reduce duplication by extracting the shared API call logic into a reusable helper and a generic mutation hook factory. For example:

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { API_URL } from "../../constants";

const postRequest = async (endpoint, { baselookup, formData, conn_type }) => {
  const res = await fetch(`${API_URL}/${endpoint}/${conn_type}/mapped_variables/${baselookup}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(formData),
  });
  const jsonData = await res.json();
  if (!res.ok) {
    return { status_code: res.status, data: jsonData?.detail ?? [] };
  }
  return { status_code: res.status || 500, data: jsonData?.data ?? [] };
};

const createCsvMappingHook = (endpoint, queryKey) => {
  return () => {
    const queryClient = useQueryClient();
    return useMutation({
      mutationFn: (payload) => postRequest(endpoint, payload),
      onSuccess: () => queryClient.invalidateQueries({ queryKey }),
    });
  };
};

export const useSaveCsvMappings = createCsvMappingHook("flatfile_mapper/add", ['mappings']);
export const useTestCsvMappings = createCsvMappingHook("flatfile_mapper/test", ['test_mappings']);

By abstracting the shared logic, you maintain functionality while reducing complexity and code duplication.

Comment on lines +164 to +181
{ !querySaved ? (
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="primary" onClick={()=>handleSubmit()}>
Save
{spinner &&
<CircularProgress style={{"color":"black","marginLeft":"10px"}} size="1rem"/>
}
</Button>
</AnimateButton>
):(
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="success" onClick={() => window.location.href = `${FRONTEND_URL}/schema/config?baselookup=${baselookup}`}>
Finish
</Button>
</AnimateButton>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Invert ternary operator to remove negation (invert-ternary)

Suggested change
{ !querySaved ? (
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="primary" onClick={()=>handleSubmit()}>
Save
{spinner &&
<CircularProgress style={{"color":"black","marginLeft":"10px"}} size="1rem"/>
}
</Button>
</AnimateButton>
):(
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="success" onClick={() => window.location.href = `${FRONTEND_URL}/schema/config?baselookup=${baselookup}`}>
Finish
</Button>
</AnimateButton>
)}
{ querySaved ?
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="success" onClick={() => window.location.href = `${FRONTEND_URL}/schema/config?baselookup=${baselookup}`}>
Finish
</Button>
</AnimateButton>
:
<AnimateButton>
<Button disableElevation disabled={disableSave} fullWidth size="medium" type="button" variant="contained"
color="primary" onClick={()=>handleSubmit()}>
Save
{spinner &&
<CircularProgress style={{"color":"black","marginLeft":"10px"}} size="1rem"/>
}
</Button>
</AnimateButton>}


ExplanationNegated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By inverting the ternary condition and swapping the
expressions we can simplify the code.

Comment on lines +6 to +10
const data = fetch(API_URL+"/dictionary_mapper/base_schemas")
.then((res) =>
res.json(),
);
return data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const data = fetch(API_URL+"/dictionary_mapper/base_schemas")
.then((res) =>
res.json(),
);
return data;
return fetch(API_URL+"/dictionary_mapper/base_schemas")
.then((res) =>
res.json(),
);


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Comment on lines +15 to +19
const data = fetch(API_URL+"/dictionary_mapper/base_schema_variables/"+baselookup)
.then((res) =>
res.json(),
);
return data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const data = fetch(API_URL+"/dictionary_mapper/base_schema_variables/"+baselookup)
.then((res) =>
res.json(),
);
return data;
return fetch(API_URL+"/dictionary_mapper/base_schema_variables/"+baselookup)
.then((res) =>
res.json(),
);


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

@MaryKilewe MaryKilewe merged commit b6a3ba8 into master Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant