Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

[Issue #188] More filters in search schema #189

Merged
merged 4 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions api/openapi.generated.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,37 @@ paths:
page_offset: 1
page_size: 100
sort_direction: ascending
example5:
summary: Filter by award fields
value:
filters:
expected_number_of_awards:
min: 5
award_floor:
min: 10000
award_ceiling:
max: 1000000
estimated_total_program_funding:
min: 100000
max: 250000
pagination:
order_by: opportunity_id
page_offset: 1
page_size: 25
sort_direction: descending
example6:
summary: FIlter by assistance listing numbers
value:
filters:
assistance_listing_number:
one_of:
- '43.001'
- '47.049'
pagination:
order_by: opportunity_id
page_offset: 1
page_size: 25
sort_direction: descending
security:
- ApiKeyAuth: []
/v0.1/opportunities/search:
Expand Down Expand Up @@ -831,6 +862,86 @@ components:
type: string
minLength: 2
example: USAID
AssistanceListingNumberFilterV1:
type: object
properties:
one_of:
type: array
minItems: 1
items:
type: string
pattern: ^\d{2}\.\d{2,3}$
example: '45.149'
IsCostSharingFilterV1:
type: object
properties:
one_of:
type:
- array
- 'null'
items:
type: boolean
example: true
ExpectedNumberAwardsFilterV1:
type: object
properties:
min:
type:
- integer
- 'null'
minimum: 0
example: 0
max:
type:
- integer
- 'null'
minimum: 0
example: 25
AwardFloorFilterV1:
type: object
properties:
min:
type:
- integer
- 'null'
minimum: 0
example: 0
max:
type:
- integer
- 'null'
minimum: 0
example: 10000
AwardCeilingFilterV1:
type: object
properties:
min:
type:
- integer
- 'null'
minimum: 0
example: 0
max:
type:
- integer
- 'null'
minimum: 0
example: 10000000
EstimatedTotalProgramFundingFilterV1:
type: object
properties:
min:
type:
- integer
- 'null'
minimum: 0
example: 0
max:
type:
- integer
- 'null'
minimum: 0
example: 10000000
PostDateFilterV1:
type: object
properties:
Expand Down Expand Up @@ -885,6 +996,36 @@ components:
- object
allOf:
- $ref: '#/components/schemas/AgencyFilterV1'
assistance_listing_number:
type:
- object
allOf:
- $ref: '#/components/schemas/AssistanceListingNumberFilterV1'
is_cost_sharing:
type:
- object
allOf:
- $ref: '#/components/schemas/IsCostSharingFilterV1'
expected_number_of_awards:
type:
- object
allOf:
- $ref: '#/components/schemas/ExpectedNumberAwardsFilterV1'
award_floor:
type:
- object
allOf:
- $ref: '#/components/schemas/AwardFloorFilterV1'
award_ceiling:
type:
- object
allOf:
- $ref: '#/components/schemas/AwardCeilingFilterV1'
estimated_total_program_funding:
type:
- object
allOf:
- $ref: '#/components/schemas/EstimatedTotalProgramFundingFilterV1'
post_date:
type:
- object
Expand Down
31 changes: 31 additions & 0 deletions api/src/api/opportunities_v1/opportunity_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,37 @@
},
},
},
"example5": {
"summary": "Filter by award fields",
"value": {
"filters": {
"expected_number_of_awards": {"min": 5},
"award_floor": {"min": 10000},
"award_ceiling": {"max": 1000000},
"estimated_total_program_funding": {"min": 100000, "max": 250000},
},
"pagination": {
"order_by": "opportunity_id",
"page_offset": 1,
"page_size": 25,
"sort_direction": "descending",
},
},
},
"example6": {
"summary": "FIlter by assistance listing numbers",
"value": {
"filters": {
"assistance_listing_number": {"one_of": ["43.001", "47.049"]},
},
"pagination": {
"order_by": "opportunity_id",
"page_offset": 1,
"page_size": 25,
"sort_direction": "descending",
},
},
},
}


Expand Down
44 changes: 43 additions & 1 deletion api/src/api/opportunities_v1/opportunity_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

from src.api.schemas.extension import Schema, fields, validators
from src.api.schemas.response_schema import AbstractResponseSchema, PaginationMixinSchema
from src.api.schemas.search_schema import DateSearchSchemaBuilder, StrSearchSchemaBuilder
from src.api.schemas.search_schema import (
BoolSearchSchemaBuilder,
DateSearchSchemaBuilder,
IntegerSearchSchemaBuilder,
StrSearchSchemaBuilder,
)
from src.constants.lookup_constants import (
ApplicantType,
FundingCategory,
Expand Down Expand Up @@ -320,6 +325,43 @@ class OpportunitySearchFilterV1Schema(Schema):
.with_one_of(example="USAID", minimum_length=2)
.build()
)
assistance_listing_number = fields.Nested(
StrSearchSchemaBuilder("AssistanceListingNumberFilterV1Schema")
.with_one_of(
example="45.149", pattern=r"^\d{2}\.\d{2,3}$"
) # Always of the format ##.## or ##.###
.build()
)
is_cost_sharing = fields.Nested(
BoolSearchSchemaBuilder("IsCostSharingFilterV1Schema").with_one_of(example=True).build()
)
expected_number_of_awards = fields.Nested(
IntegerSearchSchemaBuilder("ExpectedNumberAwardsFilterV1Schema")
.with_minimum_value(example=0)
.with_maximum_value(example=25)
.build()
)

award_floor = fields.Nested(
IntegerSearchSchemaBuilder("AwardFloorFilterV1Schema")
.with_minimum_value(example=0)
.with_maximum_value(example=10_000)
.build()
)

award_ceiling = fields.Nested(
IntegerSearchSchemaBuilder("AwardCeilingFilterV1Schema")
.with_minimum_value(example=0)
.with_maximum_value(example=10_000_000)
.build()
)

estimated_total_program_funding = fields.Nested(
IntegerSearchSchemaBuilder("EstimatedTotalProgramFundingFilterV1Schema")
.with_minimum_value(example=0)
.with_maximum_value(example=10_000_000)
.build()
)

post_date = fields.Nested(
DateSearchSchemaBuilder("PostDateFilterV1Schema").with_start_date().with_end_date().build()
Expand Down
2 changes: 2 additions & 0 deletions api/src/api/schemas/extension/field_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from src.api.schemas.extension.schema_common import MarshmallowErrorContainer
from src.validation.validation_constants import ValidationErrorType

Validator = validators.Validator # re-export


class Regexp(validators.Regexp):
REGEX_ERROR = MarshmallowErrorContainer(
Expand Down
Loading