Skip to content

feat: add insert rows json function in redshift#300

Merged
vishnurk6247 merged 4 commits into
developfrom
feat/redshift-insert
Jun 23, 2026
Merged

feat: add insert rows json function in redshift#300
vishnurk6247 merged 4 commits into
developfrom
feat/redshift-insert

Conversation

@vishnurk6247

@vishnurk6247 vishnurk6247 commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

Release Notes

New Features

  • Added JSON-based bulk insert support for Redshift, enabling insertion of multiple rows from dictionary-formatted data into target tables.

Breaking Changes

  • Removed Azure Synapse datasource support, including query execution and schema/table discovery capabilities.

Maintenance

  • Updated the underlying SQL Server package dependency used by the platform to align with the revised datasource support.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Implements insert_rows_json on RedshiftClient with JSON serialization, SUPER-column detection, and bulk-insert via executemany, then wires it through RedshiftPlugin using schema-qualified table names. Simultaneously removes the entire Azure Synapse datasource integration: deletes SynapseClient and SynapsePlugin implementations, removes Synapse from datasource type-switching logic across controllers and services, and updates the dependency from pyodbc to mssql-python.

Changes

Redshift JSON Row Insert

Layer / File(s) Summary
RedshiftClient.insert_rows_json with SUPER-column support
wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py
Adds json import. Introduces _get_super_columns helper to detect SUPER-typed columns from information_schema.columns. Implements insert_rows_json method: validates non-empty data and identical row keys, derives columns from the first dict, validates table/column identifiers, JSON-serializes dict/list cell values, wraps SUPER columns with JSON_PARSE, constructs named-placeholder INSERT INTO ... VALUES ... statement, executes via executemany, commits on success, rolls back and re-raises on RedshiftError, and closes cursor in finally.
RedshiftPlugin.insert_rows_json forwarding
wavefront/server/plugins/datasource/datasource/redshift/__init__.py
Promotes stub to typed (table_name: str, data: List[Dict[str, Any]]) -> None method that forwards to self.client.insert_rows_json with schema-qualified {self.db_name}.{table_name} reference.

Azure Synapse Datasource Removal

Layer / File(s) Summary
Cloud package cleanup and dependency migration
wavefront/server/packages/flo_cloud/flo_cloud/azure/synapse.py, wavefront/server/packages/flo_cloud/flo_cloud/azure/__init__.py, wavefront/server/packages/flo_cloud/pyproject.toml
Deletes synapse.py module (removes SynapseClient and all connection/query/metadata logic). Updates azure/__init__.py to remove SynapseClient from exports and set azure logger level to WARNING. Replaces pyodbc>=5.0.0 dependency with mssql-python.
Datasource plugin synapse removal
wavefront/server/plugins/datasource/datasource/synapse/config.py, wavefront/server/plugins/datasource/datasource/__init__.py
Deletes synapse/config.py (removes SynapseConfig dataclass). Removes SynapsePlugin/SynapseConfig imports from datasource/__init__.py. Updates DatasourcePlugin.__init__ config parameter type union to exclude SynapseConfig. Removes AZURE_SYNAPSE branch from __get_datasource method, narrowing available plugins to BigQuery/Redshift/Postgres/MSSQL.
Datasource controller and service cleanup
wavefront/server/modules/plugins_module/plugins_module/controllers/datasource_controller.py, wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py
Removes SynapseConfig import and AZURE_SYNAPSE branches from datasource_controller.py (in add_datasource and update_datasource methods). Removes SynapseConfig import and conditional branch from datasource_services.py get_datasource_config function; updates return type annotation to exclude SynapseConfig from the union.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Sequence Diagrams

