Skip to content

Commit

Permalink
Allow tables to be nested more than one level in schemaCompletionSource
Browse files Browse the repository at this point in the history
FIX: Allow table names to contain multiple dots in the schema passed to
`schemaCompletionSource`.

See https://discuss.codemirror.net/t/quoting-table-names-when-using-schemacompletionsource/6721
  • Loading branch information
marijnh committed Jun 22, 2023
1 parent be533e3 commit eb70d19
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 19 deletions.
42 changes: 23 additions & 19 deletions src/complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,23 @@ function maybeQuoteCompletions(quote: string | null, completions: readonly Compl
const Span = /^\w*$/, QuotedSpan = /^[`'"]?\w*[`'"]?$/

class CompletionLevel {
list: readonly Completion[] = []
list: Completion[] = []
children: {[name: string]: CompletionLevel} | undefined = undefined

child(name: string) {
child(name: string, idQuote: string) {
let children = this.children || (this.children = Object.create(null))
return children[name] || (children[name] = new CompletionLevel)
let found = children[name]
if (found) return found
if (name) this.list.push(nameCompletion(name, "type", idQuote))
return (children[name] = new CompletionLevel)
}

childCompletions(type: string, idQuote: string) {
return this.children ? Object.keys(this.children).filter(x => x).map(name => nameCompletion(name, type, idQuote)) : []
addCompletions(list: readonly Completion[]) {
for (let option of list) {
let found = this.list.findIndex(o => o.label == option.label)
if (found > -1) this.list[found] = option
else this.list.push(option)
}
}
}

Expand All @@ -117,21 +124,18 @@ export function completeFromSchema(schema: {[table: string]: readonly (string |
defaultTableName?: string, defaultSchemaName?: string,
dialect?: SQLDialect): CompletionSource {
let top = new CompletionLevel
let defaultSchema = top.child(defaultSchemaName || "")
let idQuote = dialect?.spec.identifierQuotes?.[0] || '"'
let defaultSchema = top.child(defaultSchemaName || "", idQuote)
for (let table in schema) {
let dot = table.indexOf(".")
let schemaCompletions = dot > -1 ? top.child(table.slice(0, dot)) : defaultSchema
let tableCompletions = schemaCompletions.child(dot > -1 ? table.slice(dot + 1) : table)
tableCompletions.list = schema[table].map(val => typeof val == "string" ? nameCompletion(val, "property", idQuote) : val)
}
defaultSchema.list = (tables || defaultSchema.childCompletions("type", idQuote))
.concat(defaultTableName ? defaultSchema.child(defaultTableName).list : [])
for (let sName in top.children) {
let schema = top.child(sName)
if (!schema.list.length) schema.list = schema.childCompletions("type", idQuote)
let parts = table.split("."), base = parts.length == 1 ? defaultSchema : top
for (let part of parts) base = base.child(part, idQuote)
for (let option of schema[table]) if (option)
base.list.push(typeof option == "string" ? nameCompletion(option, "property", idQuote) : option)
}
top.list = defaultSchema.list.concat(schemas || top.childCompletions("type", idQuote))
if (tables) defaultSchema.addCompletions(tables)
if (schemas) top.addCompletions(schemas)
top.addCompletions(defaultSchema.list)
if (defaultTableName) top.addCompletions(defaultSchema.child(defaultTableName, idQuote).list)

return (context: CompletionContext) => {
let {parents, from, quoted, empty, aliases} = sourceContext(context.state, context.pos)
Expand All @@ -141,10 +145,10 @@ export function completeFromSchema(schema: {[table: string]: readonly (string |
for (let name of parents) {
while (!level.children || !level.children[name]) {
if (level == top) level = defaultSchema
else if (level == defaultSchema && defaultTableName) level = level.child(defaultTableName)
else if (level == defaultSchema && defaultTableName) level = level.child(defaultTableName, idQuote)
else return null
}
level = level.child(name)
level = level.child(name, idQuote)
}
let quoteAfter = quoted && context.state.sliceDoc(context.pos, context.pos + 1) == quoted
let options = level.list
Expand Down
8 changes: 8 additions & 0 deletions test/test-complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,12 @@ describe("SQL completion", () => {
ist(get("foo.b|", {schema: {foo: ["b c", "b-c", "bup"]}, dialect: MySQL})!
.options.map(o => o.apply || o.label).join(), '`b c`,`b-c`,bup')
})

it("supports nesting more than two deep", () => {
let s = {schema: {"one.two.three": ["four"]}}
ist(str(get("o|", s)), "one")
ist(str(get("one.|", s)), "two")
ist(str(get("one.two.|", s)), "three")
ist(str(get("one.two.three.|", s)), "four")
})
})

0 comments on commit eb70d19

Please sign in to comment.