Implement basic table and column name completion
This commit is contained in:
parent
f612f51e72
commit
a0509b4b55
1 changed files with 117 additions and 12 deletions
129
src/index.ts
129
src/index.ts
|
@ -5,6 +5,36 @@ import readline from 'node:readline'
|
|||
import oracledb from 'oracledb'
|
||||
import { findUpSync } from 'find-up'
|
||||
|
||||
interface OraTable {
|
||||
OWNER: string
|
||||
TABLE_NAME: string
|
||||
}
|
||||
|
||||
interface OraColumn {
|
||||
OWNER: string
|
||||
TABLE_NAME: string
|
||||
COLUMN_NAME: string
|
||||
DATA_TYPE: string
|
||||
DATA_LENGTH: number | null
|
||||
NULLABLE: 'Y' | 'N'
|
||||
}
|
||||
|
||||
interface Schema {
|
||||
tables: Table[]
|
||||
}
|
||||
|
||||
interface Table {
|
||||
owner: string
|
||||
name: string
|
||||
columns: Column[]
|
||||
}
|
||||
|
||||
interface Column {
|
||||
name: string
|
||||
datatype: string
|
||||
nullable: boolean
|
||||
}
|
||||
|
||||
function getStringParts(str: string, offset: number) {
|
||||
const init = str.slice(0, offset)
|
||||
|
||||
|
@ -43,10 +73,96 @@ async function main() {
|
|||
prompt: `${user}@${connectString}> `,
|
||||
removeHistoryDuplicates: true,
|
||||
history,
|
||||
completer(linePartial: string) {
|
||||
const words = [...rl.line.matchAll(/[a-zA-Z0-9_.$]+/g).map((g) => g[0])]
|
||||
words.push(...words.map((w) => w.toUpperCase()))
|
||||
const wset = new Set(words)
|
||||
|
||||
const completions = ['DUAL']
|
||||
const tables = schema.tables.filter((tab) => {
|
||||
if (tab.owner) {
|
||||
const fullName = `${tab.owner}.${tab.name}`
|
||||
completions.push(fullName)
|
||||
if (wset.has(fullName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (['', 'SYS', 'WMSYS'].includes(tab.owner)) {
|
||||
completions.push(tab.name)
|
||||
return wset.has(tab.name)
|
||||
}
|
||||
})
|
||||
|
||||
for (const tab of tables) {
|
||||
for (const col of tab.columns) {
|
||||
completions.push(col.name)
|
||||
}
|
||||
}
|
||||
|
||||
completions.sort()
|
||||
|
||||
const suffix = linePartial.match(/[a-zA-Z0-9_$]*.$/)?.[0] ?? ''
|
||||
const upper = suffix.toUpperCase()
|
||||
const prefix = linePartial.substring(0, linePartial.length - suffix.length)
|
||||
|
||||
return [
|
||||
completions
|
||||
.filter((comp) => comp.startsWith(suffix) || comp.startsWith(upper))
|
||||
.map((comp) => prefix + comp),
|
||||
linePartial,
|
||||
]
|
||||
},
|
||||
})
|
||||
|
||||
const connection = await oracledb.getConnection({ user, password, connectString })
|
||||
|
||||
function execute<R>(query: string, args: any[] = [], maxRows?: number) {
|
||||
return connection.execute<R>(query, args, {
|
||||
dbObjectAsPojo: true,
|
||||
prefetchRows: 1024,
|
||||
fetchArraySize: 1024,
|
||||
maxRows,
|
||||
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
||||
resultSet: false,
|
||||
})
|
||||
}
|
||||
|
||||
const schema: Schema = { tables: [] }
|
||||
|
||||
async function refresh() {
|
||||
const tables = await execute<OraTable>(
|
||||
`
|
||||
select owner, table_name from all_tables
|
||||
union all select owner, view_name table_name from all_views
|
||||
union all select '' owner, table_name from user_tables
|
||||
union all select '' owner, view_name table_name from user_views
|
||||
`,
|
||||
)
|
||||
|
||||
const columns = await execute<OraColumn>(
|
||||
'select owner, table_name, column_name, data_type, data_length, nullable from all_tab_cols',
|
||||
)
|
||||
|
||||
schema.tables.length = 0
|
||||
|
||||
for (const table of tables.rows ?? []) {
|
||||
schema.tables.push({
|
||||
owner: table.OWNER ?? '',
|
||||
name: table.TABLE_NAME,
|
||||
columns: (columns.rows ?? [])
|
||||
.filter((col) => col.OWNER === table.OWNER && col.TABLE_NAME === table.TABLE_NAME)
|
||||
.map((col) => ({
|
||||
name: col.COLUMN_NAME,
|
||||
datatype:
|
||||
col.DATA_LENGTH === null ? col.DATA_TYPE : `${col.DATA_TYPE}(${col.DATA_LENGTH})`,
|
||||
nullable: col.NULLABLE === 'Y',
|
||||
})),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
await refresh()
|
||||
rl.prompt()
|
||||
|
||||
let displayMode: 'table' | 'list' = 'table'
|
||||
|
@ -66,18 +182,7 @@ async function main() {
|
|||
process.exit(0)
|
||||
} else if (query) {
|
||||
try {
|
||||
const result = await connection.execute(
|
||||
query,
|
||||
{},
|
||||
{
|
||||
dbObjectAsPojo: true,
|
||||
prefetchRows: 1024,
|
||||
fetchArraySize: 1024,
|
||||
maxRows: 1024,
|
||||
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
||||
resultSet: false,
|
||||
},
|
||||
)
|
||||
const result = await execute(query, [], 1024)
|
||||
if (result.rows && result.rows.length > 0) {
|
||||
if (displayMode === 'table') {
|
||||
console.table(result.rows)
|
||||
|
|
Loading…
Reference in a new issue