Skip to content

Commit 1247b46

Browse files
authored
Merge pull request #47 from john-dupuy/add-migration-script
Update the migration script to work with new psql db
2 parents d677143 + 09e8b6c commit 1247b46

13 files changed

+478
-84
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ repos:
2727
hooks:
2828
- id: flake8
2929
language_version: python3
30-
args: [--max-line-length, "100"]
30+
args: [--max-line-length, "100", --ignore, "E203"]
3131
- repo: https://github.com/asottile/pyupgrade
3232
rev: v2.6.1
3333
hooks:

backend/ibutsu_server/controllers/artifact_controller.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from datetime import datetime
23

34
import connexion
45
import magic
@@ -119,6 +120,7 @@ def upload_artifact(body):
119120
filename=filename,
120121
result_id=data["resultId"],
121122
content=file_.read(),
123+
upload_date=datetime.utcnow(),
122124
data=additional_metadata,
123125
)
124126
session.add(artifact)

backend/ibutsu_server/controllers/result_controller.py

+38-26
Original file line numberDiff line numberDiff line change
@@ -81,41 +81,53 @@ def get_result_list(filter_=None, page=1, page_size=25, apply_max=False):
8181
:rtype: List[Result]
8282
"""
8383
query = Result.query
84+
count_estimate = None
8485
if filter_:
8586
for filter_string in filter_:
8687
filter_clause = convert_filter(filter_string, Result)
8788
if filter_clause is not None:
8889
query = query.filter(filter_clause)
90+
else:
91+
# use a count estimate when no filter is applied
92+
count_estimate = int(
93+
session.execute(
94+
"SELECT reltuples as approx_count FROM pg_class WHERE relname='results'"
95+
).fetchall()[0][0]
96+
)
97+
8998
offset = (page * page_size) - page_size
90-
try:
91-
# if the count is fast, just use it! Even if apply_max is set to true
92-
session.execute(f"SET statement_timeout TO {int(COUNT_TIMEOUT*1000)}; commit;")
93-
total_items = query.count()
94-
except OperationalError:
95-
# reset the timeout if we hit an exception
96-
session.execute("SET statement_timeout TO 0; commit;")
97-
if apply_max:
98-
print(
99-
f"FunctionTimedOut: 'query.count' with filters: {filter_} timed out, "
100-
f"using default items of {MAX_DOCUMENTS}"
101-
)
102-
if offset > MAX_DOCUMENTS:
103-
raise ValueError(
104-
f"Offset: {offset} exceeds the "
105-
f"MAX_DOCUMENTS: {MAX_DOCUMENTS} able to be displayed in the UI. "
106-
f"Please use the API for this request."
99+
if not count_estimate:
100+
try:
101+
# if the count is fast, just use it! Even if apply_max is set to true
102+
session.execute(f"SET statement_timeout TO {int(COUNT_TIMEOUT*1000)}; commit;")
103+
total_items = query.count()
104+
except OperationalError:
105+
# reset the timeout if we hit an exception
106+
session.execute("SET statement_timeout TO 0; commit;")
107+
if apply_max:
108+
print(
109+
f"FunctionTimedOut: 'query.count' with filters: {filter_} timed out, "
110+
f"using default items of {MAX_DOCUMENTS}"
107111
)
108-
total_items = MAX_DOCUMENTS
112+
if offset > MAX_DOCUMENTS:
113+
raise ValueError(
114+
f"Offset: {offset} exceeds the "
115+
f"MAX_DOCUMENTS: {MAX_DOCUMENTS} able to be displayed in the UI. "
116+
f"Please use the API for this request."
117+
)
118+
total_items = MAX_DOCUMENTS
119+
else:
120+
print(
121+
f"FunctionTimedOut: 'query.count' with args: {filter_} timed out, "
122+
f"but limit_documents is set to False, proceeding"
123+
)
124+
# if we don't want to limit documents, just do the standard count
125+
total_items = query.count()
109126
else:
110-
print(
111-
f"FunctionTimedOut: 'query.count' with args: {filter_} timed out, "
112-
f"but limit_documents is set to False, proceeding"
113-
)
114-
# if we don't want to limit documents, just do the standard count
115-
total_items = query.count()
127+
# reset the timeout if we don't hit an exception
128+
session.execute("SET statement_timeout TO 0; commit;")
116129
else:
117-
# reset the timeout if we don't hit an exception
118-
session.execute("SET statement_timeout TO 0; commit;")
130+
total_items = count_estimate
119131

120132
total_pages = (total_items // page_size) + (1 if total_items % page_size > 0 else 0)
121133
results = query.order_by(Result.start_time.desc()).offset(offset).limit(page_size).all()

backend/ibutsu_server/controllers/widget_config_controller.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def get_widget_config_list(filter_=None, page=1, page_size=25):
7676
offset = (page * page_size) - page_size
7777
total_items = query.count()
7878
total_pages = (total_items // page_size) + (1 if total_items % page_size > 0 else 0)
79-
widgets = query.order_by(WidgetConfig.weight.desc()).offset(offset).limit(page_size)
79+
widgets = query.order_by(WidgetConfig.weight.asc()).offset(offset).limit(page_size)
8080
return {
8181
"widgets": [widget.to_dict() for widget in widgets],
8282
"pagination": {

backend/ibutsu_server/db/models.py

+46-44
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from datetime import datetime
12
from uuid import uuid4
23

34
from ibutsu_server.db.base import Boolean
@@ -65,38 +66,39 @@ def to_dict(self):
6566

6667
class Artifact(Model, FileMixin):
6768
__tablename__ = "artifacts"
68-
result_id = Column(PortableUUID(), ForeignKey("results.id"), nullable=False)
69-
filename = Column(Text)
69+
result_id = Column(PortableUUID(), ForeignKey("results.id"), nullable=False, index=True)
70+
filename = Column(Text, index=True)
7071
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
72+
upload_date = Column(DateTime, default=datetime.utcnow, index=True)
7173

7274

7375
class Group(Model, ModelMixin):
7476
__tablename__ = "groups"
75-
name = Column(Text)
77+
name = Column(Text, index=True)
7678
projects = relationship("Project")
7779
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
7880

7981

8082
class Import(Model, ModelMixin):
8183
__tablename__ = "imports"
8284
file = relationship("ImportFile")
83-
filename = Column(Text)
84-
format = Column(Text)
85+
filename = Column(Text, index=True)
86+
format = Column(Text, index=True)
8587
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
86-
status = Column(Text)
88+
status = Column(Text, index=True)
8789

8890

8991
class ImportFile(Model, FileMixin):
9092
__tablename__ = "import_files"
91-
import_id = Column(PortableUUID(), ForeignKey("imports.id"), nullable=False)
93+
import_id = Column(PortableUUID(), ForeignKey("imports.id"), nullable=False, index=True)
9294

9395

9496
class Project(Model, ModelMixin):
9597
__tablename__ = "projects"
96-
name = Column(Text)
97-
title = Column(Text)
98-
owner_id = Column(Text)
99-
group_id = Column(PortableUUID(), ForeignKey("groups.id"))
98+
name = Column(Text, index=True)
99+
title = Column(Text, index=True)
100+
owner_id = Column(Text, index=True)
101+
group_id = Column(PortableUUID(), ForeignKey("groups.id"), index=True)
100102
reports = relationship("Report")
101103
results = relationship("Result")
102104
runs = relationship("Run")
@@ -105,64 +107,64 @@ class Project(Model, ModelMixin):
105107

106108
class Report(Model, ModelMixin):
107109
__tablename__ = "reports"
108-
created = Column(DateTime)
109-
download_url = Column(Text)
110-
filename = Column(Text)
111-
mimetype = Column(Text)
112-
name = Column(Text)
110+
created = Column(DateTime, default=datetime.utcnow, index=True)
111+
download_url = Column(Text, index=True)
112+
filename = Column(Text, index=True)
113+
mimetype = Column(Text, index=True)
114+
name = Column(Text, index=True)
113115
params = Column(mutable_json_type(dbtype=PortableJSON()))
114-
project_id = Column(PortableUUID(), ForeignKey("projects.id"))
116+
project_id = Column(PortableUUID(), ForeignKey("projects.id"), index=True)
115117
file = relationship("ReportFile")
116-
status = Column(Text)
117-
url = Column(Text)
118-
view_url = Column(Text)
118+
status = Column(Text, index=True)
119+
url = Column(Text, index=True)
120+
view_url = Column(Text, index=True)
119121

120122

121123
class ReportFile(Model, FileMixin):
122124
__tablename__ = "report_files"
123-
report_id = Column(PortableUUID(), ForeignKey("reports.id"), nullable=False)
124-
filename = Column(Text)
125+
report_id = Column(PortableUUID(), ForeignKey("reports.id"), nullable=False, index=True)
126+
filename = Column(Text, index=True)
125127
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
126128

127129

128130
class Result(Model, ModelMixin):
129131
__tablename__ = "results"
130132
artifacts = relationship("Artifact")
131-
component = Column(Text)
133+
component = Column(Text, index=True)
132134
# this is metadata but it is a reserved attr
133135
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
134-
duration = Column(Float)
135-
env = Column(Text)
136+
duration = Column(Float, index=True)
137+
env = Column(Text, index=True)
136138
params = Column(mutable_json_type(dbtype=PortableJSON()))
137-
project_id = Column(PortableUUID(), ForeignKey("projects.id"))
138-
result = Column(Text)
139-
run_id = Column(PortableUUID(), ForeignKey("runs.id"))
140-
source = Column(Text)
141-
start_time = Column(DateTime)
142-
test_id = Column(Text)
139+
project_id = Column(PortableUUID(), ForeignKey("projects.id"), index=True)
140+
result = Column(Text, index=True)
141+
run_id = Column(PortableUUID(), ForeignKey("runs.id"), index=True)
142+
source = Column(Text, index=True)
143+
start_time = Column(DateTime, default=datetime.utcnow, index=True)
144+
test_id = Column(Text, index=True)
143145

144146

145147
class Run(Model, ModelMixin):
146148
__tablename__ = "runs"
147-
component = Column(Text)
148-
created = Column(DateTime)
149+
component = Column(Text, index=True)
150+
created = Column(DateTime, default=datetime.utcnow, index=True)
149151
# this is metadata but it is a reserved attr
150152
data = Column(mutable_json_type(dbtype=PortableJSON(), nested=True))
151-
duration = Column(Float)
152-
env = Column(Text)
153-
project_id = Column(PortableUUID(), ForeignKey("projects.id"))
153+
duration = Column(Float, index=True)
154+
env = Column(Text, index=True)
155+
project_id = Column(PortableUUID(), ForeignKey("projects.id"), index=True)
154156
results = relationship("Result")
155-
source = Column(Text)
156-
start_time = Column(DateTime)
157+
source = Column(Text, index=True)
158+
start_time = Column(DateTime, default=datetime.utcnow, index=True)
157159
summary = Column(mutable_json_type(dbtype=PortableJSON()))
158160

159161

160162
class WidgetConfig(Model, ModelMixin):
161163
__tablename__ = "widget_configs"
162-
navigable = Column(Boolean)
164+
navigable = Column(Boolean, index=True)
163165
params = Column(mutable_json_type(dbtype=PortableJSON()))
164-
project_id = Column(PortableUUID(), ForeignKey("projects.id"))
165-
title = Column(Text)
166-
type = Column(Text)
167-
weight = Column(Integer)
168-
widget = Column(Text)
166+
project_id = Column(PortableUUID(), ForeignKey("projects.id"), index=True)
167+
title = Column(Text, index=True)
168+
type = Column(Text, index=True)
169+
weight = Column(Integer, index=True)
170+
widget = Column(Text, index=True)

backend/ibutsu_server/filters.py

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def string_to_column(field, model):
2626
if idx == 0:
2727
continue
2828
column = column[part]
29+
if field not in ARRAY_FIELDS:
30+
column = column.as_string()
2931
else:
3032
column = getattr(model, field)
3133
return column

0 commit comments

Comments
 (0)