mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-22 08:38:08 +02:00
feat(setup): drop redundant Snowflake schema prompt; fall back to free-text on listSchemas failure
Snowflake setup previously asked for a single schema as free text, then ran a multiselect against the discovered schemas — two schema questions back-to-back, with the first being only a session bootstrap. The SDK's `schema` is optional, so the bootstrap step is unnecessary. - Remove the free-text Snowflake schema prompt; only pass `schema` to snowflake-sdk when one is configured. - When `listSchemas()` fails (e.g. role lacks SHOW SCHEMAS), prompt the user for a comma-separated list, persist it as `schema_names`, and use it as both the table-list filter and the multiselect default. Applies to every driver with a scope-discovery spec, not just Snowflake. - Update docs to lead with `schema_names`; keep `schema_name` as a documented single-schema shorthand.
This commit is contained in:
parent
fd2ba62d92
commit
70f47e8b54
4 changed files with 129 additions and 46 deletions
|
|
@ -867,12 +867,6 @@ async function buildConnectionConfig(input: {
|
|||
stringConfigField(input.existingConnection, 'database'),
|
||||
);
|
||||
if (database === undefined) return 'back';
|
||||
const schemaName = await promptText(
|
||||
prompts,
|
||||
'Snowflake schema\nPress Enter for PUBLIC, or enter a schema name.',
|
||||
stringConfigField(input.existingConnection, 'schema_name') ?? 'PUBLIC',
|
||||
);
|
||||
if (schemaName === undefined) return 'back';
|
||||
const username = await promptText(
|
||||
prompts,
|
||||
'Snowflake username',
|
||||
|
|
@ -894,14 +888,13 @@ async function buildConnectionConfig(input: {
|
|||
);
|
||||
if (role === undefined) return 'back';
|
||||
const resolvedPasswordRef = passwordRef ?? stringConfigField(input.existingConnection, 'password');
|
||||
if (!account || !warehouse || !database || !schemaName || !username || !resolvedPasswordRef) return null;
|
||||
if (!account || !warehouse || !database || !username || !resolvedPasswordRef) return null;
|
||||
return {
|
||||
driver: 'snowflake',
|
||||
authMethod: 'password',
|
||||
account,
|
||||
warehouse,
|
||||
database,
|
||||
schema_name: schemaName,
|
||||
username,
|
||||
password: resolvedPasswordRef,
|
||||
...(role ? { role } : {}),
|
||||
|
|
@ -1312,6 +1305,21 @@ async function writeScopeConfig(input: {
|
|||
});
|
||||
}
|
||||
|
||||
async function promptCommaSeparatedScope(input: {
|
||||
prompts: KtxSetupDatabasesPromptAdapter;
|
||||
connectionId: string;
|
||||
spec: ScopeDiscoverySpec;
|
||||
}): Promise<string[] | undefined> {
|
||||
const example =
|
||||
input.spec.nounPlural === 'datasets' ? 'sales, marketing' : 'SALES, MARKETING';
|
||||
const value = await promptText(
|
||||
input.prompts,
|
||||
`Enter ${input.spec.nounPlural} for ${input.connectionId} as a comma-separated list (e.g. ${example}).`,
|
||||
);
|
||||
if (value === undefined) return undefined;
|
||||
return unique(value.split(',').map((part) => part.trim()));
|
||||
}
|
||||
|
||||
async function maybeConfigureDatabaseScope(input: {
|
||||
projectDir: string;
|
||||
connectionId: string;
|
||||
|
|
@ -1382,11 +1390,15 @@ async function maybeConfigureDatabaseScope(input: {
|
|||
`Connecting to ${input.connectionId}…`,
|
||||
]);
|
||||
|
||||
const schemasFilter = await (async (): Promise<string[]> => {
|
||||
if (cliSchemas.length > 0) return cliSchemas;
|
||||
if (!spec) return [];
|
||||
let effectiveCliSchemas = cliSchemas;
|
||||
let schemasFilter: string[];
|
||||
if (effectiveCliSchemas.length > 0) {
|
||||
schemasFilter = effectiveCliSchemas;
|
||||
} else if (!spec) {
|
||||
schemasFilter = [];
|
||||
} else {
|
||||
try {
|
||||
return unique(
|
||||
schemasFilter = unique(
|
||||
await (input.deps.listSchemas ?? defaultListSchemas)(input.projectDir, input.connectionId),
|
||||
);
|
||||
} catch (error) {
|
||||
|
|
@ -1394,9 +1406,21 @@ async function maybeConfigureDatabaseScope(input: {
|
|||
input.io.stderr.write(
|
||||
`Could not discover ${spec.promptLabel.toLowerCase()} for ${input.connectionId}; ${detail}\n`,
|
||||
);
|
||||
return [];
|
||||
const prompts = input.deps.prompts ?? createPromptAdapter();
|
||||
const typed = await promptCommaSeparatedScope({ prompts, connectionId: input.connectionId, spec });
|
||||
if (typed === undefined) return 'back';
|
||||
effectiveCliSchemas = typed;
|
||||
schemasFilter = typed;
|
||||
if (typed.length > 0) {
|
||||
await writeScopeConfig({
|
||||
projectDir: input.projectDir,
|
||||
connectionId: input.connectionId,
|
||||
values: typed,
|
||||
spec,
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
let discovered: KtxTableListEntry[];
|
||||
try {
|
||||
|
|
@ -1426,7 +1450,7 @@ async function maybeConfigureDatabaseScope(input: {
|
|||
const schemasInDiscovery = unique(discovered.map((t) => t.schema));
|
||||
|
||||
const defaultSchemas = (() => {
|
||||
if (cliSchemas.length > 0) return cliSchemas;
|
||||
if (effectiveCliSchemas.length > 0) return effectiveCliSchemas;
|
||||
if (!spec) return schemasInDiscovery;
|
||||
return spec.defaultSelection(schemasInDiscovery);
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue