@duckcodeailabs/dql-cli 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-BI2YwGNM.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-BJbWzCsK.js"></script>
11
11
  <link rel="modulepreload" crossorigin href="/assets/react-CRB3T2We.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/codemirror-BqWuFwtC.js">
13
13
  <link rel="stylesheet" crossorigin href="/assets/index-BZV40eAE.css">
@@ -28,6 +28,20 @@ export declare function prepareLocalExecution(sql: string, connection: Connectio
28
28
  sql: string;
29
29
  connection: ConnectionConfig;
30
30
  };
31
+ export interface PreparedSemanticSql {
32
+ sql: string;
33
+ semanticRefs: {
34
+ metrics: string[];
35
+ dimensions: string[];
36
+ };
37
+ unresolvedRefs: string[];
38
+ }
39
+ /**
40
+ * Shared resolver for `@metric(name)` / `@dim(name)` refs in raw SQL.
41
+ * Used by notebook SQL execution and Block Studio validation so both paths
42
+ * behave identically. If the SQL has no refs, returns it unchanged.
43
+ */
44
+ export declare function prepareSemanticSql(sql: string, semanticLayer: SemanticLayer | undefined): PreparedSemanticSql;
31
45
  export declare function normalizeProjectConnection(connection: ConnectionConfig, projectRoot: string): ConnectionConfig;
32
46
  export declare function resolveProjectRelativeSqlPaths(sql: string, projectRoot: string, dataDir?: string): string;
33
47
  type BlockStudioDiagnostic = {
@@ -52,14 +66,22 @@ export declare function validateBlockStudioSource(source: string, semanticLayer?
52
66
  };
53
67
  executableSql?: string | null;
54
68
  };
