mirror of https://github.com/buster-so/buster.git
lint fixes
This commit is contained in:
parent
8ca932b60c
commit
3c11dbf291
|
@ -2107,20 +2107,20 @@ describe('aggregateAndCreateDatasets', () => {
|
||||||
expect(result.datasets).toHaveLength(4);
|
expect(result.datasets).toHaveLength(4);
|
||||||
|
|
||||||
// Find sales datasets
|
// Find sales datasets
|
||||||
const salesDatasets = result.datasets.filter(d => d.dataKey === 'sales');
|
const salesDatasets = result.datasets.filter((d) => d.dataKey === 'sales');
|
||||||
const profitDatasets = result.datasets.filter(d => d.dataKey === 'profit');
|
const profitDatasets = result.datasets.filter((d) => d.dataKey === 'profit');
|
||||||
|
|
||||||
expect(salesDatasets).toHaveLength(2);
|
expect(salesDatasets).toHaveLength(2);
|
||||||
expect(profitDatasets).toHaveLength(2);
|
expect(profitDatasets).toHaveLength(2);
|
||||||
|
|
||||||
// Check labels include both metric and color field
|
// Check labels include both metric and color field
|
||||||
const northSalesDataset = salesDatasets.find(d => d.colors === '#0000ff');
|
const northSalesDataset = salesDatasets.find((d) => d.colors === '#0000ff');
|
||||||
expect(northSalesDataset?.label).toEqual([
|
expect(northSalesDataset?.label).toEqual([
|
||||||
{ key: 'sales', value: '' },
|
{ key: 'sales', value: '' },
|
||||||
{ key: 'region', value: 'North' },
|
{ key: 'region', value: 'North' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const southProfitDataset = profitDatasets.find(d => d.colors === '#ff00ff');
|
const southProfitDataset = profitDatasets.find((d) => d.colors === '#ff00ff');
|
||||||
expect(southProfitDataset?.label).toEqual([
|
expect(southProfitDataset?.label).toEqual([
|
||||||
{ key: 'profit', value: '' },
|
{ key: 'profit', value: '' },
|
||||||
{ key: 'region', value: 'South' },
|
{ key: 'region', value: 'South' },
|
||||||
|
@ -2161,7 +2161,7 @@ describe('aggregateAndCreateDatasets', () => {
|
||||||
|
|
||||||
// Check that labels include product category AND color field
|
// Check that labels include product category AND color field
|
||||||
const northProductADataset = result.datasets.find(
|
const northProductADataset = result.datasets.find(
|
||||||
d => d.colors === '#aabbcc' && d.label.some(l => l.key === 'product' && l.value === 'A')
|
(d) => d.colors === '#aabbcc' && d.label.some((l) => l.key === 'product' && l.value === 'A')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(northProductADataset).toBeDefined();
|
expect(northProductADataset).toBeDefined();
|
||||||
|
@ -2172,7 +2172,7 @@ describe('aggregateAndCreateDatasets', () => {
|
||||||
expect(northProductADataset?.data).toEqual([100, 120]);
|
expect(northProductADataset?.data).toEqual([100, 120]);
|
||||||
|
|
||||||
const southProductADataset = result.datasets.find(
|
const southProductADataset = result.datasets.find(
|
||||||
d => d.colors === '#ddeeff' && d.label.some(l => l.key === 'product' && l.value === 'A')
|
(d) => d.colors === '#ddeeff' && d.label.some((l) => l.key === 'product' && l.value === 'A')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(southProductADataset).toBeDefined();
|
expect(southProductADataset).toBeDefined();
|
||||||
|
@ -2210,7 +2210,7 @@ describe('aggregateAndCreateDatasets', () => {
|
||||||
expect(result.datasets).toHaveLength(1);
|
expect(result.datasets).toHaveLength(1);
|
||||||
|
|
||||||
// Dataset A should have real data
|
// Dataset A should have real data
|
||||||
const datasetA = result.datasets.find(d => d.colors === '#ff0000');
|
const datasetA = result.datasets.find((d) => d.colors === '#ff0000');
|
||||||
expect(datasetA?.data).toEqual([100, 120]);
|
expect(datasetA?.data).toEqual([100, 120]);
|
||||||
expect(datasetA?.label).toEqual([{ key: 'category', value: 'A' }]);
|
expect(datasetA?.label).toEqual([{ key: 'category', value: 'A' }]);
|
||||||
|
|
||||||
|
|
|
@ -98,10 +98,10 @@ export function createAnalystAgent(analystAgentOptions: AnalystAgentOptions) {
|
||||||
|
|
||||||
const docsSystemMessage = docsContent
|
const docsSystemMessage = docsContent
|
||||||
? ({
|
? ({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: `<data_catalog_docs>\n${docsContent}\n</data_catalog_docs>`,
|
content: `<data_catalog_docs>\n${docsContent}\n</data_catalog_docs>`,
|
||||||
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
||||||
} as ModelMessage)
|
} as ModelMessage)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
async function stream({ messages }: AnalystStreamOptions) {
|
async function stream({ messages }: AnalystStreamOptions) {
|
||||||
|
@ -134,19 +134,19 @@ export function createAnalystAgent(analystAgentOptions: AnalystAgentOptions) {
|
||||||
// Create analyst instructions system message with proper escaping
|
// Create analyst instructions system message with proper escaping
|
||||||
const analystInstructionsMessage = analystInstructions
|
const analystInstructionsMessage = analystInstructions
|
||||||
? ({
|
? ({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: `<organization_instructions>\n${analystInstructions}\n</organization_instructions>`,
|
content: `<organization_instructions>\n${analystInstructions}\n</organization_instructions>`,
|
||||||
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
||||||
} as ModelMessage)
|
} as ModelMessage)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// Create user personalization system message
|
// Create user personalization system message
|
||||||
const userPersonalizationSystemMessage = userPersonalizationMessageContent
|
const userPersonalizationSystemMessage = userPersonalizationMessageContent
|
||||||
? ({
|
? ({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: userPersonalizationMessageContent,
|
content: userPersonalizationMessageContent,
|
||||||
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
|
||||||
} as ModelMessage)
|
} as ModelMessage)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return wrapTraced(
|
return wrapTraced(
|
||||||
|
|
|
@ -83,10 +83,14 @@ describe('Analyst Agent Instructions', () => {
|
||||||
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
|
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
|
||||||
|
|
||||||
// Ensure table references require full qualification
|
// Ensure table references require full qualification
|
||||||
expect(result).toContain('All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`');
|
expect(result).toContain(
|
||||||
|
'All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'
|
||||||
|
);
|
||||||
|
|
||||||
// Ensure column references use table aliases (not full qualifiers)
|
// Ensure column references use table aliases (not full qualifiers)
|
||||||
expect(result).toContain('All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)');
|
expect(result).toContain(
|
||||||
|
'All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'
|
||||||
|
);
|
||||||
|
|
||||||
// Ensure examples show table alias usage without full qualification
|
// Ensure examples show table alias usage without full qualification
|
||||||
expect(result).toContain('c.customerid');
|
expect(result).toContain('c.customerid');
|
||||||
|
|
|
@ -151,16 +151,23 @@ describe('Think and Prep Agent Instructions', () => {
|
||||||
['investigation', 'investigation'],
|
['investigation', 'investigation'],
|
||||||
])('SQL naming conventions in %s mode', (modeName, mode) => {
|
])('SQL naming conventions in %s mode', (modeName, mode) => {
|
||||||
it(`should contain mandatory SQL naming conventions in ${modeName} mode`, () => {
|
it(`should contain mandatory SQL naming conventions in ${modeName} mode`, () => {
|
||||||
const result = getThinkAndPrepAgentSystemPrompt('Test guidance', mode as 'standard' | 'investigation');
|
const result = getThinkAndPrepAgentSystemPrompt(
|
||||||
|
'Test guidance',
|
||||||
|
mode as 'standard' | 'investigation'
|
||||||
|
);
|
||||||
|
|
||||||
// Check for MANDATORY SQL NAMING CONVENTIONS section
|
// Check for MANDATORY SQL NAMING CONVENTIONS section
|
||||||
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
|
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
|
||||||
|
|
||||||
// Ensure table references require full qualification
|
// Ensure table references require full qualification
|
||||||
expect(result).toContain('All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`');
|
expect(result).toContain(
|
||||||
|
'All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'
|
||||||
|
);
|
||||||
|
|
||||||
// Ensure column references use table aliases (not full qualifiers)
|
// Ensure column references use table aliases (not full qualifiers)
|
||||||
expect(result).toContain('All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)');
|
expect(result).toContain(
|
||||||
|
'All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'
|
||||||
|
);
|
||||||
|
|
||||||
// Ensure examples show table alias usage without full qualification
|
// Ensure examples show table alias usage without full qualification
|
||||||
expect(result).toContain('c.customerid');
|
expect(result).toContain('c.customerid');
|
||||||
|
@ -172,7 +179,10 @@ describe('Think and Prep Agent Instructions', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should use column names qualified with table aliases in ${modeName} mode`, () => {
|
it(`should use column names qualified with table aliases in ${modeName} mode`, () => {
|
||||||
const result = getThinkAndPrepAgentSystemPrompt('Test guidance', mode as 'standard' | 'investigation');
|
const result = getThinkAndPrepAgentSystemPrompt(
|
||||||
|
'Test guidance',
|
||||||
|
mode as 'standard' | 'investigation'
|
||||||
|
);
|
||||||
|
|
||||||
// Check for the updated description
|
// Check for the updated description
|
||||||
expect(result).toContain('Use column names qualified with table aliases');
|
expect(result).toContain('Use column names qualified with table aliases');
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const DEFAULT_ANTHROPIC_OPTIONS = {
|
||||||
additionalModelRequestFields: {
|
additionalModelRequestFields: {
|
||||||
anthropic_beta: ['fine-grained-tool-streaming-2025-05-14'],
|
anthropic_beta: ['fine-grained-tool-streaming-2025-05-14'],
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_OPENAI_OPTIONS = {
|
export const DEFAULT_OPENAI_OPTIONS = {
|
||||||
|
|
|
@ -97,7 +97,7 @@ async function performUpdate({
|
||||||
/**
|
/**
|
||||||
* Updates message entries with cache-first approach for streaming.
|
* Updates message entries with cache-first approach for streaming.
|
||||||
* Cache is the source of truth during streaming, DB is updated for persistence.
|
* Cache is the source of truth during streaming, DB is updated for persistence.
|
||||||
*
|
*
|
||||||
* Updates are queued per messageId to ensure they execute in order.
|
* Updates are queued per messageId to ensure they execute in order.
|
||||||
*
|
*
|
||||||
* Merge logic:
|
* Merge logic:
|
||||||
|
@ -109,18 +109,18 @@ export async function updateMessageEntries(
|
||||||
params: UpdateMessageEntriesParams
|
params: UpdateMessageEntriesParams
|
||||||
): Promise<{ success: boolean }> {
|
): Promise<{ success: boolean }> {
|
||||||
const { messageId } = params;
|
const { messageId } = params;
|
||||||
|
|
||||||
// Get the current promise for this messageId, or use a resolved promise as the starting point
|
// Get the current promise for this messageId, or use a resolved promise as the starting point
|
||||||
const currentQueue = updateQueues.get(messageId) ?? Promise.resolve({ success: true });
|
const currentQueue = updateQueues.get(messageId) ?? Promise.resolve({ success: true });
|
||||||
|
|
||||||
// Chain the new update to run after the current queue completes
|
// Chain the new update to run after the current queue completes
|
||||||
const newQueue = currentQueue
|
const newQueue = currentQueue
|
||||||
.then(() => performUpdate(params))
|
.then(() => performUpdate(params))
|
||||||
.catch(() => performUpdate(params)); // Still try to run even if previous failed
|
.catch(() => performUpdate(params)); // Still try to run even if previous failed
|
||||||
|
|
||||||
// Update the queue for this messageId
|
// Update the queue for this messageId
|
||||||
updateQueues.set(messageId, newQueue);
|
updateQueues.set(messageId, newQueue);
|
||||||
|
|
||||||
// Clean up the queue entry once this update completes
|
// Clean up the queue entry once this update completes
|
||||||
newQueue.finally(() => {
|
newQueue.finally(() => {
|
||||||
// Only remove if this is still the current queue
|
// Only remove if this is still the current queue
|
||||||
|
@ -128,6 +128,6 @@ export async function updateMessageEntries(
|
||||||
updateQueues.delete(messageId);
|
updateQueues.delete(messageId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return newQueue;
|
return newQueue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,20 +32,21 @@ type VersionHistoryEntry = {
|
||||||
type VersionHistory = Record<string, VersionHistoryEntry>;
|
type VersionHistory = Record<string, VersionHistoryEntry>;
|
||||||
|
|
||||||
// Simple in-memory queue for each reportId
|
// Simple in-memory queue for each reportId
|
||||||
const updateQueues = new Map<string, Promise<{
|
const updateQueues = new Map<
|
||||||
id: string;
|
string,
|
||||||
name: string;
|
Promise<{
|
||||||
content: string;
|
id: string;
|
||||||
versionHistory: VersionHistory | null;
|
name: string;
|
||||||
}>>();
|
content: string;
|
||||||
|
versionHistory: VersionHistory | null;
|
||||||
|
}>
|
||||||
|
>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function that performs the actual update logic.
|
* Internal function that performs the actual update logic.
|
||||||
* This is separated so it can be queued.
|
* This is separated so it can be queued.
|
||||||
*/
|
*/
|
||||||
async function performUpdate(
|
async function performUpdate(params: BatchUpdateReportInput): Promise<{
|
||||||
params: BatchUpdateReportInput
|
|
||||||
): Promise<{
|
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
@ -106,7 +107,7 @@ async function performUpdate(
|
||||||
/**
|
/**
|
||||||
* Updates a report with new content, optionally name, and version history in a single operation
|
* Updates a report with new content, optionally name, and version history in a single operation
|
||||||
* This is more efficient than multiple individual updates
|
* This is more efficient than multiple individual updates
|
||||||
*
|
*
|
||||||
* Updates are queued per reportId to ensure they execute in order.
|
* Updates are queued per reportId to ensure they execute in order.
|
||||||
*/
|
*/
|
||||||
export const batchUpdateReport = async (
|
export const batchUpdateReport = async (
|
||||||
|
@ -118,23 +119,25 @@ export const batchUpdateReport = async (
|
||||||
versionHistory: VersionHistory | null;
|
versionHistory: VersionHistory | null;
|
||||||
}> => {
|
}> => {
|
||||||
const { reportId } = params;
|
const { reportId } = params;
|
||||||
|
|
||||||
// Get the current promise for this reportId, or use a resolved promise as the starting point
|
// Get the current promise for this reportId, or use a resolved promise as the starting point
|
||||||
const currentQueue = updateQueues.get(reportId) ?? Promise.resolve({
|
const currentQueue =
|
||||||
id: '',
|
updateQueues.get(reportId) ??
|
||||||
name: '',
|
Promise.resolve({
|
||||||
content: '',
|
id: '',
|
||||||
versionHistory: null
|
name: '',
|
||||||
});
|
content: '',
|
||||||
|
versionHistory: null,
|
||||||
|
});
|
||||||
|
|
||||||
// Chain the new update to run after the current queue completes
|
// Chain the new update to run after the current queue completes
|
||||||
const newQueue = currentQueue
|
const newQueue = currentQueue
|
||||||
.then(() => performUpdate(params))
|
.then(() => performUpdate(params))
|
||||||
.catch(() => performUpdate(params)); // Still try to run even if previous failed
|
.catch(() => performUpdate(params)); // Still try to run even if previous failed
|
||||||
|
|
||||||
// Update the queue for this reportId
|
// Update the queue for this reportId
|
||||||
updateQueues.set(reportId, newQueue);
|
updateQueues.set(reportId, newQueue);
|
||||||
|
|
||||||
// Clean up the queue entry once this update completes
|
// Clean up the queue entry once this update completes
|
||||||
newQueue.finally(() => {
|
newQueue.finally(() => {
|
||||||
// Only remove if this is still the current queue
|
// Only remove if this is still the current queue
|
||||||
|
@ -142,6 +145,6 @@ export const batchUpdateReport = async (
|
||||||
updateQueues.delete(reportId);
|
updateQueues.delete(reportId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return newQueue;
|
return newQueue;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,13 +32,11 @@ describe('DEFAULT_CHART_CONFIG', () => {
|
||||||
category: [],
|
category: [],
|
||||||
size: [],
|
size: [],
|
||||||
tooltip: null,
|
tooltip: null,
|
||||||
colorBy: null,
|
|
||||||
});
|
});
|
||||||
expect(config.pieChartAxis).toEqual({
|
expect(config.pieChartAxis).toEqual({
|
||||||
x: [],
|
x: [],
|
||||||
y: [],
|
y: [],
|
||||||
tooltip: null,
|
tooltip: null,
|
||||||
colorBy: null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify the config is a complete object with all required properties
|
// Verify the config is a complete object with all required properties
|
||||||
|
|
Loading…
Reference in New Issue