Skip to content

Use ogsi model#32

Draft
AlexAxthelm wants to merge 26 commits intomainfrom
use-ogsi-model
Draft

Use ogsi model#32
AlexAxthelm wants to merge 26 commits intomainfrom
use-ogsi-model

Conversation

@AlexAxthelm
Copy link
Collaborator

@AlexAxthelm AlexAxthelm commented Mar 4, 2026

Followup to #29, but here I'm adding the dependency on the OGSI domain model, and adding a domain-specific endpoint (/api/v1/oil-gas-fields). Bringing in the frontend mvp from #20, but otherwise closing that set of PRs as superseded by this.

Later, we can decide if we want to un-expose the resources endpoint.

ChatGPT helped write the code and identify spots to edit, but I've altered it's output significantly.

Putting as draft, but in practice, I think it's ready for review (missing new tests). looking to @mbarlow12 for suggestsions on if there's anything in particular I should add in tests?

@AlexAxthelm AlexAxthelm changed the base branch from use-stitch-models to main March 4, 2026 22:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the OGSI domain model to Stitch, refactors the generic Resource API to be domain-agnostic, and introduces a new domain-specific Oil & Gas Fields API + frontend wiring.

Changes:

  • Add stitch-ogsi/stitch-models workspace dependencies and use OGSI models for Oil & Gas Fields.
  • Introduce /api/v1/oil-gas-fields endpoints backed by a new oil_gas_fields table (1:1 with resources).
  • Update the frontend MVP to query and display OG fields instead of generic resources.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
uv.lock Adds workspace deps for stitch-models and stitch-ogsi.
packages/stitch-models/src/stitch/models/init.py Introduces EmptySourcePayload and a BaseResource alias for domain-agnostic use.
deployments/stitch-frontend/src/queries/ogfields.js Adds React Query key/query factory for OG fields.
deployments/stitch-frontend/src/queries/api.js Adds getOGFields / getOGField API helpers.
deployments/stitch-frontend/src/hooks/useOGFields.js Adds hooks wrapping authenticated queries for OG fields.
deployments/stitch-frontend/src/components/OGFieldsView.jsx Adds list view UI for OG fields + cache controls.
deployments/stitch-frontend/src/components/OGFieldsList.jsx Adds list rendering and JSON debug output for OG fields.
deployments/stitch-frontend/src/components/OGFieldView.jsx Adds single-OG-field fetch view by ID.
deployments/stitch-frontend/src/App.test.jsx Updates app smoke tests to expect OG field headings.
deployments/stitch-frontend/src/App.jsx Switches app to OGFields views instead of Resources views.
deployments/api/tests/utils.py Simplifies test factories to a minimal, domain-agnostic CreateResource.
deployments/api/tests/routers/test_resources_unit.py Updates resources router unit tests for the new entities/factories.
deployments/api/tests/routers/test_resources_integration.py Updates resources integration tests to match simplified resource model.
deployments/api/tests/db/test_resource_actions.py Updates DB integration tests for simplified resource creation/listing.
deployments/api/tests/conftest.py Removes fixtures tied to removed source tables/models.
deployments/api/src/stitch/api/routers/resources.py Switches router models to domain-agnostic resources.entities.
deployments/api/src/stitch/api/routers/oil_gas_fields.py Adds new /oil-gas-fields router using OGSI models + new DB model.
deployments/api/src/stitch/api/resources/entities.py Introduces domain-agnostic CreateResource/Resource API models.
deployments/api/src/stitch/api/ogsi/entities.py Adds OGSI-ish API models (currently not referenced elsewhere).
deployments/api/src/stitch/api/main.py Registers the new oil-gas-fields router.
deployments/api/src/stitch/api/entities.py Removes legacy source/resource entities; keeps User.
deployments/api/src/stitch/api/db/resource_actions.py Refactors resource actions to be domain-agnostic (no sources/memberships).
deployments/api/src/stitch/api/db/model/sources.py Deletes source table models and related helpers.
deployments/api/src/stitch/api/db/model/resource.py Removes country, loosens membership source typing, adjusts source_pk handling.
deployments/api/src/stitch/api/db/model/oil_gas_field.py Adds OilGasFieldModel with JSON payload + FK to resources.
deployments/api/src/stitch/api/db/model/mixins.py Makes PayloadMixin accept any BaseModel payload (not only SourceBase).
deployments/api/src/stitch/api/db/model/init.py Exports OilGasFieldModel; removes source model exports.
deployments/api/src/stitch/api/db/init_job.py Updates dev seeding to create resources + example OG fields (no source tables).
deployments/api/pyproject.toml Adds stitch-models and stitch-ogsi as dependencies.
Comments suppressed due to low confidence (2)