69
+ export interface BlockGitMetadata {
70
+ commitSha: string;
71
+ repo: string | null;
72
+ branch: string | null;
73
+ }
74
+ export declare function readGitMetadata(projectRoot: string): BlockGitMetadata | null;
55
75
  export declare function createBlockArtifacts(projectRoot: string, options: {
56
76
  name: string;
57
77
  domain?: string;
78
+ owner?: string;
58
79
  content?: string;
59
80
  description?: string;
60
81
  tags?: string[];
61
82
  metricRefs?: string[];
62
83
  template?: string;
84
+ gitMetadata?: BlockGitMetadata | null;
63
85
  }): {
64
86
  path: string;
65
87
  content: string;
@@ -1 +1 @@
1
- {"version":3,"file":"local-runtime.d.ts","sourceRoot":"","sources":["../src/local-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local-runtime.d.ts","sourceRoot":"","sources":["../src/local-runtime.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { execSync } from 'node:child_process';
1
2
  import { createServer } from 'node:http';
2
3
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
3
4
  import { dirname, extname, join, normalize, relative, resolve } from 'node:path';
@@ -339,20 +340,37 @@ export async function startLocalServer(opts) {
339
340
  if (req.method === 'POST' && path === '/api/blocks/save-from-cell') {
340
341
  try {
341
342
  const body = await readJSON(req);
342
- const { name, domain, content, description, tags, metricRefs, template, } = body;
343
+ const { name, domain, owner, content, description, tags, metricRefs, template, } = body;
343
344
  if (!name || typeof name !== 'string' || !content || typeof content !== 'string') {
344
345
  res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
345
346
  res.end(serializeJSON({ error: 'name and content are required' }));
346
347
  return;
347
348
  }
349
+ const missing = [];
350
+ if (!owner || !owner.trim())
351
+ missing.push('owner');
352
+ if (!domain || !domain.trim())
353
+ missing.push('domain');
354
+ if (!description || !description.trim())
355
+ missing.push('description');
356
+ if (missing.length > 0) {
357
+ res.writeHead(422, { 'Content-Type': 'application/json; charset=utf-8' });
358
+ res.end(serializeJSON({
359
+ error: `Block is missing required governance fields: ${missing.join(', ')}`,
360
+ missing,
361
+ }));
362
+ return;
363
+ }
348
364
  const created = createBlockArtifacts(projectRoot, {
349
365
  name,
350
366
  domain,
367
+ owner,
351
368
  content,
352
369
  description,
353
370
  tags,
354
371
  metricRefs,
355
372
  template,
373
+ gitMetadata: readGitMetadata(projectRoot),
356
374
  });
357
375
  res.writeHead(201, { 'Content-Type': 'application/json; charset=utf-8' });
358
376
  res.end(serializeJSON(created));
@@ -1279,9 +1297,21 @@ export async function startLocalServer(opts) {
1279
1297
  res.end(serializeJSON({ columns: [], rows: [], error: 'Missing SQL in request body.' }));
1280
1298
  return;
1281
1299
  }
1282
- const prepared = prepareLocalExecution(typeof body.sql === 'string' ? body.sql : '', isConnectionConfig(body.connection) ? body.connection : connection, projectRoot, projectConfig);
1300
+ const semantic = prepareSemanticSql(body.sql, semanticLayer);
1301
+ if (semantic.unresolvedRefs.length > 0) {
1302
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
1303
+ res.end(serializeJSON({
1304
+ columns: [],
1305
+ rows: [],
1306
+ error: `Unknown semantic reference${semantic.unresolvedRefs.length > 1 ? 's' : ''}: ${semantic.unresolvedRefs.join(', ')}`,
1307
+ code: 'semantic_ref',
1308
+ unresolvedRefs: semantic.unresolvedRefs,
1309
+ }));
1310
+ return;
1311
+ }
1312
+ const prepared = prepareLocalExecution(semantic.sql, isConnectionConfig(body.connection) ? body.connection : connection, projectRoot, projectConfig);
1283
1313
  const result = await executor.executeQuery(prepared.sql, Array.isArray(body.sqlParams) ? body.sqlParams : [], body.variables && typeof body.variables === 'object' ? body.variables : {}, prepared.connection);
1284
- const payload = serializeJSON(normalizeQueryResult(result));
1314
+ const payload = serializeJSON(normalizeQueryResult(result, semantic.semanticRefs));
1285
1315
  res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
1286
1316
  res.end(payload);
1287
1317
  }
@@ -1848,9 +1878,10 @@ export function formatLocalQueryRuntimeError(connection, error) {
1848
1878
  * Connector returns columns as ColumnMeta[] ({name,type,driverType}).
1849
1879
  * The notebook SPA expects columns as string[] (just names).
1850
1880
  */
1851
- function normalizeQueryResult(result) {
1881
+ function normalizeQueryResult(result, semanticRefs) {
1852
1882
  const rawCols = Array.isArray(result?.columns) ? result.columns : [];
1853
1883
  const columns = rawCols.map((c) => typeof c === 'string' ? c : typeof c?.name === 'string' ? c.name : String(c));
1884
+ const hasRefs = semanticRefs && (semanticRefs.metrics.length > 0 || semanticRefs.dimensions.length > 0);
1854
1885
  return {
1855
1886
  columns,
1856
1887
  rows: Array.isArray(result?.rows) ? result.rows : [],
@@ -1860,6 +1891,7 @@ function normalizeQueryResult(result) {
1860
1891
  : typeof result?.executionTime === 'number'
1861
1892
  ? result.executionTime
1862
1893
  : 0,
1894
+ ...(hasRefs ? { semanticRefs } : {}),
1863
1895
  };
1864
1896
  }
1865
1897
  export function serializeJSON(value) {
@@ -1941,6 +1973,25 @@ export function prepareLocalExecution(sql, connection, projectRoot, projectConfi
1941
1973
  connection: normalizedConnection,
1942
1974
  };
1943
1975
  }
1976
+ /**
1977
+ * Shared resolver for `@metric(name)` / `@dim(name)` refs in raw SQL.
1978
+ * Used by notebook SQL execution and Block Studio validation so both paths
1979
+ * behave identically. If the SQL has no refs, returns it unchanged.
1980
+ */
1981
+ export function prepareSemanticSql(sql, semanticLayer) {
1982
+ if (!hasSemanticRefs(sql)) {
1983
+ return { sql, semanticRefs: { metrics: [], dimensions: [] }, unresolvedRefs: [] };
1984
+ }
1985
+ const resolution = resolveSemanticRefs(sql, semanticLayer);
1986
+ return {
1987
+ sql: resolution.resolvedSql,
1988
+ semanticRefs: {
1989
+ metrics: resolution.resolvedMetrics,
1990
+ dimensions: resolution.resolvedDimensions,
1991
+ },
1992
+ unresolvedRefs: resolution.unresolvedRefs,
1993
+ };
1994
+ }
1944
1995
  export function normalizeProjectConnection(connection, projectRoot) {
1945
1996
  const normalized = { ...connection };
1946
1997
  if ((normalized.driver === 'file' || normalized.driver === 'duckdb') && normalized.filepath && normalized.filepath !== ':memory:' && !isAbsoluteLikePath(normalized.filepath)) {
@@ -2720,6 +2771,26 @@ function canonicalizeSafe(source) {
2720
2771
  return source;
2721
2772
  }
2722
2773
  }
2774
+ export function readGitMetadata(projectRoot) {
2775
+ const run = (cmd) => execSync(cmd, { cwd: projectRoot, encoding: 'utf-8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
2776
+ try {
2777
+ const commitSha = run('git rev-parse HEAD');
2778
+ let repo = null;
2779
+ let branch = null;
2780
+ try {
2781
+ repo = run('git config --get remote.origin.url') || null;
2782
+ }
2783
+ catch { /* no remote */ }
2784
+ try {
2785
+ branch = run('git rev-parse --abbrev-ref HEAD') || null;
2786
+ }
2787
+ catch { /* detached */ }
2788
+ return { commitSha, repo, branch };
2789
+ }
2790
+ catch {
2791
+ return null;
2792
+ }
2793
+ }
2723
2794
  export function createBlockArtifacts(projectRoot, options) {
2724
2795
  const slug = options.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'block';
2725
2796
  const safeDomain = (options.domain ?? '')
@@ -2736,23 +2807,27 @@ export function createBlockArtifacts(projectRoot, options) {
2736
2807
  const templateContent = options.template
2737
2808
  ? listBlockTemplates().find((template) => template.id === options.template)?.content
2738
2809
  : undefined;
2810
+ const relativePath = safeDomain ? `blocks/${safeDomain}/${slug}.dql` : `blocks/${slug}.dql`;
2739
2811
  const fileContent = canonicalizeSafe(normalizeBlockStudioContent({
2740
2812
  name: options.name,
2741
2813
  domain: safeDomain || 'uncategorized',
2814
+ owner: options.owner,
2742
2815
  description: options.description,
2743
2816
  tags: options.tags,
2744
2817
  content: options.content?.trim() || templateContent,
2745
2818
  }));
2746
2819
  writeFileSync(blockPath, fileContent, 'utf-8');
2747
- const relativePath = safeDomain ? `blocks/${safeDomain}/${slug}.dql` : `blocks/${slug}.dql`;
2748
2820
  const companionPath = writeBlockCompanionFile(projectRoot, {
2749
2821
  slug,
2750
2822
  name: options.name,
2751
2823
  domain: safeDomain || 'uncategorized',
2824
+ owner: options.owner,
2752
2825
  description: options.description,
2753
2826
  tags: options.tags,
2754
2827
  provider: 'dql',
2755
2828
  content: fileContent,
2829
+ gitMetadata: options.gitMetadata,
2830
+ gitPath: relativePath,
2756
2831
  });
2757
2832
  return {
2758
2833
  path: relativePath,
@@ -2928,6 +3003,17 @@ function writeBlockCompanionFile(projectRoot, options) {
2928
3003
  for (const table of options.lineage)
2929
3004
  lines.push(` - ${yamlScalar(table)}`);
2930
3005
  }
3006
+ if (options.gitMetadata || options.gitPath) {
3007
+ lines.push('git:');
3008
+ if (options.gitMetadata?.commitSha)
3009
+ lines.push(` commitSha: ${yamlScalar(options.gitMetadata.commitSha)}`);
3010
+ if (options.gitMetadata?.repo)
3011
+ lines.push(` repo: ${yamlScalar(options.gitMetadata.repo)}`);
3012
+ if (options.gitMetadata?.branch)
3013
+ lines.push(` branch: ${yamlScalar(options.gitMetadata.branch)}`);
3014
+ if (options.gitPath)
3015
+ lines.push(` path: ${yamlScalar(options.gitPath)}`);
3016
+ }
2931
3017
  lines.push('reviewStatus: draft');
2932
3018
  writeFileSync(companionPath, lines.join('\n') + '\n', 'utf-8');
2933
3019
  return relative(projectRoot, companionPath).replaceAll('\\', '/');
@@ -2968,6 +3054,7 @@ function normalizeBlockStudioContent(options) {
2968
3054
  return buildBlankBlockContent({
2969
3055
  name: options.name,
2970
3056
  domain: options.domain,
3057
+ owner: options.owner,
2971
3058
  description: options.description,
2972
3059
  tags: options.tags,
2973
3060
  sql: content || 'SELECT 1 AS value',
@@ -2979,7 +3066,7 @@ function buildBlankBlockContent(options) {
2979
3066
  ` domain = "${escapeDqlString(options.domain)}"`,
2980
3067
  ' type = "custom"',
2981
3068
  ` description = "${escapeDqlString(options.description?.trim() || options.name)}"`,
2982
- ' owner = ""',
3069
+ ` owner = "${escapeDqlString(options.owner?.trim() ?? '')}"`,
2983
3070
  ];
2984
3071
  lines.push(` tags = [${(options.tags ?? []).map((tag) => `"${escapeDqlString(tag)}"`).join(', ')}]`);
2985
3072
  lines.push('');