sequenceDiagram
  participant Caller
  participant RedshiftClient
  participant ColumnQuery
  participant InsertCursor
  Caller->>RedshiftClient: insert_rows_json(table_name, data)
  RedshiftClient->>RedshiftClient: validate data non-empty
  RedshiftClient->>RedshiftClient: derive columns from first row
  RedshiftClient->>RedshiftClient: validate all rows have identical keys
  RedshiftClient->>RedshiftClient: validate table/column identifiers
  RedshiftClient->>ColumnQuery: _get_super_columns(table_name)
  ColumnQuery-->>RedshiftClient: set of SUPER column names
  RedshiftClient->>RedshiftClient: serialize dict/list → JSON, wrap SUPER with JSON_PARSE
  RedshiftClient->>InsertCursor: executemany(INSERT INTO ... statement)
  alt success
    RedshiftClient->>RedshiftClient: connection.commit()
    RedshiftClient-->>Caller: return row count
  else RedshiftError
    RedshiftClient->>RedshiftClient: connection.rollback() + log error
    RedshiftClient-->>Caller: raise RedshiftError
  end
  RedshiftClient->>InsertCursor: close() in finally block
Loading

Possibly Related PRs

  • rootflo/wavefront#261: That PR adds Azure Synapse datasource integration (SynapseClient/SynapsePlugin wiring and AZURE_SYNAPSE handling), whereas this PR removes the same Synapse modules/entry points entirely.
  • rootflo/wavefront#297: That PR extends datasource controller/service type-switching logic for MSSQL support in the same locations where this PR removes AZURE_SYNAPSE handling.

Suggested Reviewers

  • rootflo-hardik
  • vizsatiz

Poem

🐇 Synapse departures, Redshift ascends,
JSON rows serialize, SUPER columns mend,
With executemany we bulk insert with grace,
Schema-qualified names keep all in place,
No more pyodbc—mssql takes the stand,
The datasource landscape, now freshly planned! 🚀

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title focuses only on adding the insert_rows_json function in Redshift, but the PR also removes Azure Synapse support across multiple modules and dependencies. Revise the title to reflect the full scope of changes, such as 'feat: add Redshift JSON insert and remove Azure Synapse support' or similar.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/redshift-insert

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py`:
- Around line 350-359: The columns are extracted only from the first row using
data[0].keys(), and the serialization logic uses row.get(col) which silently
inserts NULL for missing keys and drops extra keys from later rows without any
validation. To fix this, validate that all rows have a consistent schema
matching the first row before the serialization loop, or collect all unique keys
across all rows first. This ensures data integrity by explicitly handling or
rejecting rows that deviate from the expected schema rather than silently
corrupting data through dropped or missing columns.
- Around line 361-363: The INSERT statement construction is vulnerable to
identifier injection because table_name and column identifiers from the columns
list are directly interpolated into the SQL command string without validation.
Before composing the command variable that constructs the INSERT statement, add
validation logic to ensure that table_name and each column identifier contains
only safe characters (such as alphanumeric characters and underscores) that are
valid for SQL identifiers. This validation should occur before the column_list
and command variables are created to prevent malicious table names or column
names from being used to modify the SQL structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 25050d9d-5248-49c3-ba3f-3c76caa876f6

📥 Commits

Reviewing files that changed from the base of the PR and between 30d94b9 and 3fe5c2d.

📒 Files selected for processing (2)
  • wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py
  • wavefront/server/plugins/datasource/datasource/redshift/__init__.py

Comment thread wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py
Comment thread wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py (1)

32-41: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Legacy Synapse datasource records now fail hard without a migration/deprecation path.

With the Synapse branch removed while DataSourceType.AZURE_SYNAPSE still exists upstream, persisted Synapse datasources will now fall into the invalid-type ValueError path and fail at runtime. Please add a migration/retirement strategy (or an explicit controlled deprecation branch) before release to avoid request-time breakage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py`
around lines 32 - 41, The datasource type validation logic in this conditional
chain is missing a case for DataSourceType.AZURE_SYNAPSE, which still exists in
persisted datasources upstream despite the Synapse branch being removed. This
causes the code to fall through to the ValueError when processing existing
Synapse records. Before the final else clause that raises the ValueError, add an
explicit elif branch for DataSourceType.AZURE_SYNAPSE that implements a
controlled deprecation path, such as logging a deprecation warning and either
migrating the datasource to an alternative type (like MSSQL or Postgres) or
providing a graceful fallback configuration. This prevents runtime failures for
existing Synapse datasource records while providing users with a clear
migration/deprecation message.
♻️ Duplicate comments (1)
wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py (1)

