Skip to content

datasource import: generate object drafts from an OData $metadata document, and the Studio datasource page lists and imports its entity sets — epic #27261 P2 #27745

Closed

Description

@objectstack-fleet

epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Filing gate: ③ maintainer-directed — 田騏 at 2026-10-29T21:58Z 「现在启动全部 P2」 (epic comment 6509296853, D1 amended), at 2026-10-29T21:59Z 「OData 驱动 只做 v4」 (6509311454), at 2026-10-29T22:01Z 「同意」 (generic P2 parts open source in this repository; vendor-specific drivers such as Salesforce stay out of it).
Ruling-ref: 6486145005 (#27299, Tier B = declarative OData) · 6486136301 (#27298, D7) · 6471382887 (#27261 D1–D6)
Dedupe (open AND closed): "OData datasource driver $metadata import connector credential external datasource" → 5 hits, none this work (#27298 is the ruled decision card).
Reader: the epic PM (#27261) dispatches it in the epic subtree.
Blocked-by: #27741
type: Feature

维护者速读

  • 做什么: 在 Studio 里指向一个 OData 数据源,列出它的实体集,勾选后生成对象草稿(字段、类型、主键、关联);AI 通过 MCP 的同一入口也能做。
  • 为什么: 不写代码接入的另一半:没有导入,管理员仍要手写对象。
  • 需要您做的: 无。

Task

  • IExternalDatasourceService.generateObjectDraft / importObject work for an odata datasource through the driver's introspectSchema ($metadata): EDM types map to field types, the key to the id, navigation properties to lookups when the target is also imported (else left out and named).
  • Studio's datasource page (ui/packages/app-shell/src/views/metadata-admin) lists an OData datasource's entity sets with an import action; imported objects are external, read-only unless the author opts in.
  • MCP: list_remote_tables / import_object reach the same path.
  • Tests: draft generation from a recorded $metadata fixture; the Studio flow against a mocked service.

Clause-②: decided by the dev from the diff · Metadata-protocol: none.

Activity

  1. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
    Claim: PM loop round 11 2026-10-30T01:37Z
    Session: session_017ihL2c5z3q4h8inrn5kwqV (epic PM); implementing card thread session_017ihL2c8AWH1pFbfa5XHrbg
    Account: marchtian
    Branch: claude/project-thread-kmqsti (the card thread's platform-assigned branch — measured platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27745
    Domain: domain:ui
    Seat: epic:#27261#1 (epic PM; no domain:* seat). Maintainer order, 田騏 2026-10-29T21:58Z: 「现在启动全部 P2」 (ruling 6486145005, Tier B = declarative OData)
    File surface: packages/services/service-datasource/src/** (draft generation and import for a driver.odata datasource through introspectSchema), packages/drivers/driver-odata/src/** (only what introspectSchema must add for drafts: EDM → field type, key, navigation), ui/packages/app-shell/src/views/metadata-admin/** (the datasource page's entity-set list and import action), the MCP list_remote_tables / import_object path, their tests, .changeset/** (stop on breach, including any packages/spec/src/** edit; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: epic #27261 P2 (ruling 6486145005), unblocked by #27741 (PR #27796, 0a4b0fb223)
    Thread-read: none
    Premise: holds — on origin/main (0a4b0fb2) driver-odata answers introspectSchema from $metadata, but no draft or import path or Studio flow reaches an OData datasource.
    Serial constraints: #27746 (PR #27819) edits service-datasource/src/datasource-connection-service.ts and the admin plugin/service; do not edit those files, or merge main after #27819 lands and say so. If the diff turns out to change a published contract (Clause-② other than no), stop and report before the PR.

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
    Claim amendment · 2026-10-30T01:41Z

    The card thread stopped on a spec question, as the claim asks. On main, the type-compat matrix (packages/spec/src/data/type-compat.ts) knows no EDM names. It serves both draft suggestion (suggestFieldTypeForSqlType) and Gate 2 boot validation (isCompatible). So every Edm.* column canonicalises to unknown: drafts come out all text, and an object mapping Edm.Int32 to number is a type_mismatch error at boot under onMismatch: 'fail'.

    PM ruling: option A. The matrix gains an odata arm: SqlDialect adds 'odata', and DIALECT_ALIASES.odata maps the EDM primitives, with Edm.Int64 and Edm.Decimal lossy as their SQL kin are. The service maps the driver's odata-4.0 dialect onto it. This keeps one type table for draft, catalog and Gate 2. A second EDM table inside service-datasource (option B) was declined: it would leave the CLI and every other matrix reader EDM-blind.

    • File surface adds packages/spec/src/data/type-compat.ts, its tests, and the generated references the change re-records.
    • Clause-② becomes yes: a published union widens. The PR names every exhaustive consumer of SqlDialect in the repository, ui/ included, and updates it in the same PR.
    • Contract face: the PR body says "Fable review owed". It lands only after a CONTRACT_REVIEW_TIER record PASS on its head.

    Navigation lookups read the registry (no contract change). The draft's snake_case field names with external.columnMap for PascalCase EDM properties stay inside service-datasource.

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
    Claim amendment 2 · 2026-10-30T01:41Z

    Second half of the option-A ruling (6512853588). isCompatible lists lookup only under the uuid row, so a lookup over a foreign-key column of type Edm.Int32, int or varchar is a Gate 2 type_mismatch today, for SQL federation too. The same file adds lookup and master_detail to the exact sets of the text, integer and bigint rows. Gate 2 gets looser and nothing that passes today fails. The changeset and PR say so in plain words for SQL federation.

    A single-valued navigation becomes a lookup only when it has a ReferentialConstraint whose dependent property is on the entity type and whose referenced property is the target's single key. Every other navigation is left out and named in the review notes. No further surface change.

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
    Scope addition · 2026-10-30T02:43Z

    #27747's guide (PR #27871) says in content/docs/data-modeling/odata-datasources.mdx §2: "Declare each field by hand. Nothing generates fields from $metadata today." When this card's import lands, rewrite that bullet to point at the import flow (Studio datasource page and MCP import_object). The file surface adds that one page. Merge main after #27871 lands.

  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c8AWH1pFbfa5XHrbg
    os-dev-report

    {
     "issue": 27745,
     "status": "done",
     "branch": "claude/project-thread-kmqsti",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/27880",
     "head": "14e38cf6",
     "session": "session_017ihL2c8AWH1pFbfa5XHrbg",
     "premise_still_valid": true,
     "summary": "OData $metadata import end to end. spec type-compat (ruling A, amendments 6512853588/6512860835): SqlDialect 'odata' with EDM aliases; lookup/master_detail exact under text/integer/bigint (Gate 2 looser for SQL federation too, Clause-② yes widening). driver-odata introspectSchema lists each navigation's referentialConstraints. service-datasource: typeVocabulary maps odata-4.0 to odata for draft/refreshCatalog/validate; snake_case field and object names with external.columnMap (rename overrides land there too; fixes the _products object name); draftLookups makes a lookup only for a single ReferentialConstraint onto the target's single key with the target imported on the same datasource (or self), every other navigation left out and named in review. Studio tables tab: multi-select + Import selected (targets first, by review remoteType), batch results, write opt-in only when the datasource allows writes (single-table dialog too), en/zh rows. MCP: registerFederationTools list_remote_tables/import_object under grantsAuthoringTools; runtime bridge asks FEDERATION_READ/WRITE_CAPABILITY before the service lookup (403), 503 without a service; rest exports the two constants. Guide odata-datasources.mdx §2 bullet rewritten to point at the import (PM item after #27871).",
     "tests": "service-datasource 64 files / 1041 passed incl. external-object-draft-odata-metadata.test.ts (13: real ODataDriver over a recorded Northwind $metadata, EDM mapping, columnMap, lookups only onto imported targets, self ref, composite source, Gate 2 clean on 4 objects + negative control, driver follows category_id). driver-odata 439 passed; spec type-compat 27 passed, check:generated current; mcp 595 passed incl. mcp-federation-tools.test.ts (9); runtime mcp-federation-bridge.test.ts (4) + MCP domain files; ui metadata-admin external+previews 154 files / 1722 passed incl. SchemaBrowser.batchImport-27745.test.tsx (7); app-shell type-check 0.",
     "gates": "dispatch-gates --commands after merging origin/main (e320e366) and the guide edit: 122 derived. First pass on 100: 93 exit 0, 7 exit 3 (teardown fixture commit, spec dist, dual-build dist); all rerun after their prerequisites, exit 0; the 22 families the merge/docs added all exit 0. Final --ran: 122 derived, 122 run, 0 NOT-MEASURED (DERIVED zero). CI on 4f044127 all green; on 14e38cf6 at report time: lint/type-check source gates, Check Changeset, PR-body guards success, Test Core and builds in_progress, 0 failure.",
     "dogfood_battery": "n/a: no ! in the title; Dogfood Regression Gate job green on the PR",
     "mcp_calls": "github issue_read (#27745 get/comments), pull_request_read (#27880 get, get_check_runs), get_job_logs (the test-source alias gate red on bc74ebf9), subscribe_pr_activity x1; no MCP write tool",
     "api_writes": "relay pr_create (PR #27880); relay issue_patch on #27880 (run 40996633151, 11703 bytes read back identical); relay comment on #27745 (this report). git push is not a REST write.",
     "surface_note": "No edit to datasource-connection-service.ts or the admin plugin/service (#27819), per the Claim. packages/spec touched under the PM ruling; PR says Fable review owed and waits for a contract review PASS. vitest.config.ts alias for @objectstack/driver-odata (test-source alias gate). content/docs/data-modeling/odata-datasources.mdx per the PM's added item.",
     "deviation": "The ruling text said Edm.Int64/Edm.Decimal would be lossy; they take SQL's bigint/numeric verdict (exact for number), because lossiness is per canonical row. My misstatement in the option text; stated in the PR body.",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: none · runtime test-layer typecheck reports @objectstack/driver-turso unresolved in organization-ownership-boot-guard.turso-remote.kernel.test.ts in a cloud container (package not built); CI green, untouched file, not filed"
     ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
    Landed · 2026-10-30T04:31Z

    PR #27880 merged through the queue as d3b0a405d9 on 2026-10-30T04:21:18Z (head 14e38cf6; contract review PASS 6514424141 at CONTRACT_REVIEW_TIER, which, under the 2026-10-29 19:39Z order, also served as the full review of the spec change; seat ACCEPT 6514449474). An OData datasource's entity sets import as object drafts from $metadata through Studio's Tables tab and MCP list_remote_tables / import_object. The type matrix knows the odata dialect, and a lookup can sit on a text or integer foreign key. Follow-on: #27917 (the record's should-fixes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions