Merge pull request #254 from sartography/bug/225_enum_lookup_same_field_name

Bug/225 enum lookup same field name
This commit is contained in:
Dan Funk 2021-03-02 14:55:47 -05:00 committed by GitHub
commit 7d97fe107d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 279 additions and 60 deletions

View File

@ -954,7 +954,7 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
/workflow/{workflow_id}/lookup/{field_id}:
/workflow/{workflow_id}/lookup/{task_spec_name}/{field_id}:
parameters:
- name: workflow_id
in: path
@ -963,6 +963,12 @@ paths:
schema:
type: integer
format: int32
- name: task_spec_name
in: path
required: true
description: The name of the current task
schema:
type: string
- name: field_id
in: path
required: true

View File

@ -252,7 +252,7 @@ def delete_workflow_spec_category(cat_id):
session.commit()
def lookup(workflow_id, field_id, query=None, value=None, limit=10):
def lookup(workflow_id, task_spec_name, field_id, query=None, value=None, limit=10):
"""
given a field in a task, attempts to find the lookup table or function associated
with that field and runs a full-text query against it to locate the values and
@ -260,7 +260,7 @@ def lookup(workflow_id, field_id, query=None, value=None, limit=10):
Tries to be fast, but first runs will be very slow.
"""
workflow = session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first()
lookup_data = LookupService.lookup(workflow, field_id, query, value, limit)
lookup_data = LookupService.lookup(workflow, task_spec_name, field_id, query, value, limit)
return LookupDataSchema(many=True).dump(lookup_data)

View File

@ -148,6 +148,7 @@ class LookupFileModel(db.Model):
__tablename__ = 'lookup_file'
id = db.Column(db.Integer, primary_key=True)
workflow_spec_id = db.Column(db.String)
task_spec_id = db.Column(db.String)
field_id = db.Column(db.String)
is_ldap = db.Column(db.Boolean) # Allows us to run an ldap query instead of a db lookup.
file_data_model_id = db.Column(db.Integer, db.ForeignKey('file_data.id'))

View File