390-391: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard against empty column lists.

If the first row is an empty dictionary, columns will be an empty list, resulting in malformed SQL: INSERT INTO table () VALUES (). This will cause a runtime error.

🛡️ Suggested fix
 columns = list(data[0].keys())
+if not columns:
+    raise ValueError('insert_rows_json requires at least one column')

 identifier_pattern = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py` around lines
390 - 391, The line assigning columns from data[0].keys() does not handle the
case where data[0] is an empty dictionary, which results in an empty columns
list and generates malformed SQL. Add a guard condition after the columns
assignment in the redshift.py file to check if the columns list is empty and
raise an appropriate error or handle this edge case before proceeding with SQL
generation. This ensures the code does not attempt to create INSERT statements
with empty column lists.
🧹 Nitpick comments (2)
wavefront/server/plugins/datasource/datasource/__init__.py (1)

21-22: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make unsupported Synapse explicit in this boundary.

datasource_type still accepts the full DataSourceType enum, but this class now supports only four types. Add an explicit AZURE_SYNAPSE branch (with a deprecation message) or narrow accepted types so failures are deterministic and clearer than the generic invalid-type fallback.

Also applies to: 49-50

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wavefront/server/plugins/datasource/datasource/__init__.py` around lines 21 -
22, The function parameter at the boundary currently accepts the full
DataSourceType enum while only supporting four specific types (BigQuery,
Redshift, Postgres, MSSQL). Make unsupported types explicit by either narrowing
the type hint for the datasource_type parameter to only accept the four
supported types using a Literal or Union type annotation, or by adding an
explicit branch that catches AZURE_SYNAPSE specifically and raises a clear
deprecation error. Apply the same fix to the corresponding location at lines
49-50 to maintain consistency across all boundaries accepting datasource types.
wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py (1)

435-435: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Quote the table name for consistency and keyword safety.

Column identifiers are quoted on Line [430], but table_name is inserted directly without quotes on Line [435]. While the validation (Lines [394-396]) prevents injection, unquoted table/schema names that happen to be SQL keywords (e.g., order, user, table) will cause syntax errors at runtime.

🔧 Recommended fix
+def _quote_qualified_identifier(name: str) -> str:
+    """Quote each part of a dot-qualified identifier."""
+    return '.'.join(f'"{part}"' for part in name.split('.'))
+
 ...
-        command = f'INSERT INTO {table_name} ({column_list}) VALUES ({placeholders})'
+        quoted_table = _quote_qualified_identifier(table_name)
+        command = f'INSERT INTO {quoted_table} ({column_list}) VALUES ({placeholders})'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py` at line 435,
The INSERT statement construction at line 435 inserts the `table_name` variable
directly without quotes, while column identifiers are quoted elsewhere. To
ensure consistency and prevent syntax errors when table names happen to be SQL
keywords, add quotes around the `table_name` variable in the INSERT command
f-string, matching the quoting approach used for the `column_list`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py`:
- Around line 24-25: The return type annotation for the function that returns a
tuple of config types does not account for the actual return value of (None,
None). Update the type annotation on the return statement to indicate that both
elements of the tuple can be None by making each config type optional using the
union operator with None or Optional. This change applies to the return type
annotation around line 24-25 and also at line 30, so ensure both locations are
updated to match the actual nullable return contract.

---

Outside diff comments:
In
`@wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py`:
- Around line 32-41: The datasource type validation logic in this conditional
chain is missing a case for DataSourceType.AZURE_SYNAPSE, which still exists in
persisted datasources upstream despite the Synapse branch being removed. This
causes the code to fall through to the ValueError when processing existing
Synapse records. Before the final else clause that raises the ValueError, add an
explicit elif branch for DataSourceType.AZURE_SYNAPSE that implements a
controlled deprecation path, such as logging a deprecation warning and either
migrating the datasource to an alternative type (like MSSQL or Postgres) or
providing a graceful fallback configuration. This prevents runtime failures for
existing Synapse datasource records while providing users with a clear
migration/deprecation message.

