feat: Add organization member support with memberType field
Implements support for both individual persons and organizations as members. Changes: - Added MemberType enum (INDIVIDUAL, ORGANIZATION) to distinguish member types - Added member_type column to database (defaults to INDIVIDUAL for backward compatibility) - Added company_name field for organizations - Made first_name nullable (required for individuals, optional for organizations) - Implemented conditional validation: - INDIVIDUAL members require first_name - ORGANIZATION members require company_name - Updated GraphQL schema with new memberType and companyName fields - Updated all resolvers to handle new fields and validation - Added comprehensive unit tests for validation logic - Updated existing tests to work with new fields - All 53 tests passing Technical notes: - Using memberType instead of 'kind' to avoid GraphQL introspection conflicts - Using native_enum=False for SQLite compatibility - Using batch_alter_table for SQLite ALTER COLUMN compatibility - Backward compatible: existing members automatically become INDIVIDUAL type 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"""add organization member support
|
||||
|
||||
Revision ID: b61b6b2d83cc
|
||||
Revises: 0f79356844b5
|
||||
Create Date: 2025-12-04 12:03:16.548989
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'b61b6b2d83cc'
|
||||
down_revision: Union[str, Sequence[str], None] = '0f79356844b5'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# Add member_type column with default 'INDIVIDUAL'
|
||||
op.add_column(
|
||||
'members',
|
||||
sa.Column('member_type', sa.String(length=20), nullable=False, server_default='INDIVIDUAL')
|
||||
)
|
||||
|
||||
# Add company_name column (nullable)
|
||||
op.add_column(
|
||||
'members',
|
||||
sa.Column('company_name', sa.String(length=200), nullable=True)
|
||||
)
|
||||
|
||||
# Alter first_name to be nullable (SQLite compatible using batch operations)
|
||||
with op.batch_alter_table('members', schema=None) as batch_op:
|
||||
batch_op.alter_column(
|
||||
'first_name',
|
||||
existing_type=sa.String(length=100),
|
||||
nullable=True
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# Remove company_name and member_type columns
|
||||
op.drop_column('members', 'company_name')
|
||||
op.drop_column('members', 'member_type')
|
||||
|
||||
# Revert first_name to nullable=False
|
||||
# Note: This may fail if there are organization members without first_name
|
||||
with op.batch_alter_table('members', schema=None) as batch_op:
|
||||
batch_op.alter_column(
|
||||
'first_name',
|
||||
existing_type=sa.String(length=100),
|
||||
nullable=False
|
||||
)
|
||||
Reference in New Issue
Block a user