Skip to content

Commit f53202a

Browse files
akhaneevmarijnh
authored andcommitted
SQLDialect identifierCaseInsensitive option
1 parent 06939af commit f53202a

File tree

5 files changed

+29
-8
lines changed

5 files changed

+29
-8
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ Defaults to <code>&quot;?&quot;</code>.</p>
168168

169169
<dd><p>The characters that can be used to quote identifiers. Defaults
170170
to <code>&quot;\&quot;&quot;</code>.</p>
171+
</dd><dt id="user-content-sqldialectspec.identifiercaseinsensitive">
172+
<code><strong><a href="#user-content-sqldialectspec.identifiercaseinsensitive">identifiercaseinsensitive</a></strong>&#8288;?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a></code></dt>
173+
174+
<dd><p>Controls whether identifiers are case-insensitive. Identifiers with upper-case letters are quoted then set to false. Defaults
175+
to <code>false</code>.</p>
171176
</dd><dt id="user-content-sqldialectspec.unquotedbitliterals">
172177
<code><strong><a href="#user-content-sqldialectspec.unquotedbitliterals">unquotedBitLiterals</a></strong>&#8288;?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a></code></dt>
173178

src/complete.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ class CompletionLevel {
101101
list: Completion[] = []
102102
children: {[name: string]: CompletionLevel} | undefined = undefined
103103

104-
constructor(readonly idQuote: string) {}
104+
constructor(readonly idQuote: string, readonly idCaseInsensitive?: boolean) {}
105105

106106
child(name: string) {
107107
let children = this.children || (this.children = Object.create(null))
108108
let found = children[name]
109109
if (found) return found
110-
if (name && !this.list.some(c => c.label == name)) this.list.push(nameCompletion(name, "type", this.idQuote))
111-
return (children[name] = new CompletionLevel(this.idQuote))
110+
if (name && !this.list.some(c => c.label == name)) this.list.push(nameCompletion(name, "type", this.idQuote, this.idCaseInsensitive))
111+
return (children[name] = new CompletionLevel(this.idQuote, this.idCaseInsensitive))
112112
}
113113

114114
maybeChild(name: string) {
@@ -123,7 +123,7 @@ class CompletionLevel {
123123

124124
addCompletions(completions: readonly (Completion | string)[]) {
125125
for (let option of completions)
126-
this.addCompletion(typeof option == "string" ? nameCompletion(option, "property", this.idQuote) : option)
126+
this.addCompletion(typeof option == "string" ? nameCompletion(option, "property", this.idQuote, this.idCaseInsensitive) : option)
127127
}
128128

129129
addNamespace(namespace: SQLNamespace) {
@@ -154,8 +154,9 @@ class CompletionLevel {
154154
}
155155
}
156156

157-
function nameCompletion(label: string, type: string, idQuote: string): Completion {
158-
if (/^[a-z_][a-z_\d]*$/.test(label)) return {label, type}
157+
function nameCompletion(label: string, type: string, idQuote: string, idCaseInsensitive: boolean): Completion {
158+
const regex = new RegExp("^[a-z_][a-z_\\d]*$", idCaseInsensitive ? 'i' : undefined);
159+
if (regex.test(label)) return {label, type}
159160
return {label, type, apply: idQuote + label + idQuote}
160161
}
161162

@@ -168,7 +169,7 @@ export function completeFromSchema(schema: SQLNamespace,
168169
defaultTableName?: string, defaultSchemaName?: string,
169170
dialect?: SQLDialect): CompletionSource {
170171
let idQuote = dialect?.spec.identifierQuotes?.[0] || '"'
171-
let top = new CompletionLevel(idQuote)
172+
let top = new CompletionLevel(idQuote, dialect?.spec.identifierCaseInsensitive)
172173
let defaultSchema = defaultSchemaName ? top.child(defaultSchemaName) : null
173174
top.addNamespace(schema)
174175
if (tables) (defaultSchema || top).addCompletions(tables)

src/sql.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ export type SQLDialectSpec = {
7676
/// The characters that can be used to quote identifiers. Defaults
7777
/// to `"\""`.
7878
identifierQuotes?: string
79+
/// Controls whether identifiers are case-insensitive. Identifiers
80+
/// with upper-case letters are quoted then set to false. Defaults to
81+
/// false.
82+
identifierCaseInsensitive?: boolean,
7983
/// Controls whether bit values can be defined as 0b1010. Defaults
8084
/// to false.
8185
unquotedBitLiterals?: boolean,

src/tokens.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export interface Dialect {
168168
operatorChars: string,
169169
specialVar: string,
170170
identifierQuotes: string,
171+
identifierCaseInsensitive: boolean,
171172
words: {[name: string]: number}
172173
}
173174

@@ -188,6 +189,7 @@ const defaults: Dialect = {
188189
operatorChars: "*+\-%<>!=&|~^/",
189190
specialVar: "?",
190191
identifierQuotes: '"',
192+
identifierCaseInsensitive: false,
191193
words: keywords(SQLKeywords, SQLTypes)
192194
}
193195

test/test-complete.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {EditorState} from "@codemirror/state"
22
import {CompletionContext, CompletionResult, CompletionSource} from "@codemirror/autocomplete"
3-
import {schemaCompletionSource, PostgreSQL, MySQL, SQLConfig} from "@codemirror/lang-sql"
3+
import {schemaCompletionSource, PostgreSQL, MySQL, SQLConfig, SQLDialect} from "@codemirror/lang-sql"
44
import ist from "ist"
55

66
function get(doc: string, conf: SQLConfig & {explicit?: boolean} = {}) {
@@ -162,6 +162,15 @@ describe("SQL completion", () => {
162162
'`b c`, `b-c`, bup')
163163
})
164164

165+
it("adds identifiers for upper case completions", () => {
166+
ist(str(get("foo.c|", {schema: {foo: ["Column", "cell"]}, dialect: PostgreSQL})),
167+
'"Column", cell')
168+
169+
const customDialect = SQLDialect.define({...PostgreSQL.spec, identifierCaseInsensitive: true})
170+
ist(str(get("foo.c|", {schema: {foo: ["Column", "cell"]}, dialect: customDialect})),
171+
'Column, cell')
172+
})
173+
165174
it("supports nesting more than two deep", () => {
166175
let s = {schema: {"one.two.three": ["four"]}}
167176
ist(str(get("o|", s)), "one")

0 commit comments

Comments
 (0)