diff --git a/README.md b/README.md
index 793339a..d2cebce 100644
--- a/README.md
+++ b/README.md
@@ -168,6 +168,11 @@ Defaults to "?".
The characters that can be used to quote identifiers. Defaults
to "\"".
+
+ identifiercaseinsensitive?: boolean
+
+Controls whether identifiers are case-insensitive. Identifiers with upper-case letters are quoted then set to false. Defaults
+to false.
unquotedBitLiterals?: boolean
diff --git a/src/complete.ts b/src/complete.ts
index 34341f1..7ff703d 100644
--- a/src/complete.ts
+++ b/src/complete.ts
@@ -101,14 +101,14 @@ class CompletionLevel {
list: Completion[] = []
children: {[name: string]: CompletionLevel} | undefined = undefined
- constructor(readonly idQuote: string) {}
+ constructor(readonly idQuote: string, readonly idCaseInsensitive?: boolean) {}
child(name: string) {
let children = this.children || (this.children = Object.create(null))
let found = children[name]
if (found) return found
- if (name && !this.list.some(c => c.label == name)) this.list.push(nameCompletion(name, "type", this.idQuote))
- return (children[name] = new CompletionLevel(this.idQuote))
+ if (name && !this.list.some(c => c.label == name)) this.list.push(nameCompletion(name, "type", this.idQuote, this.idCaseInsensitive))
+ return (children[name] = new CompletionLevel(this.idQuote, this.idCaseInsensitive))
}
maybeChild(name: string) {
@@ -123,7 +123,7 @@ class CompletionLevel {
addCompletions(completions: readonly (Completion | string)[]) {
for (let option of completions)
- this.addCompletion(typeof option == "string" ? nameCompletion(option, "property", this.idQuote) : option)
+ this.addCompletion(typeof option == "string" ? nameCompletion(option, "property", this.idQuote, this.idCaseInsensitive) : option)
}
addNamespace(namespace: SQLNamespace) {
@@ -154,8 +154,9 @@ class CompletionLevel {
}
}
-function nameCompletion(label: string, type: string, idQuote: string): Completion {
- if (/^[a-z_][a-z_\d]*$/.test(label)) return {label, type}
+function nameCompletion(label: string, type: string, idQuote: string, idCaseInsensitive: boolean): Completion {
+ const regex = new RegExp("^[a-z_][a-z_\\d]*$", idCaseInsensitive ? 'i' : undefined);
+ if (regex.test(label)) return {label, type}
return {label, type, apply: idQuote + label + idQuote}
}
@@ -168,7 +169,7 @@ export function completeFromSchema(schema: SQLNamespace,
defaultTableName?: string, defaultSchemaName?: string,
dialect?: SQLDialect): CompletionSource {
let idQuote = dialect?.spec.identifierQuotes?.[0] || '"'
- let top = new CompletionLevel(idQuote)
+ let top = new CompletionLevel(idQuote, dialect?.spec.identifierCaseInsensitive)
let defaultSchema = defaultSchemaName ? top.child(defaultSchemaName) : null
top.addNamespace(schema)
if (tables) (defaultSchema || top).addCompletions(tables)
diff --git a/src/sql.ts b/src/sql.ts
index 0e2351c..7ac932c 100644
--- a/src/sql.ts
+++ b/src/sql.ts
@@ -76,6 +76,10 @@ export type SQLDialectSpec = {
/// The characters that can be used to quote identifiers. Defaults
/// to `"\""`.
identifierQuotes?: string
+ /// Controls whether identifiers are case-insensitive. Identifiers
+ /// with upper-case letters are quoted then set to false. Defaults to
+ /// false.
+ identifierCaseInsensitive?: boolean,
/// Controls whether bit values can be defined as 0b1010. Defaults
/// to false.
unquotedBitLiterals?: boolean,
diff --git a/src/tokens.ts b/src/tokens.ts
index 585df14..3c72707 100644
--- a/src/tokens.ts
+++ b/src/tokens.ts
@@ -168,6 +168,7 @@ export interface Dialect {
operatorChars: string,
specialVar: string,
identifierQuotes: string,
+ identifierCaseInsensitive: boolean,
words: {[name: string]: number}
}
@@ -188,6 +189,7 @@ const defaults: Dialect = {
operatorChars: "*+\-%<>!=&|~^/",
specialVar: "?",
identifierQuotes: '"',
+ identifierCaseInsensitive: false,
words: keywords(SQLKeywords, SQLTypes)
}
diff --git a/test/test-complete.ts b/test/test-complete.ts
index 3562093..f7386fe 100644
--- a/test/test-complete.ts
+++ b/test/test-complete.ts
@@ -1,6 +1,6 @@
import {EditorState} from "@codemirror/state"
import {CompletionContext, CompletionResult, CompletionSource} from "@codemirror/autocomplete"
-import {schemaCompletionSource, PostgreSQL, MySQL, SQLConfig} from "@codemirror/lang-sql"
+import {schemaCompletionSource, PostgreSQL, MySQL, SQLConfig, SQLDialect} from "@codemirror/lang-sql"
import ist from "ist"
function get(doc: string, conf: SQLConfig & {explicit?: boolean} = {}) {
@@ -162,6 +162,15 @@ describe("SQL completion", () => {
'`b c`, `b-c`, bup')
})
+ it("adds identifiers for upper case completions", () => {
+ ist(str(get("foo.c|", {schema: {foo: ["Column", "cell"]}, dialect: PostgreSQL})),
+ '"Column", cell')
+
+ const customDialect = SQLDialect.define({...PostgreSQL.spec, identifierCaseInsensitive: true})
+ ist(str(get("foo.c|", {schema: {foo: ["Column", "cell"]}, dialect: customDialect})),
+ 'Column, cell')
+ })
+
it("supports nesting more than two deep", () => {
let s = {schema: {"one.two.three": ["four"]}}
ist(str(get("o|", s)), "one")