Skip to content

feat:(fb) Add FormService for form management - #66

Merged
poBogan merged 4 commits into
mainfrom
feature/form-crud-service
Jan 27, 2026
Merged

feat:(fb) Add FormService for form management#66
poBogan merged 4 commits into
mainfrom
feature/form-crud-service

Conversation

@poBogan

@poBogan poBogan commented Jan 25, 2026

Copy link
Copy Markdown
Contributor

I asked Claude for help and this is what it came up with.

Implementation Details

Summary

Created a comprehensive service layer for form CRUD operations in form_service.py. The service follows the existing project patterns and conventions, mirroring the structure of submission_service.py.

Implemented Methods

FormService Class

The service layer includes the following methods:

Core CRUD Operations

  1. create_form(form_data: FormCreate) -> FormInDB

    • Creates a new form in the database
    • Automatically generates ObjectId and timestamps
    • Initializes view_count and submission_count to 0
    • Returns the created form
  2. get_form_by_id(form_id: PyObjectId) -> FormInDB | None

    • Retrieves a single form by its ID
    • Returns None if form not found
    • Handles ObjectId conversion
  3. get_all_forms(skip: int = 0, limit: int = 10, active_only: bool = False) -> tuple[list[FormInDB], int]

    • Retrieves all forms with pagination support
    • Optional active_only filter to show only active forms
    • Returns tuple of (forms list, total count)
    • Validates pagination parameters (skip >= 0, 1 <= limit <= 100)
    • Sorts by creation date (newest first)
  4. update_form(form_id: PyObjectId, form_data: FormUpdate) -> FormInDB | None

    • Updates an existing form with partial data
    • Only updates fields that are provided (not None)
    • Automatically sets updated_at timestamp
    • Returns updated form or None if not found
  5. delete_form(form_id: PyObjectId) -> bool

    • Deletes a form by ID
    • Returns True if deleted, False if not found

Utility Methods

  1. increment_view_count(form_id: PyObjectId) -> bool
    • Atomically increments the view count for a form
    • Useful for tracking form analytics
    • Returns True if successful, False if form not found

Helper Methods

  1. _to_object_id(obj_id: PyObjectId) -> ObjectId

    • Converts PyObjectId to MongoDB ObjectId
    • Validates ObjectId format
    • Raises ValueError for invalid IDs
  2. _document_to_form(doc: dict | None) -> FormInDB | None

    • Converts MongoDB document to FormInDB model
    • Handles None documents gracefully
    • Logs errors during conversion

Key Features

  • Type Safety: Strict type hints for all parameters and return values
  • Error Handling: Comprehensive error handling with PyMongoError catching
  • Logging: Detailed logging for all operations (info, warning, error levels)
  • Async/Await: All I/O operations use async/await pattern
  • Validation: Proper validation of pagination parameters and ObjectIds
  • Consistency: Follows the same patterns as submission_service.py

Integration

The service integrates with:

  • Database: Uses Motor (AsyncIOMotorDatabase) for MongoDB operations
  • Models: Uses Pydantic models from app/models/form.py
  • Logger: Uses the project's logger from app/utils/logger

Code Quality

Linting: Passed Ruff checks with no errors
Conventions: Follows Python backend conventions (snake_case, type hints, async/await)
Documentation: Comprehensive docstrings for all methods
Error Handling: Proper exception handling and logging

Usage Example

from app.db.mongodb import get_database
from app.services.form_service import FormService
from app.models.form import FormCreate

# Initialize service
db = await get_database()
form_service = FormService(db)

# Create a form
form_data = FormCreate(
    title="Event Registration",
    description="Register for our upcoming event",
    questions=[...],
    is_active=True
)
new_form = await form_service.create_form(form_data)

# Get all active forms
forms, total = await form_service.get_all_forms(skip=0, limit=10, active_only=True)

# Increment view count
await form_service.increment_view_count(new_form.id)

Related Issue

Closes #49

Checklist

Introduces the FormService class to handle business logic and database operations for forms, including create, read, update, delete, and view count increment. Updates __init__.py to export FormService.
@poBogan
poBogan requested a review from seberatolmez January 25, 2026 00:48
@poBogan poBogan self-assigned this Jan 25, 2026
@poBogan poBogan added enhancement New feature or request form backend labels Jan 25, 2026
Removed an unnecessary trailing newline in __init__.py and improved logger.info formatting in form_service.py for better readability.
@DogukanUrker
DogukanUrker requested review from DogukanUrker and removed request for seberatolmez January 25, 2026 05:38

@DogukanUrker DogukanUrker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

hey, i see there’s a plan in the pr body but that’s not really how this should work. the whole point of an implementation plan is to discuss and get approval before writing the code, not after the pr is already open. otherwise it’s just documentation, not a plan we can actually act on.

for future prs, please create the implementation plan separately, get approval from me or berat first, then start coding. i’ll review this one today, if it needs major changes we might be better off starting fresh with the proper flow.

btw i noticed you used claude for the plan which is cool. curious though, which model did you use and where? (cursor, claude code, claude desktop, etc.?)

@poBogan

poBogan commented Jan 25, 2026

Copy link
Copy Markdown
Contributor Author

I used Claude Sonnet 4.5 that Antigravity provides. About the workflow, initially my intention was to follow it (create a implementation plan, get approval and continue with coding) but when I asked help from Claude about the task it just did everything without a implementation plan, when I asked for one it said that it did not create one since the task seemed simple and an implementation plan was not required. So I examined the code myself and decided it was ok to send you the code and documentation. In any case I will folow the proper workflow for future prs

@DogukanUrker

Copy link
Copy Markdown
Member

ahh got it. so antigravity actually has a “plan mode” you can select from the chat (there’s fast mode and plan mode). for implementation plans, try using plan mode and start your prompt with something like “create an implementation plan for…” before diving into the task.

ai models tend to be eager to complete everything from start to finish. that’s just how they’re built. we need to guide them with proper prompts to prevent that. but honestly, the fact that you reviewed the code yourself and made the judgment call to send it is really solid, that’s exactly the kind of critical thinking we need for software development.

also heads up,antigravity gives you claude opus 4.5 for free, try using that next time. it’s currently the best model for coding tasks.

i want to set up a more detailed meeting soon about ai usage. i’ll walk through how to get the results we want more easily and efficiently. haven’t reviewed the pr yet so can’t speak on the code itself, but appreciate the proactive approach

@DogukanUrker DogukanUrker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm! the code follows the existing patterns from submission_service well and the implementation is solid.

there are a couple of small things we can address later:

  • _to_object_id returns unknown types unchanged instead of raising an error (same pattern exists in submission_service though)
  • update_form uses exclude_none=True which prevents intentionally clearing fields like start_date or deadline - might want to change to just exclude_unset=True

nothing blocking, we can revisit these in a follow-up if needed.

Raise TypeError if obj_id is not ObjectId or str in _to_object_id, and update form update logic to include fields with None values by removing exclude_none from model_dump.
Simplified the TypeError exception message in the _ensure_object_id method by moving it to a single line for improved readability.
@poBogan
poBogan merged commit e711499 into main Jan 27, 2026
2 checks passed
@poBogan
poBogan deleted the feature/form-crud-service branch January 27, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend enhancement New feature or request form

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(fb): implement form CRUD service

2 participants