Commit ab690172 authored by Dylan Jones's avatar Dylan Jones

move where.model.sa -> where.model

parent a19386b0
......@@ -19,7 +19,8 @@ fileConfig(config.config_file_name)
# target_metadata = mymodel.Base.metadata
import sys, os
sys.path.append(os.getcwd())
from where.model.sa import Base
from where.model import Base
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,
......
from flask import Flask, redirect, jsonify, abort, request, url_for, Response, make_response
from werkzeug.datastructures import Headers
from flask import Flask, redirect, jsonify, abort, request, url_for, make_response
from where.model import with_session, Point, Category, Field
from where.model.field_types import FieldType
from where.model.sa import Category, Point, Field, with_session
app = Flask(__name__)
......@@ -23,7 +22,6 @@ def index():
@app.route('/test_data')
@with_session
def test_data(session):
# session = Session()
session.query(Point).delete()
session.query(Field).delete()
session.query(Category).delete()
......@@ -95,7 +93,6 @@ def test_data(session):
"value": True
}
}
session.add(fn)
session.commit()
......@@ -127,8 +124,8 @@ def get_point(session, id):
def add_point(session):
allowed_params = {'name', 'lat', 'lon', 'attributes', 'category_id', 'parent_id'}
data = request.get_json()
data = {key:val for key, val in data.items() if key in allowed_params}
data = {key: val for key, val in data.items() if key in allowed_params}
# TODO: For some reason point.category is NULL when we do validation, even though the category ID is present
# this is causing an exception whenever a non-null attributes object is passed
point = Point(category_id=data.pop('category_id'))
......@@ -147,7 +144,7 @@ def add_point(session):
@with_session
def search_points(session):
q = session.query(Point)
if 'category_id' in request.args:
q = q.filter(Point.category_id == request.args.get('category_id'))
......@@ -158,4 +155,4 @@ def search_points(session):
if __name__ == '__main__':
app.run()
\ No newline at end of file
app.run()
from contextlib import contextmanager
from sqlalchemy import Column, Integer, String, Float, JSON, ForeignKey, Enum
from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import relationship, validates
from .field_types import FieldType
from .meta import Session, engine
@contextmanager
def session_context():
session = Session()
try:
yield session
session.commit()
except BaseException:
session.rollback()
raise
finally:
session.close()
def with_session(func):
"""
Decorator for convenience when building endpoints. The first argument to the
decorated function will be a safe-to-use, autocommitting Session instance.
:param func: the view function to wrap
:return: the wrapped function
"""
def wrapper(*args, **kwargs):
with session_context() as session:
return func(session, *args, **kwargs)
# Flask identifies endpoint handlers based on their name
wrapper.__name__ = func.__name__
return wrapper
@as_declarative()
class Base(object):
pass
class Point(Base):
"""
Represents actual instances of any and all points on the map.
"""
__tablename__ = 'point'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=True)
lat = Column(Float, nullable=False)
lon = Column(Float, nullable=False)
attributes = Column(JSON, nullable=False)
# Relationships
category_id = Column(Integer, ForeignKey('category.id'), nullable=False)
category = relationship('Category')
parent_id = Column(Integer, ForeignKey('point.id'), nullable=True)
parent = relationship('Point', remote_side=[id])
children = relationship('Point')
@validates('attributes')
def validate_data(self, _, data):
if data is None:
return
fields = self.category.fields
for key in data:
# Find Field object that corresponds to this key
for field in fields:
if field.slug == key:
break
else:
raise ValueError(f'extra data "{key}" must be a registered field')
field.validate_data(data[key])
return data
def as_json(self, children=True):
if children:
children = [child.as_json(children=False) for child in self.children]
return {
"name": self.name,
"lat": self.lat,
"lon": self.lon,
"category": self.category.id,
"attributes": self.attributes,
"children": children
}
class Category(Base):
"""
Represent a schema for a single category of objects (e.g. water fountain or bathroom)
"""
__tablename__ = 'category'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False, unique=True)
icon = Column(String, nullable=True)
fields = relationship("Field")
def as_json(self):
return {
"id": self.id,
"name": self.name,
"icon": self.icon,
"attributes": {attr.slug: attr.as_json() for attr in self.fields}
}
class Field(Base):
"""
Represents a single field in the Category schema.
"""
__tablename__ = 'field'
id = Column(Integer, primary_key=True, autoincrement=True)
slug = Column(String, nullable=False)
name = Column(String, nullable=False)
type = Column(Enum(FieldType), nullable=False)
# Relationship
category_id = Column(Integer, ForeignKey('category.id'))
def validate_data(self, data):
"""
Verify that data is the correct type for this Field.
"""
self.type.validate(data)
def as_json(self):
return {
"slug": self.slug,
"name": self.name,
"type": self.type.name
}
# uh putting this here doesn't feel right but there's not anything *too* wrong with it
Base.metadata.create_all(engine)
from contextlib import contextmanager
from sqlalchemy import String, ForeignKey, Enum, Integer, Float, JSON
from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import relationship, validates
from sqlalchemy.schema import Column
from .field_types import FieldType
from .meta import Session, engine
@contextmanager
def session_context():
session = Session()
try:
yield session
session.commit()
except BaseException:
session.rollback()
raise
finally:
session.close()
# Decorator for convenience when building endpoints
def with_session(func):
def wrapper(*args, **kwargs):
with session_context() as session:
return func(session, *args, **kwargs)
# Flask identifies endpoint handlers based on their name
wrapper.__name__ = func.__name__
return wrapper
@as_declarative()
class Base(object):
pass
class Point(Base):
"""
Represents actual instances of any and all points on the map.
"""
__tablename__ = 'point'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=True)
lat = Column(Float, nullable=False)
lon = Column(Float, nullable=False)
attributes = Column(JSON, nullable=False)
# Relationships
category_id = Column(Integer, ForeignKey('category.id'), nullable=False)
category = relationship('Category')
parent_id = Column(Integer, ForeignKey('point.id'), nullable=True)
parent = relationship('Point', remote_side=[id])
children = relationship('Point')
@validates('attributes')
def validate_data(self, _, data):
if data is None:
return
fields = self.category.fields
for key in data:
# Find Field object that corresponds to this key
for field in fields:
if field.slug == key:
break
else:
raise ValueError(f'extra data "{key}" must be a registered field')
field.validate_data(data[key])
return data
def as_json(self, children=True):
if children:
children = [child.as_json(children=False) for child in self.children]
return {
"name": self.name,
"lat": self.lat,
"lon": self.lon,
"category": self.category.id,
"attributes": self.attributes,
"children": children
}
class Category(Base):
"""
Represent a schema for a single category of objects (e.g. water fountain or bathroom)
"""
__tablename__ = 'category'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False, unique=True)
icon = Column(String, nullable=True)
fields = relationship("Field")
def as_json(self):
return {
"id": self.id,
"name": self.name,
"icon": self.icon,
"attributes": {attr.slug: attr.as_json() for attr in self.fields}
}
class Field(Base):
"""
Represents a single field in the Category schema.
"""
__tablename__ = 'field'
id = Column(Integer, primary_key=True, autoincrement=True)
slug = Column(String, nullable=False)
name = Column(String, nullable=False)
type = Column(Enum(FieldType), nullable=False)
# Relationship
category_id = Column(Integer, ForeignKey('category.id'))
def validate_data(self, data):
"""
Verify that data is the correct type for this Field.
"""
self.type.validate(data)
def as_json(self):
return {
"slug": self.slug,
"name": self.name,
"type": self.type.name
}
# uh putting this here doesn't feel right but there's not anything *too* wrong with it
Base.metadata.create_all(engine)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment