diff --git a/microsetta_private_api/admin/admin_impl.py b/microsetta_private_api/admin/admin_impl.py index 293756121..1369a7f3d 100644 --- a/microsetta_private_api/admin/admin_impl.py +++ b/microsetta_private_api/admin/admin_impl.py @@ -543,7 +543,7 @@ def list_barcode_query_fields(token_info): "sample-has-inconsistencies": "Sample Has Inconsistencies", "received-unknown-validity": "Received Unknown Validity" }, - 'operators': ['equal', 'not_equal'] + 'operators': ['equal', 'not_equal', 'is_null', 'is_not_null'] } ) filter_fields.append( @@ -571,7 +571,26 @@ def list_barcode_query_fields(token_info): "Torso": "Torso", "Vaginal mucus": "Vaginal mucus" }, - 'operators': ['equal', 'not_equal'] + 'operators': ['equal', 'not_equal', 'is_null', 'is_not_null'] + } + ) + filter_fields.append( + { + # Note that this id string must match the + # latest scan timestamp in the exact + # barcode search query. + 'id': 'scan_timestamp_latest', + 'label': 'Last Scanned', + 'type': 'date', + 'description': "YYYY/MM/DD", + 'default_value': "YYYY/MM/DD", + 'validation': { + "format": "YYYY/MM/DD" + }, + 'operators': ['less_or_equal', + 'greater_or_equal', + 'is_null', + 'is_not_null'] } ) diff --git a/microsetta_private_api/repo/admin_repo.py b/microsetta_private_api/repo/admin_repo.py index 26b0aa988..ec55b59f5 100644 --- a/microsetta_private_api/repo/admin_repo.py +++ b/microsetta_private_api/repo/admin_repo.py @@ -1119,13 +1119,13 @@ def search_barcode(self, sql_cond, cond_params): "USING (barcode) " "LEFT JOIN ( " "SELECT barcode, max(scan_timestamp) " - "AS scan_timestamp " + "AS scan_timestamp_latest " "FROM barcodes.barcode_scans " "GROUP BY barcode " ") AS latest_scan " "ON barcode_scans.barcode = latest_scan.barcode " "AND barcode_scans.scan_timestamp = " - "latest_scan.scan_timestamp " + "latest_scan.scan_timestamp_latest " "WHERE {cond}" ).format(cond=sql_cond), cond_params diff --git a/microsetta_private_api/util/query_builder_to_sql.py b/microsetta_private_api/util/query_builder_to_sql.py index 819fc3a43..c2ec8a79b 100644 --- a/microsetta_private_api/util/query_builder_to_sql.py +++ b/microsetta_private_api/util/query_builder_to_sql.py @@ -26,8 +26,8 @@ # not_ends_with, # is_empty, # is_not_empty, - # is_null, - # is_not_null, + 'is_null': "is null", + 'is_not_null': "is not null", } @@ -59,9 +59,14 @@ def build_condition_helper_rule(root_obj, out_values): if operator not in supported_operators: raise RepoException("Unsupported query operator: " + str(operator)) - cond = "{id} " + supported_operators[operator] + " {value}" - out_values.append(value) + if operator in ["is_null", "is_not_null"]: + cond = "{id}" + supported_operators[operator] + # no need to append null to out_values + else: + cond = "{id} " + supported_operators[operator] + " {value}" + out_values.append(value) + return sql.SQL(cond).format( id=sql.Identifier(id), value=sql.Placeholder())