Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions apps/dev-playground/config/queries/.appkit-types-cache.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"version": "1",
"queries": {
"apps_list": {
"hash": "e2c65853cf4b332d638bdd30a3aefb69",
"type": "{\n name: \"apps_list\";\n parameters: Record<string, never>;\n result: Array<{\n /** @sqlType STRING */\n id: string;\n /** @sqlType STRING */\n name: string;\n /** @sqlType STRING */\n creator: string;\n /** @sqlType STRING */\n tags: string;\n /** @sqlType DECIMAL(38,6) */\n totalSpend: number;\n /** @sqlType DATE */\n createdAt: string;\n }>;\n }"
},
"cost_recommendations": {
"hash": "730c7d8b5e2726981088b5975157b0da",
"type": "{\n name: \"cost_recommendations\";\n parameters: Record<string, never>;\n result: Array<{\n /** @sqlType INT */\n dummy: number;\n }>;\n }"
},
"example": {
"hash": "aeb02ed3e8a6c77279099406f8709543",
"type": "{\n name: \"example\";\n parameters: Record<string, never>;\n result: Array<{\n /** @sqlType BOOLEAN */\n \"(1 = 1)\": boolean;\n }>;\n }"
},
"spend_data": {
"hash": "caa0430652fe15eff658e48e6dac2446",
"type": "{\n name: \"spend_data\";\n parameters: {\n /** STRING - use sql.string() */\n groupBy: SQLStringMarker;\n /** STRING - use sql.string() */\n aggregationLevel: SQLStringMarker;\n /** DATE - use sql.date() */\n startDate: SQLDateMarker;\n /** DATE - use sql.date() */\n endDate: SQLDateMarker;\n /** STRING - use sql.string() */\n appId: SQLStringMarker;\n /** STRING - use sql.string() */\n creator: SQLStringMarker;\n };\n result: Array<{\n /** @sqlType STRING */\n group_key: string;\n /** @sqlType TIMESTAMP */\n aggregation_period: string;\n /** @sqlType DECIMAL(38,6) */\n cost_usd: number;\n }>;\n }"
},
"spend_summary": {
"hash": "bbe188624c3f5904c3a7593cb32982d5",
"type": "{\n name: \"spend_summary\";\n parameters: {\n /** STRING - use sql.string() */\n aggregationLevel: SQLStringMarker;\n /** DATE - use sql.date() */\n endDate: SQLDateMarker;\n /** DATE - use sql.date() */\n startDate: SQLDateMarker;\n };\n result: Array<{\n /** @sqlType DECIMAL(33,0) */\n total: number;\n /** @sqlType DECIMAL(33,0) */\n average: number;\n /** @sqlType DECIMAL(33,0) */\n forecasted: number;\n }>;\n }"
},
"sql_helpers_test": {
"hash": "1322df4ba9c107e8d23e2a04bae860c5",
"type": "{\n name: \"sql_helpers_test\";\n parameters: {\n /** STRING - use sql.string() */\n stringParam: SQLStringMarker;\n /** NUMERIC - use sql.number() */\n numberParam: SQLNumberMarker;\n /** BOOLEAN - use sql.boolean() */\n booleanParam: SQLBooleanMarker;\n /** DATE - use sql.date() */\n dateParam: SQLDateMarker;\n /** TIMESTAMP - use sql.timestamp() */\n timestampParam: SQLTimestampMarker;\n /** STRING - use sql.string() */\n binaryParam: SQLStringMarker;\n };\n result: Array<{\n /** @sqlType STRING */\n string_value: string;\n /** @sqlType STRING */\n number_value: string;\n /** @sqlType STRING */\n boolean_value: string;\n /** @sqlType STRING */\n date_value: string;\n /** @sqlType STRING */\n timestamp_value: string;\n /** @sqlType BINARY */\n binary_value: string;\n /** @sqlType STRING */\n binary_hex: string;\n /** @sqlType INT */\n binary_length: number;\n }>;\n }"
},
"top_contributors": {
"hash": "2d58759cca2fe31dae06475a23080120",
"type": "{\n name: \"top_contributors\";\n parameters: {\n /** STRING - use sql.string() */\n aggregationLevel: SQLStringMarker;\n /** DATE - use sql.date() */\n startDate: SQLDateMarker;\n /** DATE - use sql.date() */\n endDate: SQLDateMarker;\n };\n result: Array<{\n /** @sqlType STRING */\n app_name: string;\n /** @sqlType DECIMAL(38,6) */\n total_cost_usd: number;\n }>;\n }"
},
"untagged_apps": {
"hash": "5946262b49710b8ab458d1bf950ff8c9",
"type": "{\n name: \"untagged_apps\";\n parameters: {\n /** STRING - use sql.string() */\n aggregationLevel: SQLStringMarker;\n /** DATE - use sql.date() */\n startDate: SQLDateMarker;\n /** DATE - use sql.date() */\n endDate: SQLDateMarker;\n };\n result: Array<{\n /** @sqlType STRING */\n app_name: string;\n /** @sqlType STRING */\n creator: string;\n /** @sqlType DECIMAL(38,6) */\n total_cost_usd: number;\n /** @sqlType DECIMAL(38,10) */\n avg_period_cost_usd: number;\n }>;\n }"
}
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
},
"lint-staged": {
"(*.ts|*.tsx|*.js|*.jsx|*.json|*.md|*.yml|*.yaml|*.css)": [
"pnpm lint:fix && pnpm format"
"biome lint --write",
"biome format --write"
]
},
"devDependencies": {
Expand All @@ -48,6 +49,7 @@
"jsdom": "^27.0.0",
"lint-staged": "^15.5.1",
"plop": "^4.0.4",
"pg": "^8.16.3",
"publint": "^0.3.15",
"tsdown": "^0.15.7",
"tsx": "^4.20.6",
Expand Down
2 changes: 2 additions & 0 deletions packages/app-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@
"@opentelemetry/semantic-conventions": "^1.38.0",
"dotenv": "^16.6.1",
"express": "^4.22.0",
"pg": "^8.16.3",
"shared": "workspace:*",
"vite": "npm:[email protected]",
"ws": "^8.18.3",
"zod-to-ts": "^2.0.0"
},
"devDependencies": {
"@types/express": "^4.17.25",
"@types/pg": "^8.15.6",
"@types/ws": "^8.18.1",
"@vitejs/plugin-react": "^5.1.1"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/app-kit/src/analytics/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class AnalyticsPlugin extends Plugin {

this.SQLClient = new SQLWarehouseConnector({
timeout: config.timeout,
telemetry: this.telemetry,
telemetry: config.telemetry,
});
}

Expand Down
49 changes: 45 additions & 4 deletions packages/app-kit/src/analytics/tests/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,53 @@ import { beforeEach, describe, expect, test, vi } from "vitest";
import { AnalyticsPlugin, analytics } from "../analytics";
import type { IAnalyticsConfig } from "../types";

// Mock CacheManager singleton with actual caching behavior
const { mockCacheStore, mockCacheInstance } = vi.hoisted(() => {
const store = new Map<string, unknown>();

const generateKey = (parts: unknown[], userKey: string): string => {
const { createHash } = require("node:crypto");
const allParts = [userKey, ...parts];
const serialized = JSON.stringify(allParts);
return createHash("sha256").update(serialized).digest("hex");
};

const instance = {
get: vi.fn(),
set: vi.fn(),
delete: vi.fn(),
getOrExecute: vi.fn(
async (key: unknown[], fn: () => Promise<unknown>, userKey: string) => {
const cacheKey = generateKey(key, userKey);
if (store.has(cacheKey)) {
return store.get(cacheKey);
}
const result = await fn();
store.set(cacheKey, result);
return result;
},
),
generateKey: vi.fn((parts: unknown[], userKey: string) =>
generateKey(parts, userKey),
),
};

return { mockCacheStore: store, mockCacheInstance: instance };
});

vi.mock("../../cache", () => ({
CacheManager: {
getInstanceSync: vi.fn(() => mockCacheInstance),
},
}));

describe("Analytics Plugin", () => {
let config: IAnalyticsConfig;

beforeEach(() => {
config = { timeout: 5000 };
setupDatabricksEnv();
mockCacheStore.clear();
});

test("Analytics plugin data should have correct name", () => {
Expand Down Expand Up @@ -180,7 +221,7 @@ describe("Analytics Plugin", () => {
},
{
userDatabricksClient: mockUserClient as any,
userName: "user-token-123",
userId: "user-token-123",
},
);

Expand Down Expand Up @@ -277,7 +318,7 @@ describe("Analytics Plugin", () => {
async () => {
await handler(mockReq1, mockRes1);
},
{ userName: "user-token-1" },
{ userId: "user-token-1" },
);

const mockReq2 = createMockRequest({
Expand All @@ -290,7 +331,7 @@ describe("Analytics Plugin", () => {
async () => {
await handler(mockReq2, mockRes2);
},
{ userName: "user-token-2" },
{ userId: "user-token-2" },
);

const mockReq1Again = createMockRequest({
Expand All @@ -303,7 +344,7 @@ describe("Analytics Plugin", () => {
async () => {
await handler(mockReq1Again, mockRes1Again);
},
{ userName: "user-token-1" },
{ userId: "user-token-1" },
);

expect(executeMock).toHaveBeenCalledTimes(2);
Expand Down
1 change: 0 additions & 1 deletion packages/app-kit/src/analytics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { BasePluginConfig } from "shared";

export interface IAnalyticsConfig extends BasePluginConfig {
timeout?: number;
typePath?: string;
}

export interface IAnalyticsQueryRequest {
Expand Down
11 changes: 11 additions & 0 deletions packages/app-kit/src/cache/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { CacheConfig } from "shared";

/** Default configuration for cache */
export const cacheDefaults: CacheConfig = {
enabled: true,
ttl: 3600, // 1 hour
maxSize: 1000, // 1000 entries
cacheKey: [], // no cache key by default
cleanupProbability: 0.01, // 1% probability of triggering cleanup on each get operation
strictPersistence: false, // if false, use in-memory storage if lakebase is unavailable
};
Loading