Skip to content
Open
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
18 changes: 17 additions & 1 deletion common/src/api/v1/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,28 @@ pub struct OriginFilter {
pub architecture: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IdentityFilter {
pub name: Option<String>,
#[serde(default)]
pub search_type: SearchType,
pub version: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchType {
Exact,
Contains,
StartsWith,
}

impl Default for SearchType {
fn default() -> Self {
Self::Exact
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FreshnessFilter {
pub seen_only: Option<bool>,
Expand Down
21 changes: 21 additions & 0 deletions contrib/docs/rebuilderd-v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ paths:
- $ref: '#/components/parameters/component'

- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/search_type'
- $ref: '#/components/parameters/version'
- $ref: '#/components/parameters/architecture'
responses:
Expand Down Expand Up @@ -271,6 +272,7 @@ paths:
- $ref: '#/components/parameters/component'

- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/search_type'
- $ref: '#/components/parameters/version'
responses:
"200":
Expand Down Expand Up @@ -329,6 +331,7 @@ paths:
- $ref: '#/components/parameters/component'

- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/search_type'
- $ref: '#/components/parameters/version'
- $ref: '#/components/parameters/architecture'
responses:
Expand Down Expand Up @@ -388,6 +391,7 @@ paths:
- $ref: '#/components/parameters/component'

- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/search_type'
- $ref: '#/components/parameters/version'
- $ref: '#/components/parameters/architecture'
responses:
Expand Down Expand Up @@ -437,6 +441,7 @@ paths:
- $ref: '#/components/parameters/component'

- $ref: '#/components/parameters/name'
- $ref: '#/components/parameters/search_type'
- $ref: '#/components/parameters/version'
- $ref: '#/components/parameters/architecture'
responses:
Expand Down Expand Up @@ -1477,6 +1482,22 @@ components:
type: string
description: |-
Filters the results by the version of the package.
search_type:
in: query
name: search_type
required: false
schema:
type: string
enum:
- exact
- contains
- starts_with
default: exact
description: |-
Specifies the matching strategy for the 'name' parameter.
- `exact`: Matches the name exactly (default).
- `contains`: Matches if the name contains the provided string.
- `starts_with`: Matches if the name starts with the provided string.
distribution:
in: query
name: distribution
Expand Down
1 change: 1 addition & 0 deletions daemon/src/api/v1/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub async fn request_rebuild(
let identity_filter = IdentityFilter {
name: queue_request.name,
version: queue_request.version,
..Default::default()
};

let mut sql = source_packages::table
Expand Down
19 changes: 13 additions & 6 deletions daemon/src/api/v1/util/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ use diesel::expression::{AsExpression, ValidGrouping};
use diesel::query_builder::QueryFragment;
use diesel::sql_types::{Bool, Text};
use diesel::sqlite::Sqlite;
use diesel::{BoolExpressionMethods, BoxableExpression, Expression, SelectableExpression};
use diesel::{ExpressionMethods, SqliteExpressionMethods};
use rebuilderd_common::api::v1::{FreshnessFilter, IdentityFilter, OriginFilter};
use diesel::{
BoolExpressionMethods, BoxableExpression, Expression, ExpressionMethods, SelectableExpression,
SqliteExpressionMethods, TextExpressionMethods,
};
use rebuilderd_common::api::v1::{FreshnessFilter, IdentityFilter, OriginFilter, SearchType};

pub trait IntoIdentityFilter<QS, DB>
where
Expand Down Expand Up @@ -64,9 +66,14 @@ impl<T: 'static> IntoIdentityFilter<T, Sqlite> for IdentityFilter {
+ Send
+ 'static,
{
let name_is: Self::Output = match self.name {
Some(name) => Box::new(name_column.is(name)),
None => Box::new(AsExpression::<Bool>::as_expression(true)),
let name_is: Self::Output = if let Some(name) = self.name {
match self.search_type {
SearchType::Exact => Box::new(name_column.eq(name)),
SearchType::Contains => Box::new(name_column.like(format!("%{name}%"))),
SearchType::StartsWith => Box::new(name_column.like(format!("{name}%"))),
}
} else {
Box::new(AsExpression::<Bool>::as_expression(true))
};

let version_is: Self::Output = match self.version {
Expand Down
196 changes: 192 additions & 4 deletions tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use rebuilderd::db;
use rebuilderd::schema::{attestation_logs, rebuild_artifacts};
use rebuilderd_common::api::Client;
use rebuilderd_common::api::v1::{
ArtifactStatus, BinaryPackage, BinaryPackageReport, BuildRestApi, BuildStatus, JobAssignment,
MetaRestApi, PackageReport, PackageRestApi, PopQueuedJobRequest, Priority, QueueJobRequest,
QueueRestApi, QueuedJob, RebuildArtifactReport, RebuildReport, RegisterWorkerRequest,
SourcePackageReport, WorkerRestApi,
ArtifactStatus, BinaryPackage, BinaryPackageReport, BuildRestApi, BuildStatus, IdentityFilter,
JobAssignment, MetaRestApi, PackageReport, PackageRestApi, PopQueuedJobRequest, Priority,
QueueJobRequest, QueueRestApi, QueuedJob, RebuildArtifactReport, RebuildReport,
RegisterWorkerRequest, SearchType, SourcePackageReport, WorkerRestApi,
};
use rebuilderd_common::config::*;
use rebuilderd_common::errors::*;
Expand Down Expand Up @@ -573,6 +573,194 @@ async fn main() -> Result<()> {
})
.await?;

// At this point we have binary packages: "zstd", "foo", "bar"
// and source packages: "pkgbase", "hello-world"

test("Testing search_type exact matches single package", async {
let filter = IdentityFilter {
name: Some("foo".to_string()),
search_type: SearchType::Exact,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!("Expected 1 pkg, got {}", pkgs.len());
}
if pkgs[0].name != "foo" {
bail!("Expected 'foo', got '{}'", pkgs[0].name);
}
Ok(())
})
.await?;

test("Testing search_type exact does not partial match", async {
let filter = IdentityFilter {
name: Some("oo".to_string()),
search_type: SearchType::Exact,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if !pkgs.is_empty() {
bail!("Expected 0 pkgs, got {}", pkgs.len());
}
Ok(())
})
.await?;

test("Testing search_type contains", async {
let filter = IdentityFilter {
name: Some("oo".to_string()),
search_type: SearchType::Contains,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!("Expected 1 pkg containing 'oo', got {}", pkgs.len());
}
if pkgs[0].name != "foo" {
bail!("Expected 'foo', got '{}'", pkgs[0].name);
}
Ok(())
})
.await?;

test("Testing search_type starts_with", async {
let filter = IdentityFilter {
name: Some("ba".to_string()),
search_type: SearchType::StartsWith,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!("Expected 1 pkg starting with 'ba', got {}", pkgs.len());
}
if pkgs[0].name != "bar" {
bail!("Expected 'bar', got '{}'", pkgs[0].name);
}
Ok(())
})
.await?;

test(
"Testing search_type starts_with does not match suffix",
async {
let filter = IdentityFilter {
name: Some("ar".to_string()),
search_type: SearchType::StartsWith,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if !pkgs.is_empty() {
bail!("Expected 0 pkgs, got {}", pkgs.len());
}
Ok(())
},
)
.await?;

test("Testing search_type contains on source packages", async {
let filter = IdentityFilter {
name: Some("hello".to_string()),
search_type: SearchType::Contains,
version: None,
};
let pkgs = client
.get_source_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!(
"Expected 1 source pkg containing 'hello', got {}",
pkgs.len()
);
}
if pkgs[0].name != "hello-world" {
bail!("Expected 'hello-world', got '{}'", pkgs[0].name);
}
Ok(())
})
.await?;

test(
"Testing search_type starts_with on source packages",
async {
let filter = IdentityFilter {
name: Some("hello".to_string()),
search_type: SearchType::StartsWith,
version: None,
};
let pkgs = client
.get_source_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!(
"Expected 1 source pkg starting with 'hello', got {}",
pkgs.len()
);
}
if pkgs[0].name != "hello-world" {
bail!("Expected 'hello-world', got '{}'", pkgs[0].name);
}
Ok(())
},
)
.await?;

test("Testing search_type starts_with single letter", async {
let filter = IdentityFilter {
name: Some("f".to_string()),
search_type: SearchType::StartsWith,
version: None,
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if pkgs.len() != 1 {
bail!("Expected 1 pkg starting with 'f', got {}", pkgs.len());
}
if pkgs[0].name != "foo" {
bail!("Expected 'foo', got '{}'", pkgs[0].name);
}
Ok(())
})
.await?;

test("Testing search_type default is exact", async {
let filter = IdentityFilter {
name: Some("zst".to_string()),
..Default::default()
};
let pkgs = client
.get_binary_packages(None, None, Some(&filter))
.await?
.records;
if !pkgs.is_empty() {
bail!(
"Expected 0 pkgs with default (exact) search for 'zst', got {}",
pkgs.len()
);
}
Ok(())
})
.await?;

test("Fetching task and reporting GOOD with attestation", async {
let task = request_work(&client, "rebuilderd").await?;

Expand Down
3 changes: 3 additions & 0 deletions tools/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ async fn lookup_package(client: &Client, filter: PkgsFilter) -> Result<BinaryPac
let identity_filter = IdentityFilter {
name: filter.name,
version: None, // TODO: ls.filter.version
..Default::default()
};

let mut results = client
Expand Down Expand Up @@ -227,6 +228,7 @@ async fn main() -> Result<()> {
let identity_filter = IdentityFilter {
name: ls.filter.name,
version: None, // TODO: ls.filter.version
..Default::default()
};

let mut page = Page {
Expand Down Expand Up @@ -432,6 +434,7 @@ async fn main() -> Result<()> {
let identity_filter = IdentityFilter {
name: Some(push.name),
version: push.version,
..Default::default()
};

client
Expand Down
Loading