Skip to content
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

Add experimental dataTypeCase and functionCase options #673

Merged
merged 18 commits into from
Dec 7, 2023
Merged
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
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
52 changes: 52 additions & 0 deletions docs/dataTypeCase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# dataTypeCase (experimental)

Converts data types to upper- or lowercase.

Caveat: Only supported by languages which export `dataTypes` from their `.keywords.ts` file (eg. `bigquery`, `postgresql` and others)

Note: Casing of function names like `VARCHAR(30)` are not modified - instead rely on the `functionCase` option for this.

## Options

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

### preserve

```sql
CREATE TABLE
users (
id InTeGeR PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name VarChaR(30) NOT NULL,
bio teXT,
is_email_verified BooL NOT NULL DEFAULT FALSE,
created_timestamp timestamPtz NOT NULL DEFAULT NOW()
)
```

### upper

```sql
CREATE TABLE
users (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name VarChaR(30) NOT NULL,
bio TEXT,
is_email_verified BOOL NOT NULL DEFAULT FALSE,
created_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
```

### lower

```sql
CREATE TABLE
users (
id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name VarChaR(30) NOT NULL,
bio text,
is_email_verified bool NOT NULL DEFAULT FALSE,
created_timestamp timestamptz NOT NULL DEFAULT NOW()
)
```
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
CREATE TABLE
users (
id iNtegeR PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name VarChaR(30) NOT NULL,
bio TEXT,
is_email_verified BOOL NOT NULL DEFAULT FALSE,
created_timestamp TIMESTAMPTZ NOT NULL DEFAULT NoW()
)
```

### upper

```sql
CREATE TABLE
users (
id iNtegeR PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name VARCHAR(30) NOT NULL,
bio TEXT,
is_email_verified BOOL NOT NULL DEFAULT FALSE,
created_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
```

### lower

```sql
CREATE TABLE
users (
id iNtegeR PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
first_name varchar(30) NOT NULL,
bio TEXT,
is_email_verified BOOL NOT NULL DEFAULT FALSE,
created_timestamp TIMESTAMPTZ NOT NULL DEFAULT now()
)
```
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
61 changes: 55 additions & 6 deletions src/formatter/ExpressionFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
CaseExpressionNode,
CaseWhenNode,
CaseElseNode,
DataTypeNode,
} from '../parser/ast.js';

import Layout, { WS } from './Layout.js';
Expand Down Expand Up @@ -130,26 +131,39 @@ 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 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 +503,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 +527,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 +561,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 @@ -163,9 +163,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
5 changes: 2 additions & 3 deletions src/languages/db2/db2.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,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
5 changes: 5 additions & 0 deletions src/languages/db2/db2.keywords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,17 @@ export const keywords: string[] = [

export const dataTypes: string[] = [
// https://www.ibm.com/docs/en/db2-for-zos/12?topic=columns-data-types
'ARRAY',
'BIGINT',
'CCSID',
'CHAR',
'CHARACTER',
'DATE',
'DOUBLE',
'INT',
'INTEGER',
'LONG',
'SMALLINT',
'TIME',
'TIMESTAMP',
];
5 changes: 2 additions & 3 deletions src/languages/db2i/db2i.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,8 @@ export const db2i: DialectOptions = {
reservedSetOperations,
reservedJoins,
reservedPhrases,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
nestedBlockComments: true,
extraParens: ['[]'],
Expand Down
2 changes: 2 additions & 0 deletions src/languages/db2i/db2i.keywords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ export const keywords: string[] = [

export const dataTypes: string[] = [
// https://www.ibm.com/docs/en/i/7.2?topic=iaodsd-odbc-data-types-how-they-correspond-db2-i-database-types
'ARRAY',
'BIGINT',
'BINARY',
'BIT',
Expand All @@ -516,6 +517,7 @@ export const dataTypes: string[] = [
'DOUBLE',
'FLOAT',
'GRAPHIC',
'INT',
'INTEGER',
'LONG',
'NUMERIC',
Expand Down
5 changes: 2 additions & 3 deletions src/languages/hive/hive.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ export const hive: DialectOptions = {
reservedSetOperations,
reservedJoins,
reservedPhrases,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
extraParens: ['[]'],
stringTypes: ['""-bs', "''-bs"],
Expand Down
5 changes: 2 additions & 3 deletions src/languages/mariadb/mariadb.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,8 @@ export const mariadb: DialectOptions = {
reservedJoins,
reservedPhrases,
supportsXor: true,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
// TODO: support _ char set prefixes such as _utf8, _latin1, _binary, _utf8mb4, etc.
stringTypes: [
Expand Down
5 changes: 2 additions & 3 deletions src/languages/mysql/mysql.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,8 @@ export const mysql: DialectOptions = {
reservedJoins,
reservedPhrases,
supportsXor: true,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
// TODO: support _ char set prefixes such as _utf8, _latin1, _binary, _utf8mb4, etc.
stringTypes: [
Expand Down
5 changes: 5 additions & 0 deletions src/languages/mysql/mysql.keywords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,12 @@ export const dataTypes: string[] = [
'BIGINT', // (R)
'BINARY', // (R)
'BLOB', // (R)
'BOOL', // (R)
'BOOLEAN', // (R)
'CHAR', // (R)
'CHARACTER', // (R)
'DATE', // (R)
'DATETIME', // (R)
'DEC', // (R)
'DECIMAL', // (R)
'DOUBLE', // (R)
Expand All @@ -260,6 +264,7 @@ export const dataTypes: string[] = [
'PRECISION', // (R)
'REAL', // (R)
'SMALLINT', // (R)
'TIMESTAMP', // (R)
'TINYBLOB', // (R)
'TINYINT', // (R)
'TINYTEXT', // (R)
Expand Down
5 changes: 2 additions & 3 deletions src/languages/n1ql/n1ql.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ export const n1ql: DialectOptions = {
reservedJoins,
reservedPhrases,
supportsXor: true,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
// NOTE: single quotes are actually not supported in N1QL,
// but we support them anyway as all other SQL dialects do,
Expand Down
5 changes: 2 additions & 3 deletions src/languages/plsql/plsql.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ export const plsql: DialectOptions = {
reservedJoins,
reservedPhrases,
supportsXor: true,
reservedKeywords:
// Temporary, will be replaced by reservedDataTypes
[...new Set(keywords.concat(dataTypes))],
reservedKeywords: keywords,
reservedDataTypes: dataTypes,
reservedFunctionNames: functions,
stringTypes: [
{ quote: "''-qq", prefixes: ['N'] },
Expand Down
Loading