11use crate :: {
22 Error ,
3- common:: LicenseRefMapping ,
3+ common:: { LicenseRefMapping , license_filtering , license_filtering :: LICENSE } ,
44 license:: model:: {
55 SpdxLicenseDetails , SpdxLicenseSummary ,
66 sbom_license:: {
@@ -10,11 +10,12 @@ use crate::{
1010} ;
1111use sea_orm:: {
1212 ColumnTrait , ConnectionTrait , EntityTrait , FromQueryResult , QueryFilter , QuerySelect ,
13- RelationTrait , Statement ,
13+ QueryTrait , RelationTrait , Statement ,
14+ } ;
15+ use sea_query:: {
16+ Alias , ColumnType , Condition , Expr , JoinType , Order :: Asc , PostgresQueryBuilder , query,
1417} ;
15- use sea_query:: { ColumnType , Condition , Expr , Func , JoinType , SimpleExpr } ;
1618use serde:: { Deserialize , Serialize } ;
17- use trustify_common:: db:: CaseLicenseTextSbomId ;
1819use trustify_common:: {
1920 db:: {
2021 limiter:: LimiterAsModelTrait ,
@@ -232,52 +233,35 @@ impl LicenseService {
232233 . one ( connection)
233234 . await ?;
234235
236+ const EXPANDED_LICENSE : & str = "expanded_license" ;
237+ const LICENSE_NAME : & str = "license_name" ;
235238 match sbom {
236239 Some ( sbom) => {
237- let result: Vec < LicenseRefMapping > = LicenseRefMapping :: find_by_statement ( Statement :: from_sql_and_values (
238- connection. get_database_backend ( ) ,
239- r#"
240- (
241- -- Successfully parsed (during SBOM ingestion) license ID values can be
242- -- retrieved from the spdx_licenses column. The DISTINCT must be on lower values
243- -- because the license identifiers have to be managed in case-insensitive way
244- -- ref. https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/#case-sensitivity
245- SELECT DISTINCT on (lower(l.spdx_licenses)) l.spdx_licenses as license_name, l.spdx_licenses as license_id
246- FROM sbom_package_license spl
247- -- 'spdx_licenses' must be unnested and sorted before joining in order to ensure consistent results
248- JOIN (
249- SELECT id, unnest(spdx_licenses) as spdx_licenses
250- FROM license
251- ORDER BY id, spdx_licenses
252- ) AS l ON spl.license_id = l.id
253- WHERE spl.sbom_id = $1
254- AND l.spdx_licenses IS NOT NULL
255- UNION
256- -- CycloneDX SBOMs has NO "LicenseRef" by specifications (hence
257- -- the above condition 'licensing_infos.license_id IS NULL') so
258- -- all the values in the license.text whose spdx_licenses is null
259- -- must be added to the result set. The need for the DISTINCT on lower is
260- -- clearly explained above.
261- SELECT DISTINCT ON (LOWER(l.text)) l.text as license_name, l.text as license_id
262- FROM sbom_package_license spl
263- JOIN license l ON spl.license_id = l.id
264- LEFT JOIN licensing_infos ON licensing_infos.sbom_id = spl.sbom_id
265- WHERE spl.sbom_id = $1
266- AND l.spdx_licenses IS NULL
267- AND licensing_infos.license_id IS NULL
268- UNION
269- -- SPDX SBOMs has "LicenseRef" by specifications and they're stored in
270- -- licensing_infos and so their names have to be added as well
271- SELECT DISTINCT name as license_name, license_id
272- FROM licensing_infos
273- WHERE sbom_id = $1
274- ORDER BY license_name
240+ let expand_license_expression = sbom_package_license:: Entity :: find ( )
241+ . select_only ( )
242+ . distinct ( )
243+ . column_as (
244+ license_filtering:: get_case_license_text_sbom_id ( ) ,
245+ EXPANDED_LICENSE ,
246+ )
247+ . join (
248+ JoinType :: Join ,
249+ sbom_package_license:: Relation :: License . def ( ) ,
275250 )
276- "# ,
277- [ sbom. sbom_id . into ( ) ] ,
278- ) )
279- . all ( connection)
280- . await ?;
251+ . filter ( sbom_package_license:: Column :: SbomId . eq ( sbom. sbom_id ) ) ;
252+ let ( sql, values) = query:: Query :: select ( )
253+ // reported twice to keep compatibility with LicenseRefMapping currently
254+ // exposed in the involved endpoint.
255+ . expr_as ( Expr :: col ( Alias :: new ( EXPANDED_LICENSE ) ) , LICENSE_NAME )
256+ . expr_as ( Expr :: col ( Alias :: new ( EXPANDED_LICENSE ) ) , "license_id" )
257+ . from_subquery ( expand_license_expression. into_query ( ) , "expanded_licenses" )
258+ . order_by ( LICENSE_NAME , Asc )
259+ . build ( PostgresQueryBuilder ) ;
260+ let result: Vec < LicenseRefMapping > = LicenseRefMapping :: find_by_statement (
261+ Statement :: from_sql_and_values ( connection. get_database_backend ( ) , sql, values) ,
262+ )
263+ . all ( connection)
264+ . await ?;
281265 Ok ( Some ( result) )
282266 }
283267 None => Ok ( None ) ,
@@ -290,15 +274,7 @@ impl LicenseService {
290274 paginated : Paginated ,
291275 connection : & C ,
292276 ) -> Result < PaginatedResults < LicenseText > , Error > {
293- let case_license_text_sbom_id = SimpleExpr :: FunctionCall (
294- Func :: cust ( CaseLicenseTextSbomId )
295- . arg ( Expr :: col ( license:: Column :: Text ) )
296- . arg ( Expr :: col ( (
297- sbom_package_license:: Entity ,
298- sbom_package_license:: Column :: SbomId ,
299- ) ) ) ,
300- ) ;
301- const LICENSE : & str = "license" ;
277+ let case_license_text_sbom_id = license_filtering:: get_case_license_text_sbom_id ( ) ;
302278 let limiter = license:: Entity :: find ( )
303279 . distinct ( )
304280 . select_only ( )
0 commit comments