@malloy-publisher/server 0.0.235 → 0.0.237
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.
- package/dist/app/api-doc.yaml +83 -27
- package/dist/app/assets/{EnvironmentPage-BsAnavYN.js → EnvironmentPage-DaP6CpgK.js} +1 -1
- package/dist/app/assets/{HomePage-CADE138j.js → HomePage-C9yNw3iu.js} +1 -1
- package/dist/app/assets/{LightMode-Cfh7KzN8.js → LightMode-Be4-G-dX.js} +1 -1
- package/dist/app/assets/{MainPage-CO3pRlnV.js → MainPage-J_rU2SgI.js} +2 -2
- package/dist/app/assets/{MaterializationsPage-p9YjkRXZ.js → MaterializationsPage-DHgPI4MO.js} +1 -1
- package/dist/app/assets/ModelPage-BzXfjTu5.js +1 -0
- package/dist/app/assets/{PackagePage-e4kN75YR.js → PackagePage-ByoSTLJ4.js} +1 -1
- package/dist/app/assets/RouteError-CrSeKN2r.js +1 -0
- package/dist/app/assets/{ThemeEditorPage-CciagFTq.js → ThemeEditorPage-Btxnmhtk.js} +1 -1
- package/dist/app/assets/{WorkbookPage-DNWmkCXa.js → WorkbookPage-D6JLPnWO.js} +1 -1
- package/dist/app/assets/{core-Rj_4rRnA.es-BZyvITuO.js → core-BSRgt1mG.es-Bc_D2Lq4.js} +1 -1
- package/dist/app/assets/{index-CH2AcDzc.js → index-BRijWj6K.js} +15 -15
- package/dist/app/assets/{index-DQa463gC.js → index-BX4D94xw.js} +1 -1
- package/dist/app/assets/{index-VBbcc8s6.js → index-Cvy0xtb7.js} +1 -1
- package/dist/app/assets/{index-DQpV7MyA.js → index-DMAhIJNC.js} +1 -1
- package/dist/app/index.html +1 -1
- package/dist/package_load_worker.mjs +59 -20
- package/dist/server.mjs +1342 -616
- package/package.json +8 -2
- package/.eslintrc.json +0 -44
- package/.prettierignore +0 -1
- package/.prettierrc +0 -4
- package/build.ts +0 -97
- package/dist/app/assets/ModelPage-C1OSTv-x.js +0 -1
- package/dist/app/assets/RouteError-CzbfOkng.js +0 -1
- package/eslint.config.mjs +0 -76
- package/k6-tests/README.md +0 -144
- package/k6-tests/bun.lock +0 -797
- package/k6-tests/load-test/load-test-crud-connections.ts +0 -263
- package/k6-tests/load-test/load-test-crud-packages.ts +0 -461
- package/k6-tests/load-test/load-test-crud-projects.ts +0 -160
- package/k6-tests/load-test/load-test-crud.ts +0 -142
- package/k6-tests/load-test/load-test.ts +0 -784
- package/k6-tests/package.json +0 -27
- package/k6-tests/scripts/run-with-otel.sh +0 -50
- package/k6-tests/smoke-test/smoke-test.ts +0 -158
- package/k6-tests/tsconfig.json +0 -29
- package/k6-tests/utils/client_factory.ts +0 -128
- package/k6-tests/utils/common.ts +0 -489
- package/k6-tests/utils/logger.ts +0 -62
- package/k6-tests/utils/types.d.ts +0 -35
- package/malloy_mcp.dxt +0 -0
- package/publisher.config.example.bigquery.json +0 -33
- package/publisher.config.example.duckdb.json +0 -23
- package/publisher.config.json +0 -23
- package/scripts/bake-duckdb-extensions.js +0 -110
- package/src/config.spec.ts +0 -1535
- package/src/config.theme.spec.ts +0 -178
- package/src/config.ts +0 -1142
- package/src/constants.ts +0 -105
- package/src/controller/compile.controller.ts +0 -40
- package/src/controller/connection.controller.spec.ts +0 -849
- package/src/controller/connection.controller.ts +0 -901
- package/src/controller/database.controller.ts +0 -24
- package/src/controller/materialization.controller.spec.ts +0 -293
- package/src/controller/materialization.controller.ts +0 -319
- package/src/controller/model.controller.ts +0 -164
- package/src/controller/package.controller.spec.ts +0 -273
- package/src/controller/package.controller.ts +0 -306
- package/src/controller/query.controller.ts +0 -152
- package/src/controller/theme.controller.ts +0 -83
- package/src/controller/watch-mode.controller.ts +0 -243
- package/src/data_styles.ts +0 -71
- package/src/default-publisher.config.json +0 -23
- package/src/ducklake_version.spec.ts +0 -163
- package/src/ducklake_version.ts +0 -153
- package/src/errors.spec.ts +0 -119
- package/src/errors.ts +0 -237
- package/src/filter_deprecation.spec.ts +0 -64
- package/src/filter_deprecation.ts +0 -42
- package/src/health.spec.ts +0 -123
- package/src/health.ts +0 -233
- package/src/heap_check.spec.ts +0 -144
- package/src/heap_check.ts +0 -144
- package/src/instrumentation.ts +0 -214
- package/src/json_utils.spec.ts +0 -51
- package/src/json_utils.ts +0 -33
- package/src/logger.spec.ts +0 -210
- package/src/logger.ts +0 -251
- package/src/malloy_pin_prereqs.spec.ts +0 -25
- package/src/materialization_metrics.spec.ts +0 -169
- package/src/materialization_metrics.ts +0 -346
- package/src/mcp/error_messages.spec.ts +0 -35
- package/src/mcp/error_messages.ts +0 -183
- package/src/mcp/handler_utils.spec.ts +0 -108
- package/src/mcp/handler_utils.ts +0 -251
- package/src/mcp/mcp_constants.ts +0 -6
- package/src/mcp/query_envelope.spec.ts +0 -229
- package/src/mcp/query_envelope.ts +0 -240
- package/src/mcp/server.protocol.spec.ts +0 -250
- package/src/mcp/server.ts +0 -87
- package/src/mcp/skills/build_skills_bundle.spec.ts +0 -51
- package/src/mcp/skills/build_skills_bundle.ts +0 -176
- package/src/mcp/skills/skills_bundle.json +0 -1
- package/src/mcp/skills/skills_bundle.spec.ts +0 -171
- package/src/mcp/tool_response.spec.ts +0 -108
- package/src/mcp/tool_response.ts +0 -138
- package/src/mcp/tools/compile_tool.spec.ts +0 -315
- package/src/mcp/tools/compile_tool.ts +0 -208
- package/src/mcp/tools/docs_search/build_docs_index.ts +0 -132
- package/src/mcp/tools/docs_search/malloy_docs_index.json +0 -1
- package/src/mcp/tools/docs_search_tool.spec.ts +0 -32
- package/src/mcp/tools/docs_search_tool.ts +0 -128
- package/src/mcp/tools/embedding_index.spec.ts +0 -1236
- package/src/mcp/tools/embedding_index.ts +0 -808
- package/src/mcp/tools/execute_query_tool.spec.ts +0 -294
- package/src/mcp/tools/execute_query_tool.ts +0 -316
- package/src/mcp/tools/get_context_eval.ts +0 -275
- package/src/mcp/tools/get_context_tool.spec.ts +0 -592
- package/src/mcp/tools/get_context_tool.ts +0 -585
- package/src/mcp/tools/reload_package_tool.spec.ts +0 -232
- package/src/mcp/tools/reload_package_tool.ts +0 -132
- package/src/mcp_config.spec.ts +0 -919
- package/src/mcp_config.ts +0 -425
- package/src/oom_guards.integration.spec.ts +0 -269
- package/src/package_load/package_load_pool.spec.ts +0 -252
- package/src/package_load/package_load_pool.ts +0 -931
- package/src/package_load/package_load_worker.ts +0 -1034
- package/src/package_load/protocol.ts +0 -364
- package/src/package_load/rpc_wait_accountant.spec.ts +0 -109
- package/src/package_load/rpc_wait_accountant.ts +0 -76
- package/src/package_load_metrics.spec.ts +0 -114
- package/src/package_load_metrics.ts +0 -127
- package/src/path_safety.spec.ts +0 -158
- package/src/path_safety.ts +0 -146
- package/src/pg_helpers.spec.ts +0 -223
- package/src/pg_helpers.ts +0 -52
- package/src/query_cap_metrics.spec.ts +0 -89
- package/src/query_cap_metrics.ts +0 -116
- package/src/query_concurrency.spec.ts +0 -247
- package/src/query_concurrency.ts +0 -237
- package/src/query_metadata_metrics.ts +0 -49
- package/src/query_param_utils.ts +0 -29
- package/src/query_timeout.spec.ts +0 -224
- package/src/query_timeout.ts +0 -179
- package/src/runtime/publisher.js +0 -328
- package/src/server-old.ts +0 -988
- package/src/server.ts +0 -2059
- package/src/service/annotations.spec.ts +0 -118
- package/src/service/annotations.ts +0 -91
- package/src/service/authorize.spec.ts +0 -154
- package/src/service/authorize.ts +0 -498
- package/src/service/authorize_integration.spec.ts +0 -2041
- package/src/service/build_plan.spec.ts +0 -685
- package/src/service/build_plan.ts +0 -797
- package/src/service/compile_authorize.spec.ts +0 -85
- package/src/service/compile_fragment_techniques.spec.ts +0 -156
- package/src/service/connection.spec.ts +0 -2360
- package/src/service/connection.ts +0 -2187
- package/src/service/connection_config.spec.ts +0 -734
- package/src/service/connection_config.ts +0 -899
- package/src/service/connection_federation.spec.ts +0 -184
- package/src/service/connection_fingerprint.spec.ts +0 -102
- package/src/service/connection_service.spec.ts +0 -711
- package/src/service/connection_service.ts +0 -291
- package/src/service/cron_evaluator.spec.ts +0 -79
- package/src/service/cron_evaluator.ts +0 -105
- package/src/service/db_utils.spec.ts +0 -1085
- package/src/service/db_utils.ts +0 -1502
- package/src/service/duckdb_instance_isolation.spec.ts +0 -137
- package/src/service/ducklake_lazy_attach.spec.ts +0 -110
- package/src/service/embedding_provider.spec.ts +0 -329
- package/src/service/embedding_provider.ts +0 -236
- package/src/service/environment.ts +0 -2191
- package/src/service/environment_admission.spec.ts +0 -344
- package/src/service/environment_compile.spec.ts +0 -197
- package/src/service/environment_store.spec.ts +0 -2274
- package/src/service/environment_store.ts +0 -2434
- package/src/service/environment_store_anchoring.spec.ts +0 -107
- package/src/service/environment_store_clone.spec.ts +0 -350
- package/src/service/explore_visibility.spec.ts +0 -434
- package/src/service/exports_probe.spec.ts +0 -107
- package/src/service/extension_fetch_policy.spec.ts +0 -256
- package/src/service/filter.spec.ts +0 -458
- package/src/service/filter.ts +0 -341
- package/src/service/filter_bypass.spec.ts +0 -418
- package/src/service/filter_integration.spec.ts +0 -1004
- package/src/service/freshness.spec.ts +0 -183
- package/src/service/freshness.ts +0 -112
- package/src/service/gcs_s3_utils.ts +0 -427
- package/src/service/given.ts +0 -105
- package/src/service/givens_integration.spec.ts +0 -219
- package/src/service/manifest_loader.spec.ts +0 -189
- package/src/service/manifest_loader.ts +0 -156
- package/src/service/materialization_build_session.spec.ts +0 -435
- package/src/service/materialization_build_session.ts +0 -681
- package/src/service/materialization_config_validation.spec.ts +0 -99
- package/src/service/materialization_config_validation.ts +0 -120
- package/src/service/materialization_eligibility.spec.ts +0 -158
- package/src/service/materialization_eligibility.ts +0 -305
- package/src/service/materialization_schedule_surface.spec.ts +0 -256
- package/src/service/materialization_scheduler.spec.ts +0 -289
- package/src/service/materialization_scheduler.ts +0 -304
- package/src/service/materialization_serve_transform.spec.ts +0 -1003
- package/src/service/materialization_serve_transform.ts +0 -779
- package/src/service/materialization_service.spec.ts +0 -2373
- package/src/service/materialization_service.ts +0 -2342
- package/src/service/materialization_test_fixtures.ts +0 -249
- package/src/service/model.spec.ts +0 -1157
- package/src/service/model.ts +0 -3370
- package/src/service/model_limits.spec.ts +0 -209
- package/src/service/model_limits.ts +0 -131
- package/src/service/model_storage_serve.spec.ts +0 -193
- package/src/service/model_storage_serve_joins.spec.ts +0 -193
- package/src/service/package.spec.ts +0 -612
- package/src/service/package.ts +0 -1799
- package/src/service/package_manifest.spec.ts +0 -230
- package/src/service/package_manifest.ts +0 -241
- package/src/service/package_memory_governor.spec.ts +0 -173
- package/src/service/package_memory_governor.ts +0 -233
- package/src/service/package_quote_bound_tables.spec.ts +0 -171
- package/src/service/package_race.spec.ts +0 -208
- package/src/service/package_reload_safety.spec.ts +0 -193
- package/src/service/package_rollback.spec.ts +0 -190
- package/src/service/package_worker_path.spec.ts +0 -645
- package/src/service/path_injection.spec.ts +0 -39
- package/src/service/persist_annotation_validation.spec.ts +0 -89
- package/src/service/persist_annotation_validation.ts +0 -59
- package/src/service/persistence_policy.spec.ts +0 -374
- package/src/service/proxy.spec.ts +0 -414
- package/src/service/proxy.ts +0 -248
- package/src/service/query_boundary.spec.ts +0 -470
- package/src/service/query_metadata.spec.ts +0 -408
- package/src/service/query_metadata.ts +0 -492
- package/src/service/query_metadata_identity.spec.ts +0 -149
- package/src/service/query_text.spec.ts +0 -79
- package/src/service/query_text.ts +0 -43
- package/src/service/quoting.spec.ts +0 -135
- package/src/service/quoting.ts +0 -78
- package/src/service/resolve_environment.ts +0 -15
- package/src/service/restricted_mode.spec.ts +0 -299
- package/src/service/source_extraction.ts +0 -225
- package/src/service/theme_store.ts +0 -199
- package/src/storage/DatabaseInterface.ts +0 -198
- package/src/storage/StorageManager.ts +0 -113
- package/src/storage/duckdb/ConnectionRepository.ts +0 -143
- package/src/storage/duckdb/DuckDBConnection.ts +0 -123
- package/src/storage/duckdb/DuckDBRepository.ts +0 -208
- package/src/storage/duckdb/EnvironmentRepository.ts +0 -148
- package/src/storage/duckdb/MaterializationRepository.spec.ts +0 -191
- package/src/storage/duckdb/MaterializationRepository.ts +0 -336
- package/src/storage/duckdb/PackageRepository.ts +0 -135
- package/src/storage/duckdb/schema.ts +0 -229
- package/src/stream_helpers.spec.ts +0 -280
- package/src/stream_helpers.ts +0 -162
- package/src/telemetry.ts +0 -20
- package/src/test_helpers/metrics_harness.ts +0 -166
- package/src/theme_key_parity.spec.ts +0 -57
- package/src/utils.ts +0 -29
- package/tests/fixtures/authorize-compile/model.malloy +0 -9
- package/tests/fixtures/authorize-compile/publisher.json +0 -4
- package/tests/fixtures/html-pages-nopublic/model.malloy +0 -1
- package/tests/fixtures/html-pages-nopublic/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/data.csv +0 -3
- package/tests/fixtures/html-pages-test/public/assets/app.css +0 -3
- package/tests/fixtures/html-pages-test/public/barehtml.html +0 -4
- package/tests/fixtures/html-pages-test/public/bodymeta.html +0 -8
- package/tests/fixtures/html-pages-test/public/data.json +0 -1
- package/tests/fixtures/html-pages-test/public/fitcomment.html +0 -11
- package/tests/fixtures/html-pages-test/public/index.html +0 -9
- package/tests/fixtures/html-pages-test/public/nohead.html +0 -8
- package/tests/fixtures/html-pages-test/public/notfit.html +0 -13
- package/tests/fixtures/html-pages-test/public/slides.html +0 -12
- package/tests/fixtures/html-pages-test/public/sub/page2.html +0 -9
- package/tests/fixtures/html-pages-test/public/unterminated.html +0 -10
- package/tests/fixtures/html-pages-test/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/report.malloy +0 -1
- package/tests/fixtures/persist-multi-level/data/orders.csv +0 -5
- package/tests/fixtures/persist-multi-level/multi_level.malloy +0 -18
- package/tests/fixtures/persist-multi-level/publisher.json +0 -5
- package/tests/fixtures/persist-schedule-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-test/persist_schedule_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-test/publisher.json +0 -7
- package/tests/fixtures/persist-schedule-warn-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-warn-test/persist_warn_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-warn-test/publisher.json +0 -6
- package/tests/fixtures/persist-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-test/persist_test.malloy +0 -11
- package/tests/fixtures/persist-test/publisher.json +0 -5
- package/tests/fixtures/publisher.config.json +0 -15
- package/tests/fixtures/query-givens/data/orders.csv +0 -7
- package/tests/fixtures/query-givens/model.malloy +0 -34
- package/tests/fixtures/query-givens/publisher.json +0 -5
- package/tests/fixtures/xlsx/database.xlsx +0 -0
- package/tests/harness/mcp_test_setup.ts +0 -332
- package/tests/harness/rest_e2e.ts +0 -68
- package/tests/integration/authorize/compile_authorize_http.integration.spec.ts +0 -92
- package/tests/integration/concurrent_package/concurrent_package.integration.spec.ts +0 -280
- package/tests/integration/duckdb_storage/duckdb_storage.integration.spec.ts +0 -138
- package/tests/integration/first_boot/readiness_line.integration.spec.ts +0 -177
- package/tests/integration/html_pages/html_pages.integration.spec.ts +0 -440
- package/tests/integration/legacy_routes/legacy_routes.integration.spec.ts +0 -259
- package/tests/integration/materialization/environment_list.integration.spec.ts +0 -133
- package/tests/integration/materialization/freshness_gate.integration.spec.ts +0 -292
- package/tests/integration/materialization/manifest_binding.integration.spec.ts +0 -430
- package/tests/integration/materialization/materialization_lifecycle.integration.spec.ts +0 -441
- package/tests/integration/materialization/orchestrated_rebind.integration.spec.ts +0 -150
- package/tests/integration/materialization/reference_manifest.integration.spec.ts +0 -251
- package/tests/integration/materialization/schedule_edit.integration.spec.ts +0 -126
- package/tests/integration/materialization/scheduler.integration.spec.ts +0 -200
- package/tests/integration/materialization/scheduler_recovery.integration.spec.ts +0 -172
- package/tests/integration/materialization/scheduler_transitions.integration.spec.ts +0 -256
- package/tests/integration/materialization/scheduler_wiring.integration.spec.ts +0 -143
- package/tests/integration/mcp/mcp_execute_query_tool.integration.spec.ts +0 -438
- package/tests/integration/mcp/mcp_get_context_semantic.integration.spec.ts +0 -235
- package/tests/integration/mcp/mcp_transport.integration.spec.ts +0 -98
- package/tests/integration/query_givens/query_givens.integration.spec.ts +0 -146
- package/tests/integration/query_givens/query_givens_authorize.integration.spec.ts +0 -121
- package/tests/integration/sdk_givens/sdk_givens.integration.spec.ts +0 -110
- package/tests/integration/watch-mode/watch_mode.integration.spec.ts +0 -421
- package/tests/unit/controller/theme.controller.spec.ts +0 -141
- package/tests/unit/duckdb/attached_databases.test.ts +0 -1243
- package/tests/unit/duckdb/duckdb_connection.test.ts +0 -181
- package/tests/unit/duckdb/legacy_schema_migration.test.ts +0 -197
- package/tests/unit/duckdb/repositories.test.ts +0 -208
- package/tests/unit/ducklake/ducklake.test.ts +0 -952
- package/tests/unit/service/theme_store.spec.ts +0 -139
- package/tsconfig.json +0 -32
|
@@ -1,612 +0,0 @@
|
|
|
1
|
-
import { DuckDBConnection } from "@malloydata/db-duckdb";
|
|
2
|
-
import "@malloydata/db-duckdb/native";
|
|
3
|
-
import { MalloyConfig } from "@malloydata/malloy";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
5
|
-
import { Stats } from "fs";
|
|
6
|
-
import fs from "fs/promises";
|
|
7
|
-
import { join, resolve } from "path";
|
|
8
|
-
import sinon from "sinon";
|
|
9
|
-
import { PackageNotFoundError } from "../errors";
|
|
10
|
-
import { Model } from "./model";
|
|
11
|
-
import { Package } from "./package";
|
|
12
|
-
|
|
13
|
-
// Minimal partial types for mocking
|
|
14
|
-
type PartialModel = Pick<Model, "getPath">;
|
|
15
|
-
|
|
16
|
-
describe("service/package", () => {
|
|
17
|
-
const testPackageDirectory = resolve("testPackage");
|
|
18
|
-
|
|
19
|
-
beforeEach(async () => {
|
|
20
|
-
await fs.mkdir(testPackageDirectory, { recursive: true });
|
|
21
|
-
await fs.writeFile(join(testPackageDirectory, "model1.model"), "");
|
|
22
|
-
// Create a simple parquet file with schema "name: string, value: int"
|
|
23
|
-
const parquetBuffer = Buffer.from("Name,Value\nJohn,10\nJane,20\nJim,30");
|
|
24
|
-
|
|
25
|
-
await fs.writeFile(
|
|
26
|
-
join(testPackageDirectory, "database.csv"),
|
|
27
|
-
parquetBuffer,
|
|
28
|
-
);
|
|
29
|
-
const publisherContent = JSON.stringify({ description: "Test package" });
|
|
30
|
-
await fs.writeFile(
|
|
31
|
-
join(testPackageDirectory, "publisher.json"),
|
|
32
|
-
publisherContent,
|
|
33
|
-
);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
afterEach(async () => {
|
|
37
|
-
sinon.restore();
|
|
38
|
-
// On Windows, DuckDB connections may still have file handles open,
|
|
39
|
-
// causing EBUSY errors. Retry deletion with exponential backoff.
|
|
40
|
-
const maxRetries = 3;
|
|
41
|
-
const delay = 50; // Start with 50ms
|
|
42
|
-
let lastError: unknown;
|
|
43
|
-
|
|
44
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
45
|
-
try {
|
|
46
|
-
await fs.rm(testPackageDirectory, { recursive: true, force: true });
|
|
47
|
-
return; // Success, exit retry loop
|
|
48
|
-
} catch (error) {
|
|
49
|
-
lastError = error;
|
|
50
|
-
const errnoError = error as NodeJS.ErrnoException;
|
|
51
|
-
// Only retry on EBUSY errors (Windows file handle still open)
|
|
52
|
-
if (errnoError.code !== "EBUSY") {
|
|
53
|
-
throw error; // Non-EBUSY errors should be thrown immediately
|
|
54
|
-
}
|
|
55
|
-
// Exponential backoff: 50ms, 100ms, 200ms, 400ms, 800ms
|
|
56
|
-
if (attempt < maxRetries - 1) {
|
|
57
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// If we've exhausted retries, ignore EBUSY errors as they don't affect test results
|
|
62
|
-
// and the files will be cleaned up eventually
|
|
63
|
-
if ((lastError as NodeJS.ErrnoException).code !== "EBUSY") {
|
|
64
|
-
throw lastError;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("should create a package instance", async () => {
|
|
69
|
-
// Using 'as any' for simplified mock Map value in test
|
|
70
|
-
const pkg = new Package(
|
|
71
|
-
"testProject",
|
|
72
|
-
"testPackage",
|
|
73
|
-
testPackageDirectory,
|
|
74
|
-
{ name: "testPackage", description: "Test package" },
|
|
75
|
-
[],
|
|
76
|
-
new Map([
|
|
77
|
-
[
|
|
78
|
-
"model1.malloy",
|
|
79
|
-
{
|
|
80
|
-
getPath: () => "model1.malloy",
|
|
81
|
-
setDiscoveryCuration: () => {},
|
|
82
|
-
setQueryBoundary: () => {},
|
|
83
|
-
} as unknown as Model,
|
|
84
|
-
],
|
|
85
|
-
[
|
|
86
|
-
"model2.malloynb",
|
|
87
|
-
{
|
|
88
|
-
getPath: () => "model2.malloynb",
|
|
89
|
-
setDiscoveryCuration: () => {},
|
|
90
|
-
setQueryBoundary: () => {},
|
|
91
|
-
} as unknown as Model,
|
|
92
|
-
],
|
|
93
|
-
]),
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
expect(pkg).toBeInstanceOf(Package);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe("per-package sandbox extension pinning", () => {
|
|
100
|
-
const originalPolicy = process.env.EXTENSION_FETCH_POLICY;
|
|
101
|
-
afterEach(() => {
|
|
102
|
-
if (originalPolicy === undefined) {
|
|
103
|
-
delete process.env.EXTENSION_FETCH_POLICY;
|
|
104
|
-
} else {
|
|
105
|
-
process.env.EXTENSION_FETCH_POLICY = originalPolicy;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it(
|
|
110
|
-
"pins autoinstall off on the :memory: sandbox under local-only",
|
|
111
|
-
async () => {
|
|
112
|
-
// Regression guard for the sandbox bypass: the per-package sandbox
|
|
113
|
-
// has no attached databases, so the environment attach paths never
|
|
114
|
-
// touch it. Under local-only its session must still be pinned
|
|
115
|
-
// against DuckDB's implicit auto-install, or a sandbox query
|
|
116
|
-
// referencing an unbaked extension could silently fetch from the
|
|
117
|
-
// CDN. Uses a spy (not a stub) so real DuckDB runs the pragma.
|
|
118
|
-
process.env.EXTENSION_FETCH_POLICY = "local-only";
|
|
119
|
-
const spy = sinon.spy(DuckDBConnection.prototype, "runSQL");
|
|
120
|
-
await Package.create(
|
|
121
|
-
"testProject",
|
|
122
|
-
"testPackage",
|
|
123
|
-
testPackageDirectory,
|
|
124
|
-
new Map(),
|
|
125
|
-
);
|
|
126
|
-
const issued = spy.getCalls().map((c) => String(c.args[0]));
|
|
127
|
-
expect(
|
|
128
|
-
issued.some((s) =>
|
|
129
|
-
/autoinstall_known_extensions\s*=\s*false/i.test(s),
|
|
130
|
-
),
|
|
131
|
-
).toBe(true);
|
|
132
|
-
},
|
|
133
|
-
{ timeout: 30000 },
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe("instance methods", () => {
|
|
138
|
-
describe("create", () => {
|
|
139
|
-
it("should throw PackageNotFoundError if the package manifest does not exist", async () => {
|
|
140
|
-
await fs.rm(join(testPackageDirectory, "publisher.json"));
|
|
141
|
-
sinon.stub(fs, "stat").rejects(new Error("File not found"));
|
|
142
|
-
|
|
143
|
-
await expect(
|
|
144
|
-
Package.create(
|
|
145
|
-
"testProject",
|
|
146
|
-
"testPackage",
|
|
147
|
-
testPackageDirectory,
|
|
148
|
-
new Map(),
|
|
149
|
-
),
|
|
150
|
-
).rejects.toBeInstanceOf(PackageNotFoundError);
|
|
151
|
-
});
|
|
152
|
-
it(
|
|
153
|
-
"should return a Package object if the package exists",
|
|
154
|
-
async () => {
|
|
155
|
-
sinon.stub(fs, "stat").resolves();
|
|
156
|
-
const readFileStub = sinon
|
|
157
|
-
.stub(fs, "readFile")
|
|
158
|
-
.resolves(
|
|
159
|
-
Buffer.from(
|
|
160
|
-
JSON.stringify({ description: "Test package" }),
|
|
161
|
-
),
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
// Still use Partial<Model> for the stub resolution type
|
|
165
|
-
sinon
|
|
166
|
-
.stub(Model, "create")
|
|
167
|
-
// @ts-expect-error PartialModel is a partial type
|
|
168
|
-
.resolves({ getPath: () => "model1.model" } as PartialModel);
|
|
169
|
-
|
|
170
|
-
readFileStub.restore();
|
|
171
|
-
readFileStub.resolves(Buffer.from(JSON.stringify([])));
|
|
172
|
-
|
|
173
|
-
const packageInstance = await Package.create(
|
|
174
|
-
"testProject",
|
|
175
|
-
"testPackage",
|
|
176
|
-
testPackageDirectory,
|
|
177
|
-
new Map(),
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
expect(packageInstance).toBeInstanceOf(Package);
|
|
181
|
-
expect(packageInstance.getPackageName()).toBe("testPackage");
|
|
182
|
-
expect(packageInstance.getPackageMetadata().description).toBe(
|
|
183
|
-
"Test package",
|
|
184
|
-
);
|
|
185
|
-
expect(packageInstance.listDatabases()).toEqual([
|
|
186
|
-
{
|
|
187
|
-
path: "database.csv",
|
|
188
|
-
type: "embedded",
|
|
189
|
-
info: {
|
|
190
|
-
name: "database.csv",
|
|
191
|
-
columns: [
|
|
192
|
-
{ name: "Name", type: "string" },
|
|
193
|
-
{ name: "Value", type: "number" },
|
|
194
|
-
],
|
|
195
|
-
rowCount: 3,
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
]);
|
|
199
|
-
expect(packageInstance.listModels()).toBeEmpty();
|
|
200
|
-
},
|
|
201
|
-
{ timeout: 20000 },
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
it(
|
|
205
|
-
"uses package-root-relative DuckDB file paths for nested models",
|
|
206
|
-
async () => {
|
|
207
|
-
await fs.mkdir(join(testPackageDirectory, "data"), {
|
|
208
|
-
recursive: true,
|
|
209
|
-
});
|
|
210
|
-
await fs.mkdir(join(testPackageDirectory, "models"), {
|
|
211
|
-
recursive: true,
|
|
212
|
-
});
|
|
213
|
-
await fs.writeFile(
|
|
214
|
-
join(testPackageDirectory, "data", "root.csv"),
|
|
215
|
-
"name,value\nalpha,1\nbeta,2\n",
|
|
216
|
-
);
|
|
217
|
-
await fs.writeFile(
|
|
218
|
-
join(testPackageDirectory, "models", "root_read.malloy"),
|
|
219
|
-
[
|
|
220
|
-
"source: rows is duckdb.table('data/root.csv')",
|
|
221
|
-
"query: row_count is rows -> { aggregate: c is count() }",
|
|
222
|
-
].join("\n"),
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
const absolutePackageDirectory = resolve(testPackageDirectory);
|
|
226
|
-
const packageInstance = await Package.create(
|
|
227
|
-
"testProject",
|
|
228
|
-
"testPackage",
|
|
229
|
-
absolutePackageDirectory,
|
|
230
|
-
new Map(),
|
|
231
|
-
);
|
|
232
|
-
try {
|
|
233
|
-
const rootModel = packageInstance.getModel(
|
|
234
|
-
"models/root_read.malloy",
|
|
235
|
-
);
|
|
236
|
-
expect(rootModel).toBeDefined();
|
|
237
|
-
const rootResults = await rootModel!.getQueryResults(
|
|
238
|
-
undefined,
|
|
239
|
-
"row_count",
|
|
240
|
-
);
|
|
241
|
-
expect(
|
|
242
|
-
(rootResults.compactResult as { c: number }[])[0]?.c,
|
|
243
|
-
).toBe(2);
|
|
244
|
-
} finally {
|
|
245
|
-
await packageInstance.getMalloyConfig().releaseConnections();
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
{ timeout: 20000 },
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
it(
|
|
252
|
-
"does not resolve DuckDB file paths relative to the model directory",
|
|
253
|
-
async () => {
|
|
254
|
-
await fs.mkdir(join(testPackageDirectory, "models"), {
|
|
255
|
-
recursive: true,
|
|
256
|
-
});
|
|
257
|
-
await fs.writeFile(
|
|
258
|
-
join(testPackageDirectory, "models", "sibling.csv"),
|
|
259
|
-
"name,value\nnested,3\n",
|
|
260
|
-
);
|
|
261
|
-
await fs.writeFile(
|
|
262
|
-
join(testPackageDirectory, "models", "sibling_read.malloy"),
|
|
263
|
-
[
|
|
264
|
-
"source: rows is duckdb.table('./sibling.csv')",
|
|
265
|
-
"query: row_count is rows -> { aggregate: c is count() }",
|
|
266
|
-
].join("\n"),
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
await expect(
|
|
270
|
-
Package.create(
|
|
271
|
-
"testProject",
|
|
272
|
-
"testPackage",
|
|
273
|
-
resolve(testPackageDirectory),
|
|
274
|
-
new Map(),
|
|
275
|
-
),
|
|
276
|
-
).rejects.toThrow();
|
|
277
|
-
},
|
|
278
|
-
{ timeout: 20000 },
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
it(
|
|
282
|
-
"does not treat package-root paths as filesystem isolation",
|
|
283
|
-
async () => {
|
|
284
|
-
const outsidePath = resolve(
|
|
285
|
-
testPackageDirectory,
|
|
286
|
-
"..",
|
|
287
|
-
"outside-package.csv",
|
|
288
|
-
);
|
|
289
|
-
await fs.mkdir(join(testPackageDirectory, "models"), {
|
|
290
|
-
recursive: true,
|
|
291
|
-
});
|
|
292
|
-
await fs.writeFile(outsidePath, "name,value\noutside,9\n");
|
|
293
|
-
await fs.writeFile(
|
|
294
|
-
join(testPackageDirectory, "models", "outside_read.malloy"),
|
|
295
|
-
[
|
|
296
|
-
"source: rows is duckdb.table('../outside-package.csv')",
|
|
297
|
-
"query: row_count is rows -> { aggregate: c is count() }",
|
|
298
|
-
].join("\n"),
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
let packageInstance: Package | undefined;
|
|
302
|
-
try {
|
|
303
|
-
packageInstance = await Package.create(
|
|
304
|
-
"testProject",
|
|
305
|
-
"testPackage",
|
|
306
|
-
resolve(testPackageDirectory),
|
|
307
|
-
new Map(),
|
|
308
|
-
);
|
|
309
|
-
const outsideModel = packageInstance.getModel(
|
|
310
|
-
"models/outside_read.malloy",
|
|
311
|
-
);
|
|
312
|
-
expect(outsideModel).toBeDefined();
|
|
313
|
-
const outsideResults = await outsideModel!.getQueryResults(
|
|
314
|
-
undefined,
|
|
315
|
-
"row_count",
|
|
316
|
-
);
|
|
317
|
-
expect(
|
|
318
|
-
(outsideResults.compactResult as { c: number }[])[0]?.c,
|
|
319
|
-
).toBe(1);
|
|
320
|
-
} finally {
|
|
321
|
-
await packageInstance?.getMalloyConfig().releaseConnections();
|
|
322
|
-
await fs.rm(outsidePath, { force: true });
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
{ timeout: 20000 },
|
|
326
|
-
);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
describe("listModels", () => {
|
|
330
|
-
it("should return a list of models with their paths and types", async () => {
|
|
331
|
-
// Using 'as any' for simplified mock Map value in test
|
|
332
|
-
const packageInstance = new Package(
|
|
333
|
-
"testProject",
|
|
334
|
-
"testPackage",
|
|
335
|
-
testPackageDirectory,
|
|
336
|
-
{ name: "testPackage", description: "Test package" },
|
|
337
|
-
[],
|
|
338
|
-
new Map([
|
|
339
|
-
[
|
|
340
|
-
"model1.malloy",
|
|
341
|
-
{
|
|
342
|
-
getPath: () => "model1.malloy",
|
|
343
|
-
getModel: () => "foo",
|
|
344
|
-
setDiscoveryCuration: () => {},
|
|
345
|
-
setQueryBoundary: () => {},
|
|
346
|
-
} as unknown as Model,
|
|
347
|
-
],
|
|
348
|
-
[
|
|
349
|
-
"model2.malloynb",
|
|
350
|
-
{
|
|
351
|
-
getPath: () => "model2.malloynb",
|
|
352
|
-
setDiscoveryCuration: () => {},
|
|
353
|
-
getNotebookError: () => {
|
|
354
|
-
return {
|
|
355
|
-
message: "This is the error",
|
|
356
|
-
};
|
|
357
|
-
},
|
|
358
|
-
setQueryBoundary: () => {},
|
|
359
|
-
} as unknown as Model,
|
|
360
|
-
],
|
|
361
|
-
]),
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
const models = await packageInstance.listModels();
|
|
365
|
-
expect(models).toEqual([
|
|
366
|
-
{
|
|
367
|
-
// @ts-expect-error TODO: Fix missing projectName type in API
|
|
368
|
-
environmentName: "testProject",
|
|
369
|
-
packageName: "testPackage",
|
|
370
|
-
path: "model1.malloy",
|
|
371
|
-
error: undefined,
|
|
372
|
-
},
|
|
373
|
-
]);
|
|
374
|
-
|
|
375
|
-
const notebooks = await packageInstance.listNotebooks();
|
|
376
|
-
expect(notebooks).toEqual([
|
|
377
|
-
{
|
|
378
|
-
// @ts-expect-error TODO: Fix missing projectName type in API
|
|
379
|
-
environmentName: "testProject",
|
|
380
|
-
packageName: "testPackage",
|
|
381
|
-
path: "model2.malloynb",
|
|
382
|
-
error: "This is the error",
|
|
383
|
-
},
|
|
384
|
-
]);
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
describe("getDatabaseInfo", () => {
|
|
389
|
-
it("should return the size of the database file", async () => {
|
|
390
|
-
sinon.stub(fs, "stat").resolves({ size: 13 } as Stats);
|
|
391
|
-
|
|
392
|
-
// `getDatabaseInfo` now requires the caller to pass in the
|
|
393
|
-
// shared DuckDB connection (resolved once by `readDatabases`
|
|
394
|
-
// off the package's MalloyConfig). For this isolated unit
|
|
395
|
-
// test we mint a fresh ephemeral one — production paths
|
|
396
|
-
// reuse a single connection per package via `Package.create`.
|
|
397
|
-
const conn = new DuckDBConnection("duckdb");
|
|
398
|
-
|
|
399
|
-
// @ts-expect-error Accessing private static method for testing
|
|
400
|
-
const info = await Package.getDatabaseInfo(
|
|
401
|
-
testPackageDirectory,
|
|
402
|
-
"database.csv",
|
|
403
|
-
conn,
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
expect(info).toEqual({
|
|
407
|
-
name: "database.csv",
|
|
408
|
-
columns: [
|
|
409
|
-
{ name: "Name", type: "string" },
|
|
410
|
-
{ name: "Value", type: "number" },
|
|
411
|
-
],
|
|
412
|
-
rowCount: 3,
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it("should probe an xlsx database file", async () => {
|
|
417
|
-
// Real committed fixture: DuckDB's excel extension reads it via the
|
|
418
|
-
// same duckdb.table() replacement scan the csv path uses.
|
|
419
|
-
await fs.copyFile(
|
|
420
|
-
join("tests", "fixtures", "xlsx", "database.xlsx"),
|
|
421
|
-
join(testPackageDirectory, "database.xlsx"),
|
|
422
|
-
);
|
|
423
|
-
const conn = new DuckDBConnection("duckdb");
|
|
424
|
-
|
|
425
|
-
// Unlike parquet/csv (statically linked), excel is downloaded from
|
|
426
|
-
// extensions.duckdb.org on demand. Some CI runners (notably the
|
|
427
|
-
// hosted macOS fleet, per bake-duckdb-extensions.js) cannot reach
|
|
428
|
-
// that CDN, so skip the read there rather than fail; the Linux e2e
|
|
429
|
-
// and the extension-independent specs still cover this path.
|
|
430
|
-
try {
|
|
431
|
-
await conn.runSQL("INSTALL excel; LOAD excel;");
|
|
432
|
-
} catch {
|
|
433
|
-
console.warn(
|
|
434
|
-
"Skipping xlsx probe test: excel extension could not be installed (offline runner)",
|
|
435
|
-
);
|
|
436
|
-
await conn.close();
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// @ts-expect-error Accessing private static method for testing
|
|
441
|
-
const info = await Package.getDatabaseInfo(
|
|
442
|
-
testPackageDirectory,
|
|
443
|
-
"database.xlsx",
|
|
444
|
-
conn,
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
expect(info).toEqual({
|
|
448
|
-
name: "database.xlsx",
|
|
449
|
-
columns: [
|
|
450
|
-
{ name: "Name", type: "string" },
|
|
451
|
-
// xlsx stores every number as a double, so numeric columns
|
|
452
|
-
// always surface as Malloy `number`.
|
|
453
|
-
{ name: "Value", type: "number" },
|
|
454
|
-
],
|
|
455
|
-
rowCount: 3,
|
|
456
|
-
});
|
|
457
|
-
});
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
describe("getDatabasePaths", () => {
|
|
461
|
-
it("should list xlsx files alongside parquet and csv", async () => {
|
|
462
|
-
await fs.copyFile(
|
|
463
|
-
join("tests", "fixtures", "xlsx", "database.xlsx"),
|
|
464
|
-
join(testPackageDirectory, "database.xlsx"),
|
|
465
|
-
);
|
|
466
|
-
|
|
467
|
-
// @ts-expect-error Accessing private static method for testing
|
|
468
|
-
const paths = await Package.getDatabasePaths(testPackageDirectory);
|
|
469
|
-
|
|
470
|
-
expect(paths.sort()).toEqual(["database.csv", "database.xlsx"]);
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
it("should skip Excel owner files (~$name.xlsx)", async () => {
|
|
474
|
-
// Excel creates this sibling while a workbook is open; it is not a
|
|
475
|
-
// valid zip, so probing it would throw and drop the package.
|
|
476
|
-
await fs.writeFile(
|
|
477
|
-
join(testPackageDirectory, "~$database.xlsx"),
|
|
478
|
-
"not a real xlsx",
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
// @ts-expect-error Accessing private static method for testing
|
|
482
|
-
const paths = await Package.getDatabasePaths(testPackageDirectory);
|
|
483
|
-
|
|
484
|
-
expect(paths).toEqual(["database.csv"]);
|
|
485
|
-
});
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
describe("readDatabases", () => {
|
|
489
|
-
it("should report an unreadable database file instead of failing the package", async () => {
|
|
490
|
-
// A corrupt or partial spreadsheet must not take the whole package
|
|
491
|
-
// down, but it must not vanish silently either: it stays in the
|
|
492
|
-
// listing carrying `error` instead of `info`, the same way a model
|
|
493
|
-
// that fails to compile is reported. Extension-independent:
|
|
494
|
-
// broken.xlsx throws whether excel loads or not, so this holds on
|
|
495
|
-
// runners without the CDN too.
|
|
496
|
-
await fs.writeFile(
|
|
497
|
-
join(testPackageDirectory, "broken.xlsx"),
|
|
498
|
-
"not a real xlsx",
|
|
499
|
-
);
|
|
500
|
-
const conn = new DuckDBConnection("duckdb");
|
|
501
|
-
const malloyConfig = {
|
|
502
|
-
connections: { lookupConnection: async () => conn },
|
|
503
|
-
} as unknown as MalloyConfig;
|
|
504
|
-
|
|
505
|
-
const databases =
|
|
506
|
-
// @ts-expect-error Accessing private static method for testing
|
|
507
|
-
(await Package.readDatabases(
|
|
508
|
-
testPackageDirectory,
|
|
509
|
-
malloyConfig,
|
|
510
|
-
)) as {
|
|
511
|
-
path: string;
|
|
512
|
-
info?: unknown;
|
|
513
|
-
error?: string;
|
|
514
|
-
}[];
|
|
515
|
-
|
|
516
|
-
// The valid file still loads with a full probe.
|
|
517
|
-
const good = databases.find((d) => d.path === "database.csv");
|
|
518
|
-
expect(good?.info).toBeDefined();
|
|
519
|
-
expect(good?.error).toBeUndefined();
|
|
520
|
-
|
|
521
|
-
// The broken one is visible over the API, with a reason.
|
|
522
|
-
const bad = databases.find((d) => d.path === "broken.xlsx");
|
|
523
|
-
expect(bad).toBeDefined();
|
|
524
|
-
expect(bad?.info).toBeUndefined();
|
|
525
|
-
expect(bad?.error).toBeTruthy();
|
|
526
|
-
});
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
// A host is authoritative about WHICH TABLE backs a source, never about
|
|
531
|
-
// WHETHER the source may be served frozen — that is decided by compiling the
|
|
532
|
-
// model. These assert the gate that enforces it, because the failure is silent:
|
|
533
|
-
// an admitted binding for a `given`-filtered source serves one caller's rows to
|
|
534
|
-
// everyone, and no error is raised. Scenarios
|
|
535
|
-
// `host-binding-honors-row-level-access` and `host-binding-of-unplanned-source`
|
|
536
|
-
// prove it end to end; these keep it from being refactored away.
|
|
537
|
-
describe("bindStorageServeBindings eligibility gate", () => {
|
|
538
|
-
/** A structurally complete manifest entry — the shape a host sends. */
|
|
539
|
-
const entry = (sourceName: string, table: string) => ({
|
|
540
|
-
sourceEntityId: `eid-${sourceName}`,
|
|
541
|
-
sourceName,
|
|
542
|
-
physicalTableName: table,
|
|
543
|
-
storageConnectionName: "lake",
|
|
544
|
-
schema: [{ name: "region", type: "VARCHAR" }],
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
const packageWith = (
|
|
548
|
-
eligibility:
|
|
549
|
-
| { eligible: string[]; refused: Record<string, string> }
|
|
550
|
-
| undefined,
|
|
551
|
-
) => {
|
|
552
|
-
const pkg = new Package(
|
|
553
|
-
"testProject",
|
|
554
|
-
"testPackage",
|
|
555
|
-
testPackageDirectory,
|
|
556
|
-
{ name: "testPackage" },
|
|
557
|
-
[],
|
|
558
|
-
new Map(),
|
|
559
|
-
);
|
|
560
|
-
// Private by design: its only writer is the load path, which needs a
|
|
561
|
-
// compiled package. Set directly to isolate the filter.
|
|
562
|
-
(
|
|
563
|
-
pkg as unknown as { sourceEligibility: typeof eligibility }
|
|
564
|
-
).sourceEligibility = eligibility;
|
|
565
|
-
return pkg;
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
const boundSources = (pkg: Package) =>
|
|
569
|
-
(pkg.getPackageMetadata().storageServeBindings ?? []).map(
|
|
570
|
-
(b) => b.sourceName,
|
|
571
|
-
);
|
|
572
|
-
|
|
573
|
-
it("drops a refused source's binding and keeps its eligible neighbour", () => {
|
|
574
|
-
const pkg = packageWith({
|
|
575
|
-
eligible: ["all_rollup"],
|
|
576
|
-
refused: { scoped_rollup: "references a given" },
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
pkg.bindStorageServeBindings({
|
|
580
|
-
a: entry("all_rollup", "t_all"),
|
|
581
|
-
b: entry("scoped_rollup", "t_all"),
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
expect(boundSources(pkg)).toEqual(["all_rollup"]);
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
it("refuses every binding when the build plan could not be computed", () => {
|
|
588
|
-
// The plan compute does live schema RPCs, so a warehouse blip during load
|
|
589
|
-
// is the ordinary way this happens — and the package still serves. An
|
|
590
|
-
// unexamined binding must not read as an eligible one.
|
|
591
|
-
const pkg = packageWith(undefined);
|
|
592
|
-
|
|
593
|
-
pkg.bindStorageServeBindings({ a: entry("all_rollup", "t_all") });
|
|
594
|
-
|
|
595
|
-
expect(boundSources(pkg)).toEqual([]);
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
it("refuses a source the plan never contained", () => {
|
|
599
|
-
// Malloy admits only query-shaped sources as build roots, so `#@ persist`
|
|
600
|
-
// on a filtered pass-through produces no plan entry — neither eligible nor
|
|
601
|
-
// refused. Absence is not eligibility.
|
|
602
|
-
const pkg = packageWith({ eligible: ["all_rows"], refused: {} });
|
|
603
|
-
|
|
604
|
-
pkg.bindStorageServeBindings({
|
|
605
|
-
a: entry("all_rows", "t_all"),
|
|
606
|
-
b: entry("scoped", "t_all"),
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
expect(boundSources(pkg)).toEqual(["all_rows"]);
|
|
610
|
-
});
|
|
611
|
-
});
|
|
612
|
-
});
|