Skip to content

Add dataTypeCase & functionCase #689

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

Merged
merged 39 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
bdf3be9
Identify PostgreSQL data types, add docs
karlhorky Nov 27, 2023
c6fb0b6
Add docs for functionCase, rename to dataTypeCase
karlhorky Nov 29, 2023
2ba9d0a
Add caveat about dataTypeCase language support
karlhorky Nov 29, 2023
10b4451
Move more data types to separate constant
karlhorky Nov 30, 2023
a555575
Add TokenType.RESERVED_DATA_TYPE and dataTypeCase
karlhorky Nov 30, 2023
129ba96
Merge branch 'separate-data-types' of github.com:karlhorky/sql-format…
karlhorky Nov 30, 2023
4ae6c48
Add functionCase option, make keywordCase default
karlhorky Nov 30, 2023
f8df2f6
Improve docs
karlhorky Nov 30, 2023
d57af57
Merge branch 'separate-data-types' of github.com:karlhorky/sql-format…
karlhorky Dec 1, 2023
9d4c929
Switch to reservedDataTypes
karlhorky Dec 1, 2023
4f46845
Revert to independent defaults
karlhorky Dec 1, 2023
bf17e85
Merge branch 'sql-formatter-org:master' into add-datatypeformat-option
karlhorky Dec 1, 2023
9815a46
Address ESLint no-nested-ternary rule error
karlhorky Dec 1, 2023
fb60928
Improve grammar and wording
karlhorky Dec 1, 2023
66d596e
Add tests for casing ARRAY data types
karlhorky Dec 1, 2023
8d81244
Add tests for dataTypeCase and functionCase
karlhorky Dec 2, 2023
a4e4070
Improve docs
karlhorky Dec 2, 2023
4ee4965
Add NUMERIC
karlhorky Dec 3, 2023
96d3ef7
Revert funcNameToKeyword() to its previous form
nene Dec 6, 2023
23848a1
Remove data types from function name lists
nene Dec 6, 2023
8db91fa
Move DB2 datatypes from functions to dataTypes array
nene Dec 6, 2023
cf7a656
Move DB2i datatypes from functions to dataTypes array
nene Dec 6, 2023
ea7f390
Move Spark datatypes from functions to dataTypes array
nene Dec 6, 2023
2ebd732
Parse parameterized data types to separate type of AST node
nene Dec 6, 2023
fdb8f32
Remove support for ANY operator in SQLite
nene Dec 6, 2023
a0a3c6b
Remove unnecessary CREATE TABLE test
nene Dec 7, 2023
bcd084d
Remove all data types from N1QL
nene Dec 7, 2023
98b3816
Merge branch 'master' into data-type-case-option
nene Dec 7, 2023
82b60bc
Remove unnecessary dataTypeCase tests (using CAST)
nene Dec 7, 2023
3b1cd75
Include parameterized types to dataTypeCase test
nene Dec 7, 2023
49731ee
Remove string format parameters from BigQuery keywords
nene Dec 7, 2023
9bf2110
Simplify ARRAY[] + dataTypeCase tests
nene Dec 7, 2023
24bf4b0
Treat the "array" in ARRAY[] as keyword (not as data type)
nene Dec 7, 2023
55bd653
Additional test for STRUCT and ARRAY in BigQuery
nene Dec 7, 2023
04947c6
Update dataTypeCase docs
nene Dec 7, 2023
aaa667e
Better examples for functionCase option docs
nene Dec 7, 2023
2e0f53f
Ensure that CAST() is cased as a function
nene Dec 7, 2023
9292b01
Update identifierCase docs with regards to functionCase
nene Dec 7, 2023
d0a7406
Fix formatting in identifierCase docs code examples
nene Dec 7, 2023
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ All fields are optional and all fields that are not specified will be filled wit
- [**`useTabs`**](docs/useTabs.md) to use tabs for indentation.
- [**`keywordCase`**](docs/keywordCase.md) uppercases or lowercases keywords.
- [**`identifierCase`**](docs/identifierCase.md) uppercases or lowercases identifiers. (**experimental!**)
- [**`dataTypeCase`**](docs/dataTypeCase.md) uppercases or lowercases data types. (**experimental!**)
- [**`functionCase`**](docs/functionCase.md) uppercases or lowercases function names. (**experimental!**)
- [**`indentStyle`**](docs/indentStyle.md) defines overall indentation style.
- [**`logicalOperatorNewline`**](docs/logicalOperatorNewline.md) newline before or after boolean operator (AND, OR, XOR).
- [**`expressionWidth`**](docs/expressionWidth.md) maximum number of characters in parenthesized expressions to be kept on single line.
Expand Down
45 changes: 45 additions & 0 deletions docs/dataTypeCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# dataTypeCase (experimental)

