Merge pull request #209 from karec/master

Add postgresql dialects for sqlachemy
This commit is contained in:
Syrus Akbary 2016-06-25 09:29:59 -07:00 committed by GitHub
commit b5b66326a7
5 changed files with 67 additions and 2 deletions

View File

@ -1,7 +1,7 @@
from flask import Flask from flask import Flask
from database import db_session, init_db from database import db_session, init_db
from flask_graphql import GraphQL from flask_graphql import GraphQLView
from schema import schema from schema import schema
app = Flask(__name__) app = Flask(__name__)
@ -27,7 +27,7 @@ default_query = '''
} }
}'''.strip() }'''.strip()
GraphQL(app, schema=schema, default_query=default_query) app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))
@app.teardown_appcontext @app.teardown_appcontext

View File

@ -34,5 +34,12 @@ def init_db():
roy = Employee(name='Roy', department=engineering, role=engineer) roy = Employee(name='Roy', department=engineering, role=engineer)
db_session.add(roy) db_session.add(roy)
tracy = Employee(name='Tracy', department=hr, role=manager) tracy = Employee(name='Tracy', department=hr, role=manager)
# postgresql specific dialects tests
# tracy.articles = [1, 2, 3, 4]
# tracy.json_data = {"test_json": "test_json"}
# tracy.jsonb_data = {"test_jsonb": "test_jsonb"}
# tracy.hstore_data = {"test_hstore": "test_hstore"}
db_session.add(tracy) db_session.add(tracy)
db_session.commit() db_session.commit()

View File

@ -1,6 +1,11 @@
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, func from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, func
from sqlalchemy.orm import backref, relationship from sqlalchemy.orm import backref, relationship
# Uncomment import below for postgresql tests
# import uuid
# from sqlalchemy.dialects.postgresql import UUID, ENUM, JSON, JSONB, HSTORE, ARRAY
# from sqlalchemy.sql.expression import text
from database import Base from database import Base
@ -26,6 +31,15 @@ class Employee(Base):
hired_on = Column(DateTime, default=func.now()) hired_on = Column(DateTime, default=func.now())
department_id = Column(Integer, ForeignKey('department.id')) department_id = Column(Integer, ForeignKey('department.id'))
role_id = Column(Integer, ForeignKey('roles.role_id')) role_id = Column(Integer, ForeignKey('roles.role_id'))
# Uncomment below for postgresql specific fields testing
# uuid = Column(UUID(), server_default=text("uuid_generate_v4()"))
# is_active = Column(ENUM('Yes', 'No', name='is_active'), default="Yes")
# json_data = Column(JSON())
# jsonb_data = Column(JSONB())
# hstore_data = Column(HSTORE())
# articles = Column(ARRAY(Integer))
# Use cascade='delete,all' to propagate the deletion of a Department onto its Employees # Use cascade='delete,all' to propagate the deletion of a Department onto its Employees
department = relationship( department = relationship(
Department, Department,

View File

@ -1,9 +1,12 @@
from singledispatch import singledispatch from singledispatch import singledispatch
from sqlalchemy import types from sqlalchemy import types
from sqlalchemy.orm import interfaces from sqlalchemy.orm import interfaces
from sqlalchemy.dialects import postgresql
from ...core.classtypes.enum import Enum from ...core.classtypes.enum import Enum
from ...core.types.scalars import ID, Boolean, Float, Int, String from ...core.types.scalars import ID, Boolean, Float, Int, String
from ...core.types.definitions import List
from ...core.types.custom_scalars import JSONString
from .fields import ConnectionOrListField, SQLAlchemyModelField from .fields import ConnectionOrListField, SQLAlchemyModelField
try: try:
@ -42,6 +45,8 @@ def convert_sqlalchemy_type(type, column):
@convert_sqlalchemy_type.register(types.Unicode) @convert_sqlalchemy_type.register(types.Unicode)
@convert_sqlalchemy_type.register(types.UnicodeText) @convert_sqlalchemy_type.register(types.UnicodeText)
@convert_sqlalchemy_type.register(types.Enum) @convert_sqlalchemy_type.register(types.Enum)
@convert_sqlalchemy_type.register(postgresql.ENUM)
@convert_sqlalchemy_type.register(postgresql.UUID)
def convert_column_to_string(type, column): def convert_column_to_string(type, column):
return String(description=column.doc) return String(description=column.doc)
@ -71,3 +76,16 @@ def convert_column_to_float(type, column):
def convert_column_to_enum(type, column): def convert_column_to_enum(type, column):
name = '{}_{}'.format(column.table.name, column.name).upper() name = '{}_{}'.format(column.table.name, column.name).upper()
return Enum(name, type.choices, description=column.doc) return Enum(name, type.choices, description=column.doc)
@convert_sqlalchemy_type.register(postgresql.ARRAY)
def convert_postgres_array_to_list(type, column):
graphene_type = convert_sqlalchemy_type(column.type.item_type, column)
return List(graphene_type, description=column.doc)
@convert_sqlalchemy_type.register(postgresql.HSTORE)
@convert_sqlalchemy_type.register(postgresql.JSON)
@convert_sqlalchemy_type.register(postgresql.JSONB)
def convert_json_to_string(type, column):
return JSONString(description=column.doc)

View File

@ -2,8 +2,10 @@ from py.test import raises
from sqlalchemy import Column, Table, types from sqlalchemy import Column, Table, types
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utils.types.choice import ChoiceType from sqlalchemy_utils.types.choice import ChoiceType
from sqlalchemy.dialects import postgresql
import graphene import graphene
from graphene.core.types.custom_scalars import JSONString
from graphene.contrib.sqlalchemy.converter import (convert_sqlalchemy_column, from graphene.contrib.sqlalchemy.converter import (convert_sqlalchemy_column,
convert_sqlalchemy_relationship) convert_sqlalchemy_relationship)
from graphene.contrib.sqlalchemy.fields import (ConnectionOrListField, from graphene.contrib.sqlalchemy.fields import (ConnectionOrListField,
@ -122,3 +124,27 @@ def test_should_onetomany_convert_model():
assert isinstance(graphene_type, ConnectionOrListField) assert isinstance(graphene_type, ConnectionOrListField)
assert isinstance(graphene_type.type, SQLAlchemyModelField) assert isinstance(graphene_type.type, SQLAlchemyModelField)
assert graphene_type.type.model == Article assert graphene_type.type.model == Article
def test_should_postgresql_uuid_convert():
assert_column_conversion(postgresql.UUID(), graphene.String)
def test_should_postgresql_enum_convert():
assert_column_conversion(postgresql.ENUM(), graphene.String)
def test_should_postgresql_array_convert():
assert_column_conversion(postgresql.ARRAY(types.Integer), graphene.List)
def test_should_postgresql_json_convert():
assert_column_conversion(postgresql.JSON(), JSONString)
def test_should_postgresql_jsonb_convert():
assert_column_conversion(postgresql.JSONB(), JSONString)
def test_should_postgresql_hstore_convert():
assert_column_conversion(postgresql.HSTORE(), JSONString)