Add procedure introspection
This commit is contained in:
parent
ff6f568b34
commit
6a1a83eb62
1 changed files with 133 additions and 3 deletions
136
src/index.ts
136
src/index.ts
|
@ -22,8 +22,26 @@ interface OraColumn {
|
||||||
NULLABLE: 'Y' | 'N'
|
NULLABLE: 'Y' | 'N'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OraProc {
|
||||||
|
OWNER: string
|
||||||
|
OBJECT_NAME: string
|
||||||
|
PROCEDURE_NAME: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OraArg {
|
||||||
|
OWNER: string
|
||||||
|
OBJECT_NAME: string
|
||||||
|
PACKAGE_NAME: string
|
||||||
|
POSITION: number
|
||||||
|
DATA_TYPE: string
|
||||||
|
DEFAULTED: string
|
||||||
|
DEFAULT_VALUE: string | null
|
||||||
|
IN_OUT: 'IN' | 'OUT'
|
||||||
|
}
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
tables: Table[]
|
tables: Table[]
|
||||||
|
procedures: Procedure[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Table {
|
interface Table {
|
||||||
|
@ -33,12 +51,25 @@ interface Table {
|
||||||
columns: Column[]
|
columns: Column[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Procedure {
|
||||||
|
owner: string
|
||||||
|
package: string
|
||||||
|
name: string
|
||||||
|
arguments: Argument[]
|
||||||
|
}
|
||||||
|
|
||||||
interface Column {
|
interface Column {
|
||||||
name: string
|
name: string
|
||||||
datatype: string
|
datatype: string
|
||||||
identity: boolean
|
identity: boolean
|
||||||
nullable: boolean
|
nullable: boolean
|
||||||
default?: string
|
default?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Argument {
|
||||||
|
inout: string
|
||||||
|
datatype: string
|
||||||
|
default?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStringParts(str: string, offset: number) {
|
function getStringParts(str: string, offset: number) {
|
||||||
|
@ -106,9 +137,17 @@ async function main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const proc of schema.procedures) {
|
||||||
|
if (proc.owner) {
|
||||||
|
completions.push(`${proc.owner}.${proc.package}.${proc.name}`)
|
||||||
|
} else {
|
||||||
|
completions.push(`${proc.package}.${proc.name}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
completions.sort()
|
completions.sort()
|
||||||
|
|
||||||
const suffix = linePartial.match(/[a-zA-Z0-9_$]*.$/)?.[0] ?? ''
|
const suffix = linePartial.match(/[a-zA-Z0-9_.$]*.$/)?.[0] ?? ''
|
||||||
const upper = suffix.toUpperCase()
|
const upper = suffix.toUpperCase()
|
||||||
const prefix = linePartial.substring(0, linePartial.length - suffix.length)
|
const prefix = linePartial.substring(0, linePartial.length - suffix.length)
|
||||||
|
|
||||||
|
@ -135,7 +174,7 @@ async function main() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema: Schema = { tables: [] }
|
const schema: Schema = { tables: [], procedures: [] }
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
const tables = await execute<OraTable>(
|
const tables = await execute<OraTable>(
|
||||||
|
@ -155,9 +194,28 @@ async function main() {
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const procedures = await execute<OraProc>(
|
||||||
|
`
|
||||||
|
select owner, object_name, procedure_name from all_procedures
|
||||||
|
union all select '' owner, object_name, procedure_name from user_procedures
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
|
||||||
|
const procargs = await execute<OraArg>(
|
||||||
|
`
|
||||||
|
select owner, package_name, object_name, position, in_out, data_type, defaulted, default_value from all_arguments
|
||||||
|
union all select '' owner, package_name, object_name, position, in_out, data_type, defaulted, default_value from user_arguments
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (procargs.rows) {
|
||||||
|
procargs.rows.sort((a, b) => a.POSITION - b.POSITION)
|
||||||
|
}
|
||||||
|
|
||||||
const self = await execute<{ USER: string }>('select user from dual')
|
const self = await execute<{ USER: string }>('select user from dual')
|
||||||
|
|
||||||
schema.tables.length = 0
|
schema.tables.length = 0
|
||||||
|
schema.procedures.length = 0
|
||||||
|
|
||||||
for (const table of tables.rows ?? []) {
|
for (const table of tables.rows ?? []) {
|
||||||
schema.tables.push({
|
schema.tables.push({
|
||||||
|
@ -180,6 +238,30 @@ async function main() {
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const proc of procedures.rows ?? []) {
|
||||||
|
if (proc.PROCEDURE_NAME === null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.procedures.push({
|
||||||
|
owner: proc.OWNER ?? '',
|
||||||
|
package: proc.OBJECT_NAME,
|
||||||
|
name: proc.PROCEDURE_NAME,
|
||||||
|
arguments: (procargs.rows ?? [])
|
||||||
|
.filter(
|
||||||
|
(arg) =>
|
||||||
|
arg.OWNER === (proc.OWNER || self.rows![0].USER) &&
|
||||||
|
arg.PACKAGE_NAME === proc.OBJECT_NAME &&
|
||||||
|
arg.OBJECT_NAME === proc.PROCEDURE_NAME,
|
||||||
|
)
|
||||||
|
.map((arg) => ({
|
||||||
|
inout: arg.IN_OUT ?? '?',
|
||||||
|
datatype: arg.DATA_TYPE,
|
||||||
|
default: arg.DEFAULTED === 'Y' ? arg.DEFAULT_VALUE : undefined,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await refresh()
|
await refresh()
|
||||||
|
@ -202,6 +284,27 @@ async function main() {
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
} else if (query === '\\r') {
|
} else if (query === '\\r') {
|
||||||
await refresh()
|
await refresh()
|
||||||
|
} else if (query.match(/^\\[dD]p($|\s)/)) {
|
||||||
|
const procs = schema.procedures.filter((proc) => {
|
||||||
|
if (query.startsWith('\\Dp')) {
|
||||||
|
return proc.owner
|
||||||
|
} else if (query.startsWith('\\dp')) {
|
||||||
|
return !proc.owner
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [_, name] = query.split(/\s+/).map((part) => part.trim())
|
||||||
|
const upper = (name ?? '').toUpperCase()
|
||||||
|
|
||||||
|
console.table(
|
||||||
|
procs.filter((proc) => {
|
||||||
|
const fullName = `${proc.owner}.${proc.package}.${proc.name}`
|
||||||
|
return fullName.toUpperCase().includes(upper)
|
||||||
|
}),
|
||||||
|
['owner', 'package', 'name'],
|
||||||
|
)
|
||||||
} else if (query.match(/^\\[dD][tv]?($|\s)/)) {
|
} else if (query.match(/^\\[dD][tv]?($|\s)/)) {
|
||||||
const tables = schema.tables.filter((tab) => {
|
const tables = schema.tables.filter((tab) => {
|
||||||
if (query.startsWith('\\dt')) {
|
if (query.startsWith('\\dt')) {
|
||||||
|
@ -254,6 +357,33 @@ async function main() {
|
||||||
default: col.default,
|
default: col.default,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
if (displayMode === 'table') {
|
||||||
|
console.table(rows)
|
||||||
|
} else {
|
||||||
|
console.dir(rows, { depth: null })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Did not find', name)
|
||||||
|
}
|
||||||
|
} else if (query.match(/^\\[dD]p?\+?\s+\S+/)) {
|
||||||
|
const [_, name] = query.split(/\s+/).map((part) => part.trim())
|
||||||
|
const upper = name.toUpperCase()
|
||||||
|
|
||||||
|
const procedure = schema.procedures.find((proc) => {
|
||||||
|
const fullName = proc.owner
|
||||||
|
? `${proc.owner}.${proc.package}.${proc.name}`
|
||||||
|
: `${proc.package}.${proc.name}`
|
||||||
|
|
||||||
|
return fullName === name || fullName === upper
|
||||||
|
})
|
||||||
|
|
||||||
|
if (procedure) {
|
||||||
|
const rows = procedure.arguments.map((arg) => ({
|
||||||
|
inout: arg.inout,
|
||||||
|
type: arg.datatype,
|
||||||
|
default: arg.default,
|
||||||
|
}))
|
||||||
|
|
||||||
if (displayMode === 'table') {
|
if (displayMode === 'table') {
|
||||||
console.table(rows)
|
console.table(rows)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue