Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions core/actions/assertion_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,38 @@ actions:
);
});

test(`multiline rowConditions compile to single-line failing_row_condition literals`, () => {
// Regression test for #2201: a multiline rowConditions entry must not produce a
// multiline single-quoted string literal, which BigQuery rejects.
const projectDir = tmpDirFixture.createNewTmpDir();
fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML);
fs.mkdirSync(path.join(projectDir, "definitions"));
fs.writeFileSync(
path.join(projectDir, "definitions/test.sqlx"),
`config {
type: "table",
assertions: {
rowConditions: ["a > 0\n AND b > 0"]
}
}
SELECT 1 AS a, 1 AS b`
);

const result = runMainInVm(coreExecutionRequestFromPath(projectDir));

expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]);
const rowConditionsAssertion = result.compile.compiledGraph.assertions.find(
assertion => assertion.target.name === "defaultDataset_test_assertions_rowConditions"
);
// The failing_row_condition string literal has its newline escaped, so the
// single-quoted literal stays on one line...
expect(rowConditionsAssertion.query).contains(
"'a > 0\\n AND b > 0' AS failing_row_condition"
);
// ...while the WHERE NOT (...) clause keeps the raw, multiline expression.
expect(rowConditionsAssertion.query).contains("WHERE NOT (a > 0\n AND b > 0)");
});

suite("Assertions as dependencies", ({ beforeEach }) => {
[
WorkflowSettingsTemplates.bigquery,
Expand Down
13 changes: 11 additions & 2 deletions core/compilation_sql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ export class CompilationSql {
}

public sqlString(stringContents: string) {
// Escape escape characters, then escape single quotes, then wrap the string in single quotes.
return `'${stringContents.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
// Escape escape characters, then single quotes, then newlines/carriage-returns,
// and wrap the string in single quotes. BigQuery single-quoted string literals
// cannot span multiple lines, so a raw newline becomes the two-char \n escape
// (which parses back to a newline, keeping the literal single-line). Backslash
// escaping runs first so the escape sequences introduced here are not themselves
// doubled.
return `'${stringContents
.replace(/\\/g, "\\\\")
.replace(/'/g, "\\'")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")}'`;
}

public indexAssertion(dataset: string, indexCols: string[]) {
Expand Down
Loading