-
Notifications
You must be signed in to change notification settings - Fork 4
BDMS-195: jir-kas-notes-model #241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
7d97f47
feat: Create new `Notes` table
ksmuczynski 8ab40ff
doc: Updated `Notes` model docstring for clarity.
ksmuczynski 7aff37d
feat: Add 'notable_type' category and values
ksmuczynski 1c9db25
doc: Remove TODO comments
ksmuczynski 8936e1a
feat: Add polymorphic NotesMixin to support multi-category notes
ksmuczynski d0a7b40
feat: Integrate NotesMixin into Location and Thing models
ksmuczynski c905273
feat: Add Notes schema and polymorphic relationships to Thing and Loc…
ksmuczynski 550acce
fix: Resolve circular import in Notes model
ksmuczynski f18b715
fix: Resolve undefined pk_value in NotesMixin.add_note method
ksmuczynski 6425d06
refactor: Update 'noteable_type' category to `note_type`
ksmuczynski e814635
fix: Standardize location notes as List[NoteResponse] across schemas
ksmuczynski 1000991
Merge branch 'staging' into jir-kas-notes-model
jirhiker 3267246
feat: enhance note management by adding release status and updating n…
jirhiker fc31bc8
fix: update note handling in CRUD operations to ensure session commit…
jirhiker 40ed513
feat: get polymorphic record via function
jacob-a-brown 23832ea
refactor: latest record must have null end date
jacob-a-brown ce1f522
refactor: move polymorphic record retrival to tests
jacob-a-brown d672c72
fix: call erase and rebuild db from core/initializers.py
jacob-a-brown e1ff3a3
feat: Add Notes schema and polymorphic relationships to Thing and Loc…
ksmuczynski a09348a
fix: Standardize location notes as List[NoteResponse] across schemas
ksmuczynski 8ef4904
feat: enhance note management by adding release status and updating n…
jirhiker 8837553
fix: streamline note handling by consolidating session commit and ref…
jirhiker 3a31d0c
Merge branch 'refs/heads/staging' into jir-kas-notes-model
jirhiker e5897c8
refactor: rename notable_id and notable_type to target_id and target_…
jirhiker 8cb720f
fix: comment out test notes and polymorphic relationship mappings in …
jirhiker 9d07555
Merge branch 'staging' into jir-kas-notes-model
jirhiker 774a4a2
feat: enhance notes functionality in well and location models
jirhiker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| """ | ||
| SQLAlchemy model for the Notes table. | ||
|
|
||
| This is a polymorphic table for storing all unstructured notes, categorized by | ||
| a note_type. | ||
|
|
||
| The Notes table should be used when a record might need more than one note, | ||
| when the notes need to be categorized, or when you need the ability to | ||
| search across all notes in the system. This is different from a dedicated | ||
| notes field on a specific table, which should be used to store a simple, | ||
| single-purpose attribute of the record itself. | ||
| """ | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| from sqlalchemy import Integer, Text, Index, and_ | ||
| from sqlalchemy.orm import relationship, Mapped, mapped_column, declared_attr, foreign | ||
|
|
||
| from db.base import Base, AutoBaseMixin, ReleaseMixin, lexicon_term | ||
|
|
||
| if TYPE_CHECKING: | ||
| pass | ||
|
|
||
|
|
||
| class Notes(Base, AutoBaseMixin, ReleaseMixin): | ||
| """ | ||
| Represents a single, categorized note that can be attached to various | ||
| parent objects throughout the database. | ||
| """ | ||
|
|
||
| # --- Polymorphic Columns --- | ||
| target_id: Mapped[int] = mapped_column( | ||
| Integer, | ||
| nullable=False, | ||
| comment="The ID of the parent record this note is about (e.g., a `thing_id`, `location_id`, etc).", | ||
| ) | ||
| target_table: Mapped[str] = mapped_column() | ||
| # notable_type: Mapped[str] = lexicon_term( | ||
| # nullable=False, | ||
| # comment="The type of the note associated with this record.", | ||
| # ) | ||
|
|
||
| # --- Columns --- | ||
| note_type: Mapped[str] = lexicon_term( | ||
| nullable=False, | ||
| comment="A controlled vocabulary field that defines the specific category of the note (e.g. 'Access Instructions`, ", | ||
| ) | ||
| content: Mapped[str] = mapped_column(Text, nullable=False) | ||
|
|
||
| # --- Polymorphic Parent Relationships (Internal) --- | ||
| # These are viewonly relationships used by the 'target' property below. | ||
| # _thing_target: Mapped["Thing"] = relationship( | ||
| # "Thing", | ||
| # primaryjoin="and_(foreign(Notes.target_id) == Thing.id, Notes.target_table == 'thing')", | ||
| # viewonly=True, | ||
| # ) | ||
| # _location_target: Mapped["Location"] = relationship( | ||
| # "Location", | ||
| # primaryjoin="and_(foreign(Notes.target_id) == Location.id, Notes.target_table == 'location')", | ||
| # viewonly=True, | ||
| # ) | ||
|
|
||
| @property | ||
| def target(self): | ||
| """ | ||
| A generic property to get the parent object (Thing, Location, etc.). | ||
|
|
||
| This is useful for simplifying application code by providing a single, | ||
| consistent way to access the parent of a polymorphic record without | ||
| needing to check the 'notable_type' field manually. | ||
| """ | ||
| return getattr(self, f"_{self.target_table.lower()}_target") | ||
|
|
||
| # --- Table Arguments --- | ||
| # A composite index to optimize retrieval of all note records for a specific parent object. | ||
|
|
||
| __table_args__ = (Index("ix_notes_polymorphic_link", "target_id", "target_table"),) | ||
|
|
||
|
|
||
| class NotesMixin: | ||
| """ | ||
| Mixin for models that can have multiple types or categories of notes. | ||
| It automatically creates a polymorphic One-to-Many relationship to the | ||
| Notes table. | ||
| """ | ||
|
|
||
| @declared_attr | ||
| def notes(cls): | ||
| """ | ||
| The high-performance, declarative relationship for reading notes. | ||
| This provides a polymorphic one-to-many link to the Notes table. | ||
|
|
||
| PERFORMANCE NOTE: Use with `selectinload` in queries to prevent the | ||
| N+1 query problem when accessing notes for multiple parent objects. | ||
| """ | ||
| return relationship( | ||
| "Notes", | ||
| primaryjoin=and_( | ||
| cls.id == foreign(Notes.target_id), | ||
| Notes.target_table == cls.__name__, | ||
| ), | ||
| cascade="all, delete-orphan", | ||
| lazy="selectin", | ||
| overlaps="notes", | ||
| ) | ||
|
|
||
| def add_note( | ||
| self, | ||
| content: str, | ||
| note_type: str, | ||
| release_status: str = "draft", | ||
| created_by: str = None, | ||
| ) -> Notes: | ||
| """ | ||
| A convenient factory method to create a new Note associated with this object. | ||
| This provides a clean, object-oriented API for writing. | ||
| """ | ||
|
|
||
| return Notes( | ||
| content=content, | ||
| note_type=note_type, | ||
| target_id=self.id, | ||
| target_table=self.__class__.__name__, | ||
| release_status=release_status, | ||
| ) | ||
|
|
||
| def _get_notes(self, note_type: str) -> list[Notes]: | ||
| return [n for n in self.notes if n.note_type == note_type] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """ | ||
| Pydantic models for the Notes table. | ||
| """ | ||
|
|
||
| from schemas import BaseCreateModel, BaseUpdateModel, BaseResponseModel | ||
|
|
||
| # -------- BASE SCHEMA: ---------- | ||
| """ | ||
| Defines the core, shared attributes of a Note for reuse. | ||
| """ | ||
|
|
||
|
|
||
| class BaseNote: | ||
| note_type: str | ||
| content: str | ||
|
|
||
|
|
||
| # -------- CREATE ---------- | ||
| class CreateNote(BaseCreateModel, BaseNote): | ||
| # TODO: this was a suggestion by AI, but based on our other schemas it | ||
| # seems like more should be added here... | ||
| """ | ||
| Schema for creating a new Note. The parent object's ID and type will be | ||
| taken from the URL path, not the request body. | ||
| """ | ||
| pass | ||
|
|
||
|
|
||
| # -------- RESPONSE ---------- | ||
| class NoteResponse(BaseResponseModel, BaseNote): | ||
| """ | ||
| Response schema for Note details. | ||
| """ | ||
|
|
||
| target_id: int | ||
| target_table: str | ||
|
|
||
|
jirhiker marked this conversation as resolved.
|
||
|
|
||
| # -------- UPDATE ---------- | ||
| class UpdateNote(BaseUpdateModel): | ||
| """ | ||
| Schema for updating an existing Note. All fields are optional | ||
| """ | ||
|
|
||
| note_type: str | None = None | ||
| content: str | None = None | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.