Skip to content

Commit 29187d0

Browse files
Added get/create endpoints, relationships now have same names as in blueprints
1 parent 5b216e3 commit 29187d0

8 files changed

Lines changed: 87 additions & 32 deletions

File tree

data/study.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"name": "case1",
66
"type": "AppModels:signals_simple/Case",
77
"description": "",
8+
"newAttribute": 32,
89
"duration": 100,
910
"timeStep": 0.1,
1011
"components": [

models/signals_simple/Case.blueprint.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
"name": "duration",
2626
"type": "CORE:BlueprintAttribute",
2727
"attributeType": "number"
28+
},
29+
{
30+
"name": "newAttribute",
31+
"type": "CORE:BlueprintAttribute",
32+
"attributeType": "number"
2833
},
2934
{
3035
"name": "timeStep",

plugin/api.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
@router.get('/{id}', response_model=Any)
18-
def get_data_by_id(id: UUID, table: str = None, levels: int = 1, all: bool = False,
18+
def get_data_by_id(id: UUID, table: str = None, levels: int = 1, all_data: bool = False,
1919
session: Session = Depends(get_db_session)):
2020
engine = session.get_bind()
2121
metadata_obj = MetaData()
@@ -36,14 +36,15 @@ def get_data_by_id(id: UUID, table: str = None, levels: int = 1, all: bool = Fal
3636
result = session.execute(query).first()
3737
if result:
3838
for root, _, files in os.walk(os.path.join(os.path.dirname(__file__), '..', 'models')):
39+
3940
if f'{table}.blueprint.json' in files:
4041
# Resolve model from table
4142
bp = Blueprint.from_json(os.path.join(root, table))
4243
model = resolve_model(bp)
4344

4445
# Get top level data
4546
parent_alias = aliased(model)
46-
if all:
47+
if all_data:
4748
#Fetches parent and all children to bottom
4849
parent_alias = aliased(model)
4950
return jsonable_encoder((
@@ -76,3 +77,68 @@ def get_data_by_id(id: UUID, table: str = None, levels: int = 1, all: bool = Fal
7677
break
7778
return jsonable_encoder(top)
7879
raise HTTPException(status_code=404, detail=f"Could not find ID {id}")
80+
81+
82+
@router.post('/', response_model=Any)
83+
def create_entity(entity: dict, return_all: bool = False, session: Session = Depends(get_db_session)):
84+
def create_entity_recursive(entity, is_toplevel, session):
85+
try:
86+
table = entity['type'].rsplit('/')[1]
87+
except AttributeError:
88+
HTTPException(status_code=400, detail=f"Invalid input, BP should be available as attribute: type")
89+
for root, _, files in os.walk(os.path.join(os.path.dirname(__file__), '..', 'models')):
90+
if f'{table}.blueprint.json' in files:
91+
# Resolve model from table
92+
bp = Blueprint.from_json(os.path.join(root, table))
93+
model = resolve_model(bp)
94+
95+
data_table = {}
96+
children = []
97+
children_rel_names = []
98+
data = dict()
99+
for key, value in entity.items():
100+
attr = [attr for attr in bp.attributes if attr.name == key][0]
101+
if attr.name == 'type':
102+
continue
103+
if attr.attributeType.lower() in ["string", "integer", "number", "float", "boolean", "foreign_key", "type",
104+
"core:blueprintattribute"]:
105+
if hasattr(attr, 'dimensions') and attr.dimensions == '*':
106+
data_table[key] = value
107+
else:
108+
data[key] = value
109+
else:
110+
if isinstance(value, list):
111+
children.extend(value)
112+
[children_rel_names.append(key) for _ in value]
113+
elif isinstance(value, dict):
114+
children.append(value)
115+
children_rel_names.append(key)
116+
else:
117+
raise NotImplementedError(f'Type {type(value)} not supported yet')
118+
119+
obj_in_data = jsonable_encoder(data)
120+
db_obj = model(**obj_in_data)
121+
for child, rel_name in zip(children, children_rel_names):
122+
child_obj = create_entity_recursive(child, False, session)
123+
getattr(db_obj, rel_name).append(child_obj)
124+
125+
for key, value in data_table.items():
126+
data_table_model = resolve_model(bp, key)
127+
data_table_objects = [data_table_model(data=item) for item in value]
128+
getattr(db_obj, key).extend(data_table_objects)
129+
130+
session.add(db_obj)
131+
session.commit()
132+
session.refresh(db_obj)
133+
if is_toplevel:
134+
return jsonable_encoder(db_obj)
135+
else:
136+
return db_obj
137+
138+
HTTPException(status_code=404, detail=f"Could not find Blueprint {table}")
139+
new_obj = create_entity_recursive(entity, True, session)
140+
#Re-use get_endpoint to fetch all nested objects
141+
if return_all:
142+
new_id = create_entity_recursive(entity, True, session)['id']
143+
return get_data_by_id(id=new_id, all_data=True, session=session)
144+
return new_obj

plugin/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ class Config(BaseSettings):
77
"""
88
Application configuration
99
"""
10-
SQLALCHEMY_DATABASE_URI: str = Field(' ', validation_alias='SQLALCHEMY_DATABASE_URI')
10+
SQLALCHEMY_DATABASE_URI: str = Field('', validation_alias='SQLALCHEMY_DATABASE_URI')

plugin/crud/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def create_entity(db: Session, entity: dict, commit=True) -> dict:
1313

1414
data_table = {}
1515
children = []
16+
children_rel_names = []
1617
data = dict()
1718
for key, value in entity.items():
1819
attr = [attr for attr in bp.attributes if attr.name == key][0]
@@ -27,17 +28,19 @@ def create_entity(db: Session, entity: dict, commit=True) -> dict:
2728
else:
2829
if isinstance(value, list):
2930
children.extend(value)
31+
[children_rel_names.append(key) for _ in value]
3032
elif isinstance(value, dict):
3133
children.append(value)
34+
children_rel_names.append(key)
3235
else:
3336
raise NotImplementedError(f'Type {type(value)} not supported yet')
3437

3538
obj_in_data = jsonable_encoder(data)
3639
db_obj = model(**obj_in_data)
3740

38-
for child in children:
41+
for child, rel_name in zip(children, children_rel_names):
3942
child_obj = create_entity(db, child, commit=True)
40-
getattr(db_obj, f'{child_obj.__table__.key}_s').append(child_obj)
43+
getattr(db_obj, rel_name).append(child_obj)
4144

4245
for key, value in data_table.items():
4346
data_table_model = resolve_model(bp, key)

plugin/database.py

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,17 @@
33
from config import Config
44
from plugin import models
55

6-
76
engine = None
87

98

10-
def init_engine(config=Config(), **kwargs):
11-
"""Initiate database engine."""
12-
global engine
13-
engine = create_engine(config.SQLALCHEMY_DATABASE_URI, **kwargs)
14-
return engine
15-
16-
179
def get_db_session():
1810
"""
1911
Create an independent database session/connection per request. Use the same session through all the request and
2012
then close it after the request is finished.
2113
"""
22-
session_factory = sessionmaker(autocommit=False, autoflush=False, bind=init_engine())
23-
session = session_factory()
24-
try:
25-
yield session
26-
finally:
27-
session.close()
28-
14+
config = Config()
15+
engine = create_engine(config.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True, executemany_mode="values_plus_batch")
16+
models.Base.metadata.create_all(bind=engine)
2917

30-
# def get_db_session(config=Config()):
31-
# """
32-
# Create an independent database session/connection per request. Use the same session through all the request and
33-
# then close it after the request is finished.
34-
# """
35-
# engine = create_engine(config.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True, executemany_mode="values_plus_batch")
36-
# models.Base.metadata.create_all(bind=engine)
37-
#
38-
# with Session(engine) as session:
39-
# return session
18+
with Session(engine) as session:
19+
return session

plugin/dev2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#initialize_database
77
#base_folder = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', "models"))
8-
initialize_database(base_folder=base_folder)
8+
#initialize_database(base_folder=base_folder)
99

1010

1111
# fill with data

plugin/models/blueprint_handling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def generate_models_m2m_rel(self, parent: str = None):
102102
children.append(child_blueprint)
103103
child_name = child_blueprint.name
104104
# todo: cascade delete on contained = True
105-
class_attributes[f'{child_name}_s'] = relationship(child_name,
105+
class_attributes[f'{attr_name}'] = relationship(child_name,
106106
secondary=f'{self.name}_{child_name}_map',
107107
cascade="all,delete")
108108
if parent:

0 commit comments

Comments
 (0)