Converts data types to upper- or lowercase.

## Options

- `"preserve"` (default) preserves the original case.
- `"upper"` converts to uppercase.
- `"lower"` converts to lowercase.

### preserve

```sql
CREATE TABLE user (
id InTeGeR PRIMARY KEY,
first_name VarChaR(30) NOT NULL,
bio teXT,
is_email_verified BooL,
created_timestamp timestamP
);
```

### upper

```sql
CREATE TABLE user (
id INTEGER PRIMARY KEY,
first_name VARCHAR(30) NOT NULL,
bio TEXT,
is_email_verified BOOL,
created_timestamp TIMESTAMP
);
```

### lower

```sql
CREATE TABLE user (
id integer PRIMARY KEY,
first_name varchar(30) NOT NULL,
bio text,
is_email_verified bool,
created_timestamp timestamp
);
```
48 changes: 48 additions & 0 deletions docs/functionCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# functionCase (experimental)

Converts function names to upper- or lowercase.

## Options

- `"preserve"` (default) preserves the original case.
- `"upper"` converts to uppercase.
- `"lower"` converts to lowercase.

### preserve

```sql
SELECT
Concat(Trim(first_name), ' ', Trim(last_name)) AS name,
Max(salary) AS max_pay,
Cast(ssid AS INT)
FROM
employee
WHERE
expires_at > Now()
```

### upper

```sql
SELECT
CONCAT(TRIM(first_name), ' ', TRIM(last_name)) AS name,
MAX(salary) AS max_pay,
CAST(ssid AS INT)
FROM
employee
WHERE
expires_at > NOW()
```

### lower

```sql
SELECT
concat(trim(first_name), ' ', trim(last_name)) AS name,
max(salary) AS max_pay,
cast(ssid AS INT)
FROM
employee
WHERE
expires_at > now()
```
10 changes: 6 additions & 4 deletions docs/identifierCase.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ This option doesn't yet support all types of identifiers:

- prefixed variables like `@my_var` are not converted.
- parameter placeholders like `:param` are not converted.
- function names like `count(*)` are not converted (this are currently governed by `keywordCase` option instead.)

## Options

Expand All @@ -26,7 +25,8 @@ from
where
Column6
and Column7
group by Column4
group by
Column4
```

### upper
Expand All @@ -41,7 +41,8 @@ from
where
COLUMN6
and COLUMN7
group by COLUMN4
group by
COLUMN4
```

### lower
Expand All @@ -56,5 +57,6 @@ from
where
column6
and column7
group by column4
group by
column4
```
6 changes: 6 additions & 0 deletions src/FormatOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ export type KeywordCase = 'preserve' | 'upper' | 'lower';

export type IdentifierCase = 'preserve' | 'upper' | 'lower';

export type DataTypeCase = 'preserve' | 'upper' | 'lower';

export type FunctionCase = 'preserve' | 'upper' | 'lower';

export type LogicalOperatorNewline = 'before' | 'after';

export interface FormatOptions {
tabWidth: number;
useTabs: boolean;
keywordCase: KeywordCase;
identifierCase: IdentifierCase;
dataTypeCase: DataTypeCase;
functionCase: FunctionCase;
indentStyle: IndentStyle;
logicalOperatorNewline: LogicalOperatorNewline;
expressionWidth: number;
Expand Down
71 changes: 65 additions & 6 deletions src/formatter/ExpressionFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
CaseExpressionNode,
CaseWhenNode,
CaseElseNode,
DataTypeNode,
ParameterizedDataTypeNode,
} from '../parser/ast.js';

import Layout, { WS } from './Layout.js';
Expand Down Expand Up @@ -94,6 +96,8 @@ export default class ExpressionFormatter {
switch (node.type) {
case NodeType.function_call:
return this.formatFunctionCall(node);
case NodeType.parameterized_data_type:
return this.formatParameterizedDataType(node);
case NodeType.array_subscript:
return this.formatArraySubscript(node);
case NodeType.property_access:
Expand Down Expand Up @@ -130,26 +134,46 @@ export default class ExpressionFormatter {
return this.formatLineComment(node);
case NodeType.block_comment:
return this.formatBlockComment(node);
case NodeType.data_type:
return this.formatDataType(node);
case NodeType.keyword:
return this.formatKeywordNode(node);
}
}

private formatFunctionCall(node: FunctionCallNode) {
this.withComments(node.nameKw, () => {
this.layout.add(this.showKw(node.nameKw));
this.layout.add(this.showFunctionKw(node.nameKw));
});
this.formatNode(node.parenthesis);
}

private formatParameterizedDataType(node: ParameterizedDataTypeNode) {
this.withComments(node.dataType, () => {
this.layout.add(this.showDataType(node.dataType));
});
this.formatNode(node.parenthesis);
}

private formatArraySubscript(node: ArraySubscriptNode) {
let formattedArray: string;

switch (node.array.type) {
case NodeType.data_type:
formattedArray = this.showDataType(node.array);
break;
case NodeType.keyword:
formattedArray = this.showKw(node.array);
break;
default:
formattedArray = this.showIdentifier(node.array);
break;
}

this.withComments(node.array, () => {
this.layout.add(
node.array.type === NodeType.keyword
? this.showKw(node.array)
: this.showIdentifier(node.array)
);
this.layout.add(formattedArray);
});

this.formatNode(node.parenthesis);
}

Expand Down Expand Up @@ -489,6 +513,10 @@ export default class ExpressionFormatter {
}
}

private formatDataType(node: DataTypeNode) {
this.layout.add(this.showDataType(node), WS.SPACE);
}

private showKw(node: KeywordNode): string {
if (isTabularToken(node.tokenType)) {
return toTabularFormat(this.showNonTabularKw(node), this.cfg.indentStyle);
Expand All @@ -509,6 +537,26 @@ export default class ExpressionFormatter {
}
}

private showFunctionKw(node: KeywordNode): string {
if (isTabularToken(node.tokenType)) {
return toTabularFormat(this.showNonTabularFunctionKw(node), this.cfg.indentStyle);
} else {
return this.showNonTabularFunctionKw(node);
}
}

// Like showFunctionKw(), but skips tabular formatting
private showNonTabularFunctionKw(node: KeywordNode): string {
switch (this.cfg.functionCase) {
case 'preserve':
return equalizeWhitespace(node.raw);
case 'upper':
return node.text;
case 'lower':
return node.text.toLowerCase();
}
}

private showIdentifier(node: IdentifierNode): string {
if (node.quoted) {
return node.text;
Expand All @@ -523,4 +571,15 @@ export default class ExpressionFormatter {
}
}
}

private showDataType(node: DataTypeNode): string {
switch (this.cfg.dataTypeCase) {
case 'preserve':
return equalizeWhitespace(node.raw);
case 'upper':
return node.text;
case 'lower':
return node.text.toLowerCase();
}
}
}
5 changes: 2 additions & 3 deletions src/languages/bigquery/bigquery.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ export const bigquery: DialectOptions = {
reservedSetOperations,
reservedJoins,
reservedPhrases,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
extraParens: ['[]'],
stringTypes: [
Expand Down
9 changes: 0 additions & 9 deletions src/languages/bigquery/bigquery.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,13 +585,4 @@ export const functions: string[] = [
// pivot
'PIVOT',
'UNPIVOT',

// Data types with parameters like VARCHAR(100)
// https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#parameterized_data_types
'BYTES',
'NUMERIC',
'DECIMAL',
'BIGNUMERIC',
'BIGDECIMAL',
'STRING',
];
9 changes: 1 addition & 8 deletions src/languages/bigquery/bigquery.keywords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const keywords: string[] = [
];

export const dataTypes: string[] = [
// https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
'ARRAY', // parametric, ARRAY<T>
'BOOL',
'BYTES', // parameterised, BYTES(Length)
Expand All @@ -134,12 +135,4 @@ export const dataTypes: string[] = [
'STRUCT', // parametric, STRUCT<T>
'TIME',
'TIMEZONE',

// https://cloud.google.com/bigquery/docs/reference/standard-sql/conversion_functions#formatting_syntax
'HEX',
'BASEX',
'BASE64M',
'ASCII',
'UTF-8',
'UTF8',
];
5 changes: 2 additions & 3 deletions src/languages/db2/db2.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,8 @@ export const db2: DialectOptions = {
reservedSetOperations,
reservedJoins,
reservedPhrases,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
extraParens: ['[]'],
stringTypes: [
Expand Down
Loading