deployments/stitch-frontend/src/components/OGFieldView.jsx:59

  • Grammar: the empty-state message says “fetch a ogfield”, which should be “fetch an ogfield” (or “fetch an OG field”).
        message={`No ogfield loaded. Click the button above to fetch a ogfield.`}
      />

deployments/api/src/stitch/api/ogsi/entities.py:18

  • CreateOilGasField/OilGasField models are introduced here but aren’t referenced anywhere in the API code (the router uses stitch.ogsi.model.OGFieldView / OilGasFieldBase instead). If these types are not part of the intended API surface, remove the file; otherwise, update the router to use them to avoid dead code.
from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field
from stitch.api.resources.entities import CreateResource, Resource as ResourceView


class CreateOilGasField(BaseModel):
    model_config = ConfigDict(extra="forbid")
    resource: CreateResource
    owner: str | None = Field(default=None)
    operator: str | None = Field(default=None)


class OilGasField(BaseModel):
    id: int
    resource: ResourceView
    owner: str | None = None
    operator: str | None = None

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +55 to +56
# DB ResourceModel may store `.name`; tolerate either while refactor settles.
assert getattr(db_resource, "name", None) in (None, "Test Label")
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test allows the DB value for name to be either None or the expected label. Since resource_actions.create() is supposed to persist the name, this assertion is too permissive and could hide regressions. Tighten the expectation (or, if behavior is intentionally in flux, assert the specific transitional behavior explicitly).

Suggested change
# DB ResourceModel may store `.name`; tolerate either while refactor settles.
assert getattr(db_resource, "name", None) in (None, "Test Label")
# DB should persist the provided name.
assert db_resource.name == "Test Label"

Copilot uses AI. Check for mistakes.
Comment on lines 46 to 57
cls,
created_by: UserEntity,
resource: "ResourceModel",
source: SourceKey,
source: str,
source_pk: IdType,
status: MembershipStatus = MembershipStatus.ACTIVE,
):
model = cls(
resource_id=resource.id,
source=source,
source_pk=str(source_pk),
source_pk=int(source_pk),
status=status,
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MembershipModel.create() now coerces source_pk via int(source_pk), but IdType includes UUID. int(UUID) produces a 128-bit integer that can overflow a BIGINT/PORTABLE_BIGINT column (and also changes semantics vs storing the UUID itself). Either restrict IdType here to int, or store UUIDs in a dedicated UUID/text column (or keep string storage) so memberships can safely reference non-integer IDs.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +45
export async function getOGFields(fetcher) {
const url = `${config.apiBaseUrl}/oil-gas-fields/`;
const response = await fetcher(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}

export async function getOGField(id, fetcher) {
const url = `${config.apiBaseUrl}/oil-gas-fields/${id}`;
const response = await fetcher(url);
if (!response.ok) {
const error = new Error(`HTTP error! status: ${response.status}`);
error.status = response.status;
throw error;
}
const data = await response.json();
return data;
}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New API helpers getOGFields/getOGField were added, but api.test.js only covers the resources helpers. Add tests mirroring the existing getResources/getResource coverage (success + non-OK response + network failure) to prevent regressions in URL construction and error handling.

Copilot uses AI. Check for mistakes.
@AlexAxthelm AlexAxthelm self-assigned this Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants