Skip to content

Latest Graphene Library, Assertion Error on same Enum in Multiple SQL Alchemy Columns #302

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

Closed
ShantanuJoshi opened this issue Mar 24, 2021 · 3 comments

Comments

@ShantanuJoshi
Copy link

Hi everyone I know there are quite a few issues documented regarding the assertion error that occurs as a result of the same enum being utilized in two different SQL alchemy mappings with the same column name. I've read through #208, as well as this PR: #210 which in theory should resolve the issue I'm seeing. The other approaches around changing the naming with connections fields seem unnecessary in 2.3 based on the PR and other documentation that such cases are accounted for, but please let me know if I missed a potential solution.

The resulting error is:

AssertionError: Found different types with the same name in the schema: JobStatusEnum, JobStatusEnum.

For context here's my enum, mappings, and graphene setup:

Enum:

import enum
class JobStatusEnum(enum.Enum):
    matched = 1
    interested = 2
    closed = 3
    match_rejected = 4

Mapping (left out extra columns and CinexBase is just a declarative_base(metadata=MetaData("schema_name")) ):

from sqlalchemy import Enum # and some other things

class SavedJobs(CinexBase):
    __tablename__ = 'saved_jobs'
    job_status = Column('job_status', Enum(JobStatusEnum))

class MatchedJobs(CinexBase):
    __tablename__ = 'matched_jobs'
    job_status = Column('job_status', Enum(JobStatusEnum))

The graphene setup:

class SavedJobsType(SQLAlchemyObjectType):
    class Meta:
        model = SavedJobs
        interfaces = (graphene.relay.Node,)

class MatchedJobsType(SQLAlchemyObjectType):
    class Meta:
        model = MatchedJobs
        interfaces = (graphene.relay.Node,)

Query Class (I have a custom object that adds authentication logic and filtering as a result on top of the graphene-sqlalchemy-filter library though this library simply extends the usage of core graphene-sqlalchemy objects by adding filters. Let me know if y'all think this may be the culprit (https://github.com/art1415926535/graphene-sqlalchemy-filter):

class Query(graphene.ObjectType):
   matched_jobs = AuthModifiedFilterableConnectionField(MatchedJobsType.connection, filters=MatchedJobsFilter())
   saved_jobs = AuthModifiedFilterableConnectionField(SavedJobsType.connection, filters=SavedJobsFilter())

Would appreciate any help. The way I've gotten around this is creating an extra enum class with a slightly different name as such:

class SavedJobs(CinexBase):
    __tablename__ = 'saved_jobs'
    job_status = Column('job_status', Enum(JobStatusEnum))

class MatchedJobs(CinexBase):
    __tablename__ = 'matched_jobs'
    job_status = Column('job_status', Enum(JobStatusEnum2))

Though this solution seems impractical as I would be expected to create multiple copies of the same enum for potentially 5+ tables and attempt to maintain a universal set of options. Defeats the purpose of the enum IMO.

Thanks in advance would love any direction here!

@chrisberks
Copy link
Contributor

chrisberks commented Mar 28, 2021

Create a GraphQL Interface (JobStatusable) that includes the jobStatus field, explicitly specifying the enum type.

Now have both SavedJob and MatchedJob implement it.

# models.py
import enum

class JobStatus(enum.Enum):
    MATCHED = 1
    INTERESTED = 2
    CLOSED = 3
    MATCH_REJECTED = 4

class SavedJob(CinexBase):
    __tablename__ = 'saved_jobs'
    job_status = Column('job_status', Enum(JobStatus))

class MatchedJob(CinexBase):
    __tablename__ = 'matched_jobs'
    job_status = Column('job_status', Enum(JobStatus))
# schema.py
from models import JobStatus
from models import MatchedJob as MatchedJobModel
from models import SavedJob as SavedJobModel

JobStatusEnum = graphene.Enum.from_enum(JobStatus)

class JobStatusable(graphene.Interface):
    job_status = JobStatusEnum()

class SavedJob(SQLAlchemyObjectType):
    class Meta:
        model = SavedJobModel
        interfaces = (graphene.relay.Node, JobStatusable)

class MatchedJob(SQLAlchemyObjectType):
    class Meta:
        model = MatchedJobModel
        interfaces = (graphene.relay.Node, JobStatusable)

@ShantanuJoshi
Copy link
Author

Thanks @chrisberks! This approach worked for me!

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related topics referencing this issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants