Provides some basic tools for getting additional information about a lookup field.

Adds an optional 'value' parameter to the lookup endpoint so you can find a specific entry in the lookup table.
Makes sure the data attribute returned on a lookup model is a dictionary, and not a string.
Fixes a previous bug that would crop up if double spaces were used when performing a search.
This commit is contained in:
Dan Funk 2020-06-30 10:34:16 -04:00
parent d3ce1af1ce
commit f183e12fe5
5 changed files with 38 additions and 16 deletions

View File

@ -703,18 +703,18 @@ paths:
description: The string to search for in the Value column of the lookup table. description: The string to search for in the Value column of the lookup table.
schema: schema:
type: string type: string
- name: value
in: query
required: false
description: An alternative to query, this accepts the specific value or id selected in a dropdown list or auto-complete, and will return the one matching record. Useful for getting additional details about an item selected in a dropdown.
schema:
type: string
- name: limit - name: limit
in: query in: query
required: false required: false
description: The total number of records to return, defaults to 10. description: The total number of records to return, defaults to 10.
schema: schema:
type: integer type: integer
- name: id
in: query
required: false
description: Rather than supplying a query, you can specify a speicific id to get data back on a lookup field.
schema:
type: string
get: get:
operationId: crc.api.workflow.lookup operationId: crc.api.workflow.lookup

View File

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

View File

@ -182,6 +182,7 @@ class LookupDataSchema(SQLAlchemyAutoSchema):
load_instance = True load_instance = True
include_relationships = False include_relationships = False
include_fk = False # Includes foreign keys include_fk = False # Includes foreign keys
exclude = ['id'] # Do not include the id field, it should never be used via the API.
class SimpleFileSchema(ma.Schema): class SimpleFileSchema(ma.Schema):

View File

@ -63,14 +63,14 @@ class LookupService(object):
return lookup_model return lookup_model
@staticmethod @staticmethod
def lookup(workflow, field_id, query, limit, id = None): def lookup(workflow, field_id, query, value, limit):
lookup_model = LookupService.__get_lookup_model(workflow, field_id) lookup_model = LookupService.__get_lookup_model(workflow, field_id)
if lookup_model.is_ldap: if lookup_model.is_ldap:
return LookupService._run_ldap_query(query, limit) return LookupService._run_ldap_query(query, limit)
else: else:
return LookupService._run_lookup_query(lookup_model, query, limit, id) return LookupService._run_lookup_query(lookup_model, query, value, limit)
@ -157,10 +157,10 @@ class LookupService(object):
return lookup_model return lookup_model
@staticmethod @staticmethod
def _run_lookup_query(lookup_file_model, query, limit, lookup_id): def _run_lookup_query(lookup_file_model, query, value, limit):
db_query = LookupDataModel.query.filter(LookupDataModel.lookup_file_model == lookup_file_model) db_query = LookupDataModel.query.filter(LookupDataModel.lookup_file_model == lookup_file_model)
if lookup_id is not None: # Then just find the model with that id. if value is not None: # Then just find the model with that value
db_query = db_query.filter(LookupDataModel.id == lookup_id) db_query = db_query.filter(LookupDataModel.value == value)
else: else:
# Build a full text query that takes all the terms provided and executes each term as a prefix query, and # Build a full text query that takes all the terms provided and executes each term as a prefix query, and
# OR's those queries together. The order of the results is handled as a standard "Like" on the original # OR's those queries together. The order of the results is handled as a standard "Like" on the original

View File

@ -357,15 +357,36 @@ class TestTasksApi(BaseTest):
self.assert_success(rv) self.assert_success(rv)
results = json.loads(rv.get_data(as_text=True)) results = json.loads(rv.get_data(as_text=True))
self.assertEqual(5, len(results)) self.assertEqual(5, len(results))
rv = self.app.get('/v1.0/workflow/%i/lookup/%s?id=%i' % rv = self.app.get('/v1.0/workflow/%i/lookup/%s?value=%s' %
(workflow.id, field_id, results[0]['id']), # All records with a word that starts with 'c' (workflow.id, field_id, results[0]['value']), # All records with a word that starts with 'c'
headers=self.logged_in_headers(), headers=self.logged_in_headers(),
content_type="application/json") content_type="application/json")
results = json.loads(rv.get_data(as_text=True)) results = json.loads(rv.get_data(as_text=True))
self.assertEqual(1, len(results)) self.assertEqual(1, len(results))
self.assertIsInstance(results[0]['data'], dict) self.assertIsInstance(results[0]['data'], dict)
self.assertNotIn('id', results[0], "Don't include the internal id, that can be very confusing, and should not be used.")
def test_lookup_endpoint_also_works_for_enum(self):
# Naming here get's a little confusing. fields can be marked as enum or autocomplete.
# In the event of an auto-complete it's a type-ahead search field, for an enum the
# the key/values from the spreadsheet are added directly to the form and it shows up as
# a dropdown. This tests the case of wanting to get additional data when a user selects
# something from a drodown.
self.load_example_data()
workflow = self.create_workflow('enum_options_from_file')
# get the first form in the two form workflow.
workflow = self.get_workflow_api(workflow)
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'
headers=self.logged_in_headers(),
content_type="application/json")
self.assert_success(rv)
results = json.loads(rv.get_data(as_text=True))
self.assertEqual(1, len(results))
self.assertIsInstance(results[0]['data'], dict)
def test_lookup_endpoint_for_task_ldap_field_lookup(self): def test_lookup_endpoint_for_task_ldap_field_lookup(self):
self.load_example_data() self.load_example_data()