@ -40,13 +40,14 @@ class LookupService(object):
def get_lookup_model(spiff_task, field):
workflow_id = spiff_task.workflow.data[WorkflowProcessor.WORKFLOW_ID_KEY]
workflow = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first()
return LookupService.__get_lookup_model(workflow, field.id)
return LookupService.__get_lookup_model(workflow, spiff_task.task_spec.name, field.id)
@staticmethod
def __get_lookup_model(workflow, field_id):
def __get_lookup_model(workflow, task_spec_id, field_id):
lookup_model = db.session.query(LookupFileModel) \
.filter(LookupFileModel.workflow_spec_id == workflow.workflow_spec_id) \
.filter(LookupFileModel.field_id == field_id) \
.filter(LookupFileModel.task_spec_id == task_spec_id) \
.order_by(desc(LookupFileModel.id)).first()
# one more quick query, to see if the lookup file is still related to this workflow.
@ -59,14 +60,15 @@ class LookupService(object):
if not is_current:
# Very very very expensive, but we don't know need this till we do.
lookup_model = LookupService.create_lookup_model(workflow, field_id)
logging.warning("!!!! Making a very expensive call to update the lookup models.")
lookup_model = LookupService.create_lookup_model(workflow, task_spec_id, field_id)
return lookup_model
@staticmethod
def lookup(workflow, field_id, query, value=None, limit=10):
def lookup(workflow, task_spec_id, field_id, query, value=None, limit=10):
lookup_model = LookupService.__get_lookup_model(workflow, field_id)
lookup_model = LookupService.__get_lookup_model(workflow, task_spec_id, field_id)
if lookup_model.is_ldap:
return LookupService._run_ldap_query(query, limit)
@ -74,7 +76,7 @@ class LookupService(object):
return LookupService._run_lookup_query(lookup_model, query, value, limit)
@staticmethod
def create_lookup_model(workflow_model, field_id):
def create_lookup_model(workflow_model, task_spec_id, field_id):
"""
This is all really expensive, but should happen just once (per file change).
@ -84,11 +86,12 @@ class LookupService(object):
Returns: an array of LookupData, suitable for returning to the API.
"""
processor = WorkflowProcessor(workflow_model) # VERY expensive, Ludicrous for lookup / type ahead
spec, field = processor.find_spec_and_field_by_field_id(field_id)
spec, field = processor.find_spec_and_field(task_spec_id, field_id)
# Clear out all existing lookup models for this workflow and field.
existing_models = db.session.query(LookupFileModel) \
.filter(LookupFileModel.workflow_spec_id == workflow_model.workflow_spec_id) \
.filter(LookupFileModel.task_spec_id == task_spec_id) \
.filter(LookupFileModel.field_id == field_id).all()
for model in existing_models: # Do it one at a time to cause the required cascade of deletes.
db.session.delete(model)
@ -117,7 +120,7 @@ class LookupService(object):
data_model = latest_files[0]
lookup_model = LookupService.build_lookup_table(data_model, value_column, label_column,
workflow_model.workflow_spec_id, field_id)
workflow_model.workflow_spec_id, task_spec_id, field_id)
# Use the results of an LDAP request to populate enum field options
elif field.has_property(Task.FIELD_PROP_LDAP_LOOKUP):
@ -134,7 +137,7 @@ class LookupService(object):
return lookup_model
@staticmethod
def build_lookup_table(data_model: FileDataModel, value_column, label_column, workflow_spec_id, field_id):
def build_lookup_table(data_model: FileDataModel, value_column, label_column, workflow_spec_id, task_spec_id, field_id):
""" In some cases the lookup table can be very large. This method will add all values to the database
in a way that can be searched and returned via an api call - rather than sending the full set of
options along with the form. It will only open the file and process the options if something has
@ -153,6 +156,7 @@ class LookupService(object):
lookup_model = LookupFileModel(workflow_spec_id=workflow_spec_id,
field_id=field_id,
task_spec_id=task_spec_id,
file_data_model_id=data_model.id,
is_ldap=False)

View File

@ -473,11 +473,11 @@ class WorkflowProcessor(object):
if nav_item['task_id'] == task.id:
return nav_item
def find_spec_and_field_by_field_id(self, field_id):
def find_spec_and_field(self, spec_name, field_id):
"""Tracks down a form field by name in the workflow spec,
only looks at ready tasks. Returns a tuple of the task, and form"""
for spec in self.bpmn_workflow.spec.task_specs.values():
if hasattr(spec, "form"):
if spec.name == spec_name and hasattr(spec, "form"):
for field in spec.form.fields:
if field.id == field_id:
return spec, field

View File

@ -0,0 +1,31 @@
"""empty message
Revision ID: c872232ebdcb
Revises: f28ee3722c49
Create Date: 2021-03-02 14:35:13.911050
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c872232ebdcb'
down_revision = 'f28ee3722c49'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.execute('delete from lookup_data')
op.execute('delete from lookup_file')
op.add_column('lookup_file', sa.Column('task_spec_id', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('lookup_file', 'task_spec_id')
# ### end Alembic commands ###

View File

@ -25,12 +25,6 @@ def upgrade():
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('approval_file',
sa.Column('approval_id', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('file_data_id', sa.INTEGER(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['approval_id'], ['approval.id'], name='approval_file_approval_id_fkey'),
sa.ForeignKeyConstraint(['file_data_id'], ['file_data.id'], name='approval_file_file_data_id_fkey')
)
op.create_table('approval',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('study_id', sa.INTEGER(), autoincrement=False, nullable=False),
@ -45,4 +39,10 @@ def downgrade():
sa.ForeignKeyConstraint(['workflow_id'], ['workflow.id'], name='approval_workflow_id_fkey'),
sa.PrimaryKeyConstraint('id', name='approval_pkey')
)
op.create_table('approval_file',
sa.Column('approval_id', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('file_data_id', sa.INTEGER(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['approval_id'], ['approval.id'], name='approval_file_approval_id_fkey'),
sa.ForeignKeyConstraint(['file_data_id'], ['file_data.id'], name='approval_file_file_data_id_fkey')
)
# ### end Alembic commands ###

Binary file not shown.

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_13oadue" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
<bpmn:process id="Process_1e56be7" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_07vc55t</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_07vc55t" sourceRef="StartEvent_1" targetRef="Activity_0s5qx04" />
<bpmn:exclusiveGateway id="Gateway_1j2ytgn">
<bpmn:incoming>Flow_1m73p95</bpmn:incoming>
<bpmn:outgoing>Flow_0gb1k4g</bpmn:outgoing>
<bpmn:outgoing>Flow_08kr305</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_0gb1k4g" sourceRef="Gateway_1j2ytgn" targetRef="animals">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">type == 'fruit'</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_08kr305" sourceRef="Gateway_1j2ytgn" targetRef="fruits">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">type=="fruit"</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:exclusiveGateway id="Gateway_14eyj6z">
<bpmn:incoming>Flow_09ik0zr</bpmn:incoming>
<bpmn:incoming>Flow_1tzwe06</bpmn:incoming>
<bpmn:outgoing>Flow_1ym0gex</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_09ik0zr" sourceRef="animals" targetRef="Gateway_14eyj6z" />
<bpmn:sequenceFlow id="Flow_1tzwe06" sourceRef="fruits" targetRef="Gateway_14eyj6z" />
<bpmn:endEvent id="Event_0guzzkq">
<bpmn:incoming>Flow_1ym0gex</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1ym0gex" sourceRef="Gateway_14eyj6z" targetRef="Event_0guzzkq" />
<bpmn:userTask id="animals" name="Animals" camunda:formKey="FormA">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="selectedItem" label="Select An Item" type="enum">
<camunda:properties>
<camunda:property id="spreadsheet.name" value="animals.xlsx" />
<camunda:property id="spreadsheet.value.column" value="Value" />
<camunda:property id="spreadsheet.label.column" value="Label" />
</camunda:properties>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0gb1k4g</bpmn:incoming>
<bpmn:outgoing>Flow_09ik0zr</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="fruits" name="Fruits" camunda:formKey="FromB">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="selectedItem" type="enum">
<camunda:properties>
<camunda:property id="spreadsheet.name" value="fruits.xlsx" />
<camunda:property id="spreadsheet.value.column" value="Value" />
<camunda:property id="spreadsheet.label.column" value="Label" />
</camunda:properties>
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_08kr305</bpmn:incoming>
<bpmn:outgoing>Flow_1tzwe06</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1m73p95" sourceRef="Activity_0s5qx04" targetRef="Gateway_1j2ytgn" />
<bpmn:userTask id="Activity_0s5qx04" name="What do you like" camunda:formKey="choose">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="type" type="enum">
<camunda:validation>
<camunda:constraint name="required" config="True" />
</camunda:validation>
<camunda:value id="animals" name="Animals" />
<camunda:value id="fruits" name="Fruits" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_07vc55t</bpmn:incoming>
<bpmn:outgoing>Flow_1m73p95</bpmn:outgoing>
</bpmn:userTask>
<bpmn:textAnnotation id="TextAnnotation_1vfpzfh">
<bpmn:text>Sheet one and sheet two each reference different spread sheets, but  they use  the same form name.</bpmn:text>
</bpmn:textAnnotation>
<bpmn:association id="Association_0w3ioqq" sourceRef="animals" targetRef="TextAnnotation_1vfpzfh" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1e56be7">
<bpmndi:BPMNShape id="TextAnnotation_1vfpzfh_di" bpmnElement="TextAnnotation_1vfpzfh">
<dc:Bounds x="640" y="80" width="200" height="60" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_07vc55t_di" bpmnElement="Flow_07vc55t">
<di:waypoint x="188" y="307" />
<di:waypoint x="250" y="307" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0gb1k4g_di" bpmnElement="Flow_0gb1k4g">
<di:waypoint x="410" y="282" />
<di:waypoint x="410" y="240" />
<di:waypoint x="490" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_08kr305_di" bpmnElement="Flow_08kr305">
<di:waypoint x="410" y="332" />
<di:waypoint x="410" y="370" />
<di:waypoint x="490" y="370" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_09ik0zr_di" bpmnElement="Flow_09ik0zr">
<di:waypoint x="590" y="240" />
<di:waypoint x="670" y="240" />
<di:waypoint x="670" y="282" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1tzwe06_di" bpmnElement="Flow_1tzwe06">
<di:waypoint x="590" y="370" />
<di:waypoint x="670" y="370" />
<di:waypoint x="670" y="332" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1ym0gex_di" bpmnElement="Flow_1ym0gex">
<di:waypoint x="695" y="307" />
<di:waypoint x="752" y="307" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1m73p95_di" bpmnElement="Flow_1m73p95">
<di:waypoint x="350" y="307" />
<di:waypoint x="385" y="307" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Gateway_1j2ytgn_di" bpmnElement="Gateway_1j2ytgn" isMarkerVisible="true">
<dc:Bounds x="385" y="282" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_14eyj6z_di" bpmnElement="Gateway_14eyj6z" isMarkerVisible="true">
<dc:Bounds x="645" y="282" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0guzzkq_di" bpmnElement="Event_0guzzkq">
<dc:Bounds x="752" y="289" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0eua66n_di" bpmnElement="animals">
<dc:Bounds x="490" y="200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0kcbe51_di" bpmnElement="fruits">
<dc:Bounds x="490" y="330" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="289" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fixobo_di" bpmnElement="Activity_0s5qx04">
<dc:Bounds x="250" y="267" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Association_0w3ioqq_di" bpmnElement="Association_0w3ioqq">
<di:waypoint x="589" y="208" />
<di:waypoint x="694" y="140" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

Binary file not shown.

View File

@ -4,12 +4,12 @@
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_0lvudp8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="SequenceFlow_0lvudp8" sourceRef="StartEvent_1" targetRef="Task_14svgcu" />
<bpmn:sequenceFlow id="SequenceFlow_0lvudp8" sourceRef="StartEvent_1" targetRef="TaskEnumLookup" />
<bpmn:endEvent id="EndEvent_0q4qzl9">
<bpmn:incoming>SequenceFlow_02vev7n</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_02vev7n" sourceRef="Task_14svgcu" targetRef="EndEvent_0q4qzl9" />
<bpmn:userTask id="Task_14svgcu" name="Enum Lookup Form" camunda:formKey="EnumForm">
<bpmn:sequenceFlow id="SequenceFlow_02vev7n" sourceRef="TaskEnumLookup" targetRef="EndEvent_0q4qzl9" />
<bpmn:userTask id="TaskEnumLookup" name="Enum Lookup Form" camunda:formKey="EnumForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="AllTheNames" label="Select a value" type="enum">
@ -41,7 +41,7 @@
<bpmndi:BPMNShape id="EndEvent_0q4qzl9_di" bpmnElement="EndEvent_0q4qzl9">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="UserTask_18ly1yq_di" bpmnElement="Task_14svgcu">
<bpmndi:BPMNShape id="UserTask_18ly1yq_di" bpmnElement="TaskEnumLookup">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>

View File

@ -4,12 +4,12 @@
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>SequenceFlow_0lvudp8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="SequenceFlow_0lvudp8" sourceRef="StartEvent_1" targetRef="Task_14svgcu" />
<bpmn:sequenceFlow id="SequenceFlow_0lvudp8" sourceRef="StartEvent_1" targetRef="Task_Enum_Lookup" />
<bpmn:endEvent id="EndEvent_0q4qzl9">
<bpmn:incoming>SequenceFlow_02vev7n</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_02vev7n" sourceRef="Task_14svgcu" targetRef="EndEvent_0q4qzl9" />
<bpmn:userTask id="Task_14svgcu" name="Enum Lookup Form" camunda:formKey="EnumForm">
<bpmn:sequenceFlow id="SequenceFlow_02vev7n" sourceRef="Task_Enum_Lookup" targetRef="EndEvent_0q4qzl9" />
<bpmn:userTask id="Task_Enum_Lookup" name="Enum Lookup Form" camunda:formKey="EnumForm">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="sponsor" label="Select a value" type="autocomplete">
@ -41,7 +41,7 @@
<bpmndi:BPMNShape id="EndEvent_0q4qzl9_di" bpmnElement="EndEvent_0q4qzl9">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="UserTask_18ly1yq_di" bpmnElement="Task_14svgcu">
<bpmndi:BPMNShape id="UserTask_18ly1yq_di" bpmnElement="Task_Enum_Lookup">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>

View File

@ -18,14 +18,14 @@ class TestLookupService(BaseTest):
file_model = session.query(FileModel).filter(FileModel.name == "customer_list.xls").first()
file_data_model = session.query(FileDataModel).filter(FileDataModel.file_model == file_model).first()
with self.assertRaises(ApiError):
LookupService.lookup(workflow, "not_the_right_field", "sam", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "not_the_right_field", "sam", limit=10)
def test_lookup_table_is_not_created_more_than_once(self):
spec = BaseTest.load_test_spec('enum_options_with_search')
workflow = self.create_workflow('enum_options_with_search')
LookupService.lookup(workflow, "sponsor", "sam", limit=10)
LookupService.lookup(workflow, "sponsor", "something", limit=10)
LookupService.lookup(workflow, "sponsor", "blah", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "sponsor", "sam", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "sponsor", "something", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "sponsor", "blah", limit=10)
lookup_records = session.query(LookupFileModel).all()
self.assertIsNotNone(lookup_records)
self.assertEqual(1, len(lookup_records))
@ -37,7 +37,7 @@ class TestLookupService(BaseTest):
spec = BaseTest.load_test_spec('enum_options_with_search')
workflow = self.create_workflow('enum_options_with_search')
file_model = session.query(FileModel).filter(FileModel.name == "sponsors.xls").first()
LookupService.lookup(workflow, "sponsor", "sam", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "sponsor", "sam", limit=10)
lookup_records = session.query(LookupFileModel).all()
self.assertIsNotNone(lookup_records)
self.assertEqual(1, len(lookup_records))
@ -58,7 +58,7 @@ class TestLookupService(BaseTest):
processor.reset(workflow)
workflow = processor.workflow_model
LookupService.lookup(workflow, "sponsor", "sam", limit=10)
LookupService.lookup(workflow, "Task_Enum_Lookup", "sponsor", "sam", limit=10)
lookup_records = session.query(LookupFileModel).all()
lookup_record = lookup_records[0]
lookup_data = session.query(LookupDataModel).filter(LookupDataModel.lookup_file_model == lookup_record).all()
@ -69,71 +69,103 @@ class TestLookupService(BaseTest):
workflow = self.create_workflow('enum_options_from_file')
processor = WorkflowProcessor(workflow)
processor.do_engine_steps()
results = LookupService.lookup(workflow, "AllTheNames", "", value="1000", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "", value="1000", limit=10)
self.assertEqual(1, len(results), "It is possible to find an item based on the id, rather than as a search")
self.assertIsNotNone(results[0].data)
self.assertIsInstance(results[0].data, dict)
def test_lookup_with_two_spreadsheets_with_the_same_field_name_in_different_forms(self):
spec = BaseTest.load_test_spec('enum_options_competing_files')
workflow = self.create_workflow('enum_options_competing_files')
processor = WorkflowProcessor(workflow)
processor.do_engine_steps()
task = processor.get_ready_user_tasks()[0]
task.data = {"type": "animal"}
processor.complete_task(task)
processor.do_engine_steps()
task = processor.get_ready_user_tasks()[0]
results = LookupService.lookup(workflow, task.task_spec.name, "selectedItem", "", value="pigs", limit=10)
self.assertEqual(1, len(results), "It is possible to find an item based on the id, rather than as a search")
self.assertIsNotNone(results[0].data)
results = LookupService.lookup(workflow, task.task_spec.name, "selectedItem", "", value="apples", limit=10)
self.assertEqual(0, len(results), "We shouldn't find our fruits mixed in with our animals.")
processor.reset(workflow, clear_data=True)
processor.do_engine_steps()
task = processor.get_ready_user_tasks()[0]
task.data = {"type": "fruit"}
processor.complete_task(task)
processor.do_engine_steps()
task = processor.get_ready_user_tasks()[0]
results = LookupService.lookup(workflow, task.task_spec.name, "selectedItem", "", value="apples", limit=10)
self.assertEqual(1, len(results), "It is possible to find an item based on the id, rather than as a search")
self.assertIsNotNone(results[0].data)
results = LookupService.lookup(workflow, task.task_spec.name, "selectedItem", "", value="pigs", limit=10)
self.assertEqual(0, len(results), "We shouldn't find our animals mixed in with our fruits.")
def test_some_full_text_queries(self):
spec = BaseTest.load_test_spec('enum_options_from_file')
workflow = self.create_workflow('enum_options_from_file')
processor = WorkflowProcessor(workflow)
processor.do_engine_steps()
results = LookupService.lookup(workflow, "AllTheNames", "", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "", limit=10)
self.assertEqual(10, len(results), "Blank queries return everything, to the limit")
results = LookupService.lookup(workflow, "AllTheNames", "medicines", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "medicines", limit=10)
self.assertEqual(1, len(results), "words in the middle of label are detected.")
self.assertEqual("The Medicines Company", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "UVA", limit=10)
results = LookupService.lookup(workflow,"TaskEnumLookup", "AllTheNames", "UVA", limit=10)
self.assertEqual(1, len(results), "Beginning of label is found.")
self.assertEqual("UVA - INTERNAL - GM USE ONLY", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "uva", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup","AllTheNames", "uva", limit=10)
self.assertEqual(1, len(results), "case does not matter.")
self.assertEqual("UVA - INTERNAL - GM USE ONLY", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "medici", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "medici", limit=10)
self.assertEqual(1, len(results), "partial words are picked up.")
self.assertEqual("The Medicines Company", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "Genetics Savings", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "Genetics Savings", limit=10)
self.assertEqual(1, len(results), "multiple terms are picked up..")
self.assertEqual("Genetics Savings & Clone, Inc.", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "Genetics Sav", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "Genetics Sav", limit=10)
self.assertEqual(1, len(results), "prefix queries still work with partial terms")
self.assertEqual("Genetics Savings & Clone, Inc.", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "Gen Sav", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "Gen Sav", limit=10)
self.assertEqual(1, len(results), "prefix queries still work with ALL the partial terms")
self.assertEqual("Genetics Savings & Clone, Inc.", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "Inc", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "Inc", limit=10)
self.assertEqual(7, len(results), "short terms get multiple correct results.")
self.assertEqual("Genetics Savings & Clone, Inc.", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "reaction design", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "reaction design", limit=10)
self.assertEqual(3, len(results), "all results come back for two terms.")
self.assertEqual("Reaction Design", results[0].label, "Exact matches come first.")
results = LookupService.lookup(workflow, "AllTheNames", "1 Something", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "1 Something", limit=10)
self.assertEqual("1 Something", results[0].label, "Exact matches are preferred")
results = LookupService.lookup(workflow, "AllTheNames", "1 (!-Something", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "1 (!-Something", limit=10)
self.assertEqual("1 Something", results[0].label, "special characters don't flake out")
results = LookupService.lookup(workflow, "AllTheNames", "1 Something", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "1 Something", limit=10)
self.assertEqual("1 Something", results[0].label, "double spaces should not be an issue.")
results = LookupService.lookup(workflow, "AllTheNames", "in", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "in", limit=10)
self.assertEqual(10, len(results), "stop words are not removed.")
self.assertEqual("Genetics Savings & Clone, Inc.", results[0].label)
results = LookupService.lookup(workflow, "AllTheNames", "other", limit=10)
results = LookupService.lookup(workflow, "TaskEnumLookup", "AllTheNames", "other", limit=10)
self.assertEqual("Other", results[0].label, "Can't find the word 'other', which is an english stop word")

View File

@ -266,8 +266,8 @@ class TestTasksApi(BaseTest):
workflow = self.get_workflow_api(workflow)
task = workflow.next_task
field_id = task.form['fields'][0]['id']
rv = self.app.get('/v1.0/workflow/%i/lookup/%s?query=%s&limit=5' %
(workflow.id, field_id, 'c'), # All records with a word that starts with 'c'
rv = self.app.get('/v1.0/workflow/%i/lookup/%s/%s?query=%s&limit=5' %
(workflow.id, task.name, field_id, 'c'), # All records with a word that starts with 'c'
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)
@ -281,8 +281,8 @@ class TestTasksApi(BaseTest):
workflow = self.get_workflow_api(workflow)
task = workflow.next_task
field_id = task.form['fields'][0]['id']
rv = self.app.get('/v1.0/workflow/%i/lookup/%s?query=%s&limit=5' %
(workflow.id, field_id, 'c'), # All records with a word that starts with 'c'
rv = self.app.get('/v1.0/workflow/%i/lookup/%s/%s?query=%s&limit=5' %
(workflow.id, task.name, field_id, 'c'), # All records with a word that starts with 'c'
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)
@ -290,8 +290,8 @@ class TestTasksApi(BaseTest):
self.assertEqual(5, len(results))
self.assert_options_populated(results, ['CUSTOMER_NUMBER', 'CUSTOMER_NAME', 'CUSTOMER_CLASS_MEANING'])
rv = self.app.get('/v1.0/workflow/%i/lookup/%s?value=%s' %
(workflow.id, field_id, results[0]['value']), # All records with a word that starts with 'c'
rv = self.app.get('/v1.0/workflow/%i/lookup/%s/%s?value=%s' %
(workflow.id, task.name, field_id, results[0]['value']), # All records with a word that starts with 'c'
headers=self.logged_in_headers(),
content_type="application/json")
results = json.loads(rv.get_data(as_text=True))
@ -311,8 +311,8 @@ class TestTasksApi(BaseTest):
task = workflow.next_task
field_id = task.form['fields'][0]['id']
option_id = task.form['fields'][0]['options'][0]['id']
rv = self.app.get('/v1.0/workflow/%i/lookup/%s?value=%s' %
(workflow.id, field_id, option_id), # All records with a word that starts with 'c'
rv = self.app.get('/v1.0/workflow/%i/lookup/%s/%s?value=%s' %
(workflow.id, task.name, field_id, option_id), # All records with a word that starts with 'c'
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)
@ -352,8 +352,8 @@ class TestTasksApi(BaseTest):
task = workflow.next_task
field_id = task.form['fields'][0]['id']
# lb3dp is a user record in the mock ldap responses for tests.
rv = self.app.get('/v1.0/workflow/%s/lookup/%s?query=%s&limit=5' %
(workflow.id, field_id, 'lb3dp'),
rv = self.app.get('/v1.0/workflow/%s/lookup/%s/%s?query=%s&limit=5' %
(workflow.id, task.name, field_id, 'lb3dp'),
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)