[DATABRICKS-4] PLU-600: add databricks create row action#1529
[DATABRICKS-4] PLU-600: add databricks create row action#1529pregnantboy wants to merge 1 commit intodatabricks/3-dynamic-datafrom
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
9df0e2b to
23f55f5
Compare
189d3bc to
f94b3fa
Compare
| rowData: z.array( | ||
| z.object({ | ||
| columnName: z | ||
| .string() | ||
| .min(1, { message: 'Column name is required' }) | ||
| .regex(/^[a-z0-9_]+$/, { | ||
| message: | ||
| 'Column name can only contain lowercase letters, numbers and underscores', | ||
| }), | ||
| columnValue: z.string(), | ||
| }), | ||
| ), |
There was a problem hiding this comment.
The rowData array schema has no minimum length validation, allowing empty arrays. This will generate invalid SQL like INSERT INTO table () VALUES () and cause execution to fail.
Fix by adding minimum length validation:
rowData: z.array(
z.object({
columnName: z
.string()
.min(1, { message: 'Column name is required' })
.regex(/^[a-z0-9_]+$/, {
message:
'Column name can only contain lowercase letters, numbers and underscores',
}),
columnValue: z.string(),
}),
).min(1, { message: 'At least one column is required' }),| rowData: z.array( | |
| z.object({ | |
| columnName: z | |
| .string() | |
| .min(1, { message: 'Column name is required' }) | |
| .regex(/^[a-z0-9_]+$/, { | |
| message: | |
| 'Column name can only contain lowercase letters, numbers and underscores', | |
| }), | |
| columnValue: z.string(), | |
| }), | |
| ), | |
| rowData: z.array( | |
| z.object({ | |
| columnName: z | |
| .string() | |
| .min(1, { message: 'Column name is required' }) | |
| .regex(/^[a-z0-9_]+$/, { | |
| message: | |
| 'Column name can only contain lowercase letters, numbers and underscores', | |
| }), | |
| columnValue: z.string(), | |
| }), | |
| ).min(1, { message: 'At least one column is required' }), | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
There was a problem hiding this comment.
unlikely to happen but good to have
23f55f5 to
6e6fe2e
Compare
f94b3fa to
6ee411e
Compare
6e6fe2e to
62c5d53
Compare
6ee411e to
41da125
Compare
| const { session, endSession } = await createSession($) | ||
| const { tableName, rowData } = parametersParseResult.data | ||
| const columnNames = rowData.map((row) => row.columnName) | ||
| const columnValues = rowData.map((row) => row.columnValue) | ||
|
|
||
| const statement = `INSERT INTO \`${tableName}\` (${columnNames | ||
| .map((col) => `\`${col}\``) | ||
| .join(',')}) VALUES (${columnValues | ||
| .map((_val, index) => `:val${index}`) | ||
| .join(',')})` | ||
| const namedParameters = {} as Record<string, string> | ||
| for (let i = 0; i < columnValues.length; i++) { | ||
| namedParameters[`val${i}`] = columnValues[i] | ||
| } | ||
| const operation = await session.executeStatement(statement, { | ||
| namedParameters, | ||
| }) | ||
| await operation.fetchAll() | ||
| await endSession() |
There was a problem hiding this comment.
Resource leak: if an error occurs during statement execution or fetchAll (lines 140-143), the session created on line 126 is never closed, as endSession() on line 144 is skipped when the catch block is entered. This will leak Databricks sessions in production.
Fix by ensuring cleanup:
const { session, endSession } = await createSession($)
try {
const { tableName, rowData } = parametersParseResult.data
// ... SQL execution ...
await operation.fetchAll()
} finally {
await endSession()
}| const { session, endSession } = await createSession($) | |
| const { tableName, rowData } = parametersParseResult.data | |
| const columnNames = rowData.map((row) => row.columnName) | |
| const columnValues = rowData.map((row) => row.columnValue) | |
| const statement = `INSERT INTO \`${tableName}\` (${columnNames | |
| .map((col) => `\`${col}\``) | |
| .join(',')}) VALUES (${columnValues | |
| .map((_val, index) => `:val${index}`) | |
| .join(',')})` | |
| const namedParameters = {} as Record<string, string> | |
| for (let i = 0; i < columnValues.length; i++) { | |
| namedParameters[`val${i}`] = columnValues[i] | |
| } | |
| const operation = await session.executeStatement(statement, { | |
| namedParameters, | |
| }) | |
| await operation.fetchAll() | |
| await endSession() | |
| const { session, endSession } = await createSession($) | |
| try { | |
| const { tableName, rowData } = parametersParseResult.data | |
| const columnNames = rowData.map((row) => row.columnName) | |
| const columnValues = rowData.map((row) => row.columnValue) | |
| const statement = `INSERT INTO \`${tableName}\` (${columnNames | |
| .map((col) => `\`${col}\``) | |
| .join(',')}) VALUES (${columnValues | |
| .map((_val, index) => `:val${index}`) | |
| .join(',')})` | |
| const namedParameters = {} as Record<string, string> | |
| for (let i = 0; i < columnValues.length; i++) { | |
| namedParameters[`val${i}`] = columnValues[i] | |
| } | |
| const operation = await session.executeStatement(statement, { | |
| namedParameters, | |
| }) | |
| await operation.fetchAll() | |
| } finally { | |
| await endSession() | |
| } |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
There was a problem hiding this comment.
seems valid. if somehow createSession fails, it will still be caught and thrown anw
kevinkim-ogp
left a comment
There was a problem hiding this comment.
lgtm, can create row successfully via the action!
probably can address the two comments from Graphite, both seem valid.
sidenote: users can manually upload datasets to databricks with invalid column names i.e., with spaces, and our action will fail. doesn't seem like we have much control over this, but probably good to include somewhere in our guide
| rowData: z.array( | ||
| z.object({ | ||
| columnName: z | ||
| .string() | ||
| .min(1, { message: 'Column name is required' }) | ||
| .regex(/^[a-z0-9_]+$/, { | ||
| message: | ||
| 'Column name can only contain lowercase letters, numbers and underscores', | ||
| }), | ||
| columnValue: z.string(), | ||
| }), | ||
| ), |
There was a problem hiding this comment.
unlikely to happen but good to have
| const { session, endSession } = await createSession($) | ||
| const { tableName, rowData } = parametersParseResult.data | ||
| const columnNames = rowData.map((row) => row.columnName) | ||
| const columnValues = rowData.map((row) => row.columnValue) | ||
|
|
||
| const statement = `INSERT INTO \`${tableName}\` (${columnNames | ||
| .map((col) => `\`${col}\``) | ||
| .join(',')}) VALUES (${columnValues | ||
| .map((_val, index) => `:val${index}`) | ||
| .join(',')})` | ||
| const namedParameters = {} as Record<string, string> | ||
| for (let i = 0; i < columnValues.length; i++) { | ||
| namedParameters[`val${i}`] = columnValues[i] | ||
| } | ||
| const operation = await session.executeStatement(statement, { | ||
| namedParameters, | ||
| }) | ||
| await operation.fetchAll() | ||
| await endSession() |
There was a problem hiding this comment.
seems valid. if somehow createSession fails, it will still be caught and thrown anw
62c5d53 to
e8e971b
Compare
41da125 to
a3de2ea
Compare
Add create-row action with zod validation and parameterized SQL insert. Supports dynamic table/column selection via dropdowns with inline create-new-column and modal create-new-table options. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e8e971b to
ea3ac20
Compare
a3de2ea to
775b175
Compare

Add create-row action for Databricks integration
Add create-row action with zod validation and parameterized SQL insert.
Supports dynamic table/column selection via dropdowns with inline
create-new-column and modal create-new-table options.
The action validates table and column names to only allow lowercase letters, numbers, and underscores. It constructs INSERT statements with named parameters for safe SQL execution and includes comprehensive error handling with structured logging.