---

Duplicate comments:
In `@wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py`:
- Around line 390-391: The line assigning columns from data[0].keys() does not
handle the case where data[0] is an empty dictionary, which results in an empty
columns list and generates malformed SQL. Add a guard condition after the
columns assignment in the redshift.py file to check if the columns list is empty
and raise an appropriate error or handle this edge case before proceeding with
SQL generation. This ensures the code does not attempt to create INSERT
statements with empty column lists.

---

Nitpick comments:
In `@wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py`:
- Line 435: The INSERT statement construction at line 435 inserts the
`table_name` variable directly without quotes, while column identifiers are
quoted elsewhere. To ensure consistency and prevent syntax errors when table
names happen to be SQL keywords, add quotes around the `table_name` variable in
the INSERT command f-string, matching the quoting approach used for the
`column_list`.

In `@wavefront/server/plugins/datasource/datasource/__init__.py`:
- Around line 21-22: The function parameter at the boundary currently accepts
the full DataSourceType enum while only supporting four specific types
(BigQuery, Redshift, Postgres, MSSQL). Make unsupported types explicit by either
narrowing the type hint for the datasource_type parameter to only accept the
four supported types using a Literal or Union type annotation, or by adding an
explicit branch that catches AZURE_SYNAPSE specifically and raises a clear
deprecation error. Apply the same fix to the corresponding location at lines
49-50 to maintain consistency across all boundaries accepting datasource types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b79ef9f8-588c-458e-8074-5a78c5529ab3

📥 Commits

Reviewing files that changed from the base of the PR and between 3fe5c2d and 4d8b42a.

⛔ Files ignored due to path filters (1)
  • wavefront/server/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • wavefront/server/modules/plugins_module/plugins_module/controllers/datasource_controller.py
  • wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py
  • wavefront/server/packages/flo_cloud/flo_cloud/aws/redshift.py
  • wavefront/server/packages/flo_cloud/flo_cloud/azure/__init__.py
  • wavefront/server/packages/flo_cloud/flo_cloud/azure/synapse.py
  • wavefront/server/packages/flo_cloud/pyproject.toml
  • wavefront/server/plugins/datasource/datasource/__init__.py
  • wavefront/server/plugins/datasource/datasource/synapse/__init__.py
  • wavefront/server/plugins/datasource/datasource/synapse/config.py
💤 Files with no reviewable changes (5)
  • wavefront/server/plugins/datasource/datasource/synapse/config.py
  • wavefront/server/plugins/datasource/datasource/synapse/init.py
  • wavefront/server/packages/flo_cloud/flo_cloud/azure/synapse.py
  • wavefront/server/packages/flo_cloud/pyproject.toml
  • wavefront/server/modules/plugins_module/plugins_module/controllers/datasource_controller.py

Comment on lines +24 to 25
BigQueryConfig | RedshiftConfig | PostgresConfig | MSSQLConfig,
]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Return type annotation no longer matches actual return values.

This function can return (None, None) but the annotated tuple currently excludes None for both elements. Please update the signature to reflect the nullable return contract.

Also applies to: 30-30

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@wavefront/server/modules/plugins_module/plugins_module/services/datasource_services.py`
around lines 24 - 25, The return type annotation for the function that returns a
tuple of config types does not account for the actual return value of (None,
None). Update the type annotation on the return statement to indicate that both
elements of the tuple can be None by making each config type optional using the
union operator with None or Optional. This change applies to the return type
annotation around line 24-25 and also at line 30, so ensure both locations are
updated to match the actual nullable return contract.

@vishnurk6247 vishnurk6247 merged commit 8e300f4 into develop Jun 23, 2026
10 checks passed
@vishnurk6247 vishnurk6247 deleted the feat/redshift-insert branch June 23, 2026 12:23
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.

2 participants