-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(resource): ensure that redundant aliases and join wrapping parens…
… dont affect diff for VIEW also, refactor the heavily normalize view dir for better maintainability
- Loading branch information
1 parent
b954d9f
commit f6e9f7f
Showing
19 changed files
with
361 additions
and
88 deletions.
There are no files selected for viewing
84 changes: 0 additions & 84 deletions
84
...ourceDefinition/normalizeDDLToSupportLossyShowCreateStatements/heavilyNormalizeViewDDL.ts
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
...l/normalizations/__snapshots__/removeParenthesisSurroundingJoinsInFromClause.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`removeParenthesisSurroundingJoinsInFromClause should remove them from every join 1`] = ` | ||
"select | ||
s.id as id, | ||
s.uuid as uuid, | ||
s.name as name, | ||
s.created_at as created_at, | ||
v.effective_at as effective_at, | ||
v.created_at as updated_at | ||
from | ||
contractor s | ||
join contractor_cvp cvp on s.id = cvp.contractor_id | ||
join contractor_version v on v.id = cvp.contractor_version_id | ||
" | ||
`; |
25 changes: 25 additions & 0 deletions
25
...rmalizeViewDdl/normalizations/__snapshots__/removeRedundantAliasDeclarations.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`removeRedundantAliasDeclarations redundant declarations to be removed and nonredundant to remain 1`] = ` | ||
" | ||
CREATE VIEW \`view_contractor_current\` AS | ||
SELECT | ||
s.id, | ||
s.uuid, | ||
s.name, | ||
( | ||
SELECT GROUP_CONCAT(contractor_version_to_contractor_license.contractor_license_id ORDER BY contractor_version_to_contractor_license.array_order_index) | ||
FROM contractor_version_to_contractor_license WHERE contractor_version_to_contractor_license.contractor_version_id = v.id | ||
) as license_ids, | ||
( | ||
SELECT GROUP_CONCAT(contractor_version_to_contact_method.contact_method_id ORDER BY contractor_version_to_contact_method.array_order_index) | ||
FROM contractor_version_to_contact_method WHERE contractor_version_to_contact_method.contractor_version_id = v.id | ||
) as proposed_suggestion_change_ids, | ||
s.created_at, | ||
v.effective_at, | ||
v.created_at as updated_at | ||
FROM contractor s | ||
JOIN contractor_cvp cvp ON s.id = cvp.contractor_id | ||
JOIN contractor_version v ON v.id = cvp.contractor_version_id; | ||
" | ||
`; |
6 changes: 6 additions & 0 deletions
6
...ivelyHeavilyNormalizeViewDdl/normalizations/addSpacesBetweenCommaParenthesisOccurances.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* replace `,(` patterns w/ space in between, since our formatter downstream does not like that | ||
*/ | ||
export const addSpacesBetweenCommaParenthesisOccurances = ({ ddl }: { ddl: string }) => { | ||
return ddl.replace(/,\(/g, ', ('); | ||
}; |
10 changes: 10 additions & 0 deletions
10
...s/recursivelyHeavilyNormalizeViewDdl/normalizations/lowercaseAllAsTokensExceptFirstOne.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* make all "as" words, except the first, lowercase | ||
* | ||
* for some reason, SHOW CREATE lowercases all tokens EXCEPT `as`, which it explicitly upper cases...) | ||
*/ | ||
export const lowercaseAllAsTokensExceptFirstOne = ({ ddl }: { ddl: string }) => { | ||
return ddl | ||
.replace(/ AS /g, ' as ') // /g to apply to each | ||
.replace(/ as /, ' AS '); // no /g so only apply to first case | ||
}; |
8 changes: 8 additions & 0 deletions
8
...ents/recursivelyHeavilyNormalizeViewDdl/normalizations/lowercaseEverythingAfterFirstAs.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* lowercase everything in the query, since show create does :upside_down_smiley: | ||
*/ | ||
export const lowercaseEverythingAfterFirstAs = ({ ddl }: { ddl: string }) => { | ||
const casedAsDdlParts = ddl.split(' AS '); | ||
const casedDdl = [casedAsDdlParts[0], casedAsDdlParts[1].toLowerCase()].join(' AS '); | ||
return casedDdl; | ||
}; |
8 changes: 8 additions & 0 deletions
8
...wCreateStatements/recursivelyHeavilyNormalizeViewDdl/normalizations/removeAllBackticks.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* strip out all of the back ticks. | ||
* | ||
* SHOW CREATE puts backticks __everywhere__ | ||
* | ||
* until we have an example where that breaks something, they're just too much to force users to have to maintain | ||
*/ | ||
export const removeAllBackticks = ({ ddl }: { ddl: string }) => ddl.replace(/`/g, ''); |
6 changes: 6 additions & 0 deletions
6
...sivelyHeavilyNormalizeViewDdl/normalizations/removeDoubleParenthesisInJoinOnConditions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* strip out the "double parenthesis" that SHOW CREATE likes to put on the "join on" statements | ||
*/ | ||
export const removeDoubleParenthesisInJoinOnConditions = ({ sql }: { sql: string }) => { | ||
return sql.replace(/ on\(\((\w+\.\w+\s=\s\w+\.\w+)\)\)/g, ' on $1 '); // note: strictly only do this if matching the SHOW CREATE weird format of ` on((tableA.column = tableB.column))` | ||
}; |
6 changes: 6 additions & 0 deletions
6
...reateStatements/recursivelyHeavilyNormalizeViewDdl/normalizations/removeFinalSemicolon.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* show create drops the final semicolon. it really doesnt matter if the user still has theirs | ||
*/ | ||
export const removeFinalSemicolon = ({ ddl }: { ddl: string }) => { | ||
return ddl.replace(/;/g, ''); | ||
}; |
16 changes: 16 additions & 0 deletions
16
...recursivelyHeavilyNormalizeViewDdl/normalizations/removeParenthesisFromWhereConditions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/** | ||
* strip out all of the parenthesis (since SHOW CREATE adds them everywhere and thats too much to force users to maintain); unideal since it modifies the meaning, but this is only relevant for diffing | ||
*/ | ||
export const removeParenthesisFromWhereConditions = ({ flattenedSql }: { flattenedSql: string }) => { | ||
const whereCasing = !!flattenedSql.match(/\sWHERE\s/) ? 'WHERE' : 'where'; // determine if user is using upper case or lower case "where" | ||
const sqlSplitOnWhere = flattenedSql.split(whereCasing); | ||
if (sqlSplitOnWhere.length > 2) { | ||
// should not occur because the sql should have been flattened already | ||
throw new Error('found more than two parts of DDL after splitting on where; unexpected'); // fail fast | ||
} | ||
const sqlWithoutParens = | ||
sqlSplitOnWhere.length === 2 | ||
? sqlSplitOnWhere[0] + '\n' + whereCasing + '\n' + sqlSplitOnWhere[1].replace(/[\(\)]/g, '') // tslint:disable-line prefer-template | ||
: sqlSplitOnWhere[0]; // if no where clause, then nothing to replace | ||
return sqlWithoutParens; | ||
}; |
27 changes: 27 additions & 0 deletions
27
...vilyNormalizeViewDdl/normalizations/removeParenthesisSurroundingJoinsInFromClause.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { removeParenthesisSurroundingJoinsInFromClause } from './removeParenthesisSurroundingJoinsInFromClause'; | ||
|
||
describe('removeParenthesisSurroundingJoinsInFromClause', () => { | ||
it('should remove them from every join', () => { | ||
const exampleSql = ` | ||
select | ||
s.id as id, | ||
s.uuid as uuid, | ||
s.name as name, | ||
s.created_at as created_at, | ||
v.effective_at as effective_at, | ||
v.created_at as updated_at | ||
from | ||
( | ||
( | ||
contractor s | ||
join contractor_cvp cvp on s.id = cvp.contractor_id | ||
) | ||
join contractor_version v on v.id = cvp.contractor_version_id | ||
) | ||
`.trim(); | ||
const normalizedSql = removeParenthesisSurroundingJoinsInFromClause({ flattenedSql: exampleSql }); | ||
expect(normalizedSql).not.toContain('('); | ||
expect(normalizedSql).not.toContain(')'); | ||
expect(normalizedSql).toMatchSnapshot(); | ||
}); | ||
}); |
23 changes: 23 additions & 0 deletions
23
...lyHeavilyNormalizeViewDdl/normalizations/removeParenthesisSurroundingJoinsInFromClause.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* strip out the first and last paren of the "FROM" section, IF it is defined; | ||
* | ||
* show create likes to wrap the whole "FROM" section w/ parens... its unreasonable to ask people to do that too. | ||
*/ | ||
export const removeParenthesisSurroundingJoinsInFromClause = ({ flattenedSql }: { flattenedSql: string }) => { | ||
// check that this sql has this situation going on, if not, do nothing | ||
const ddlHasParenOpenRightAfterFromClause = !!flattenedSql.match(/\sfrom\s+\(/gi); // note, we're not worried about subqueries because we expect flattenedSql as input | ||
if (!ddlHasParenOpenRightAfterFromClause) return flattenedSql; // do nothing if the situation does not exist | ||
|
||
// split DDL on the from statement, since we know it exists | ||
const flattenedSqlParts = flattenedSql.split(/\sfrom\s/gi); | ||
if (flattenedSqlParts.length !== 2) throw new Error('not exactly two parts after splitting on from; unexpected'); // fail fast | ||
|
||
// remove the parens that encapsulate each join | ||
const fromClauseWithoutParens = flattenedSqlParts[1].replace(/\(/g, '').replace(/\)/g, ''); // note: we replace all parens, since subqueries are taken care of | ||
|
||
// join them back and the ddl w/o this mess | ||
const flattenedSqlWithoutOpenCloseParenInFromClause = flattenedSqlParts[0] + '\nfrom\n' + fromClauseWithoutParens; // tslint:disable-line prefer-template | ||
|
||
// return without the parens | ||
return flattenedSqlWithoutOpenCloseParenInFromClause; | ||
}; |
31 changes: 31 additions & 0 deletions
31
...ecursivelyHeavilyNormalizeViewDdl/normalizations/removeRedundantAliasDeclarations.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { removeRedundantAliasDeclarations } from './removeRedundantAliasDeclarations'; | ||
|
||
describe('removeRedundantAliasDeclarations', () => { | ||
test('redundant declarations to be removed and nonredundant to remain', () => { | ||
const exampleSql = ` | ||
CREATE VIEW \`view_contractor_current\` AS | ||
SELECT | ||
s.id, | ||
s.uuid as uuid, | ||
s.name as name, | ||
( | ||
SELECT GROUP_CONCAT(contractor_version_to_contractor_license.contractor_license_id ORDER BY contractor_version_to_contractor_license.array_order_index) | ||
FROM contractor_version_to_contractor_license WHERE contractor_version_to_contractor_license.contractor_version_id = v.id | ||
) as license_ids, | ||
( | ||
SELECT GROUP_CONCAT(contractor_version_to_contact_method.contact_method_id ORDER BY contractor_version_to_contact_method.array_order_index) | ||
FROM contractor_version_to_contact_method WHERE contractor_version_to_contact_method.contractor_version_id = v.id | ||
) as proposed_suggestion_change_ids, | ||
s.created_at, | ||
v.effective_at, | ||
v.created_at as updated_at | ||
FROM contractor s | ||
JOIN contractor_cvp cvp ON s.id = cvp.contractor_id | ||
JOIN contractor_version v ON v.id = cvp.contractor_version_id; | ||
`; | ||
const normalizedSql = removeRedundantAliasDeclarations({ sql: exampleSql }); | ||
expect(normalizedSql).not.toContain('as uuid'); | ||
expect(normalizedSql).not.toContain('as name'); | ||
expect(normalizedSql).toMatchSnapshot(); // for visual inspection to make sure no other defects occured | ||
}); | ||
}); |
Oops, something went wrong.