diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c801fda2097f2c0f7b89559ac8ff846988193f0..5ce3842d4bf41f82d5d4daa38fa8a403df15c866 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ stages: - deploy variables: - VERSION: "3.1" + VERSION: "3.3" SONARQUBE_URL: https://sonarqube.lam.fr CONTAINER_IMAGE: portus.lam.fr/anis/anis-server diff --git a/CHANGELOG.md b/CHANGELOG.md index b82ca7a2ed4a487106f528c7df03cb60aa5f4a63..9b2bbcd3e6a146f07f917140c4ab2eb6c2c20d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.3.0] +### Added + - #54: Added search by cone-search + ## [3.2.1] ### Fixed - #55: Fixed bug json in json when only one column is selected diff --git a/VERSION b/VERSION index 0444f320767571752143e9169e56454d978101fc..0fa4ae4890372d16ea2933390c4ba9f8f28d3f8a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.2.1 \ No newline at end of file +3.3.0 \ No newline at end of file diff --git a/anis-server.yaml b/anis-server.yaml index aa30093867058cb5af5d217a3f6b5bb927fe9e53..1a44c1ff8426abe776aa4ca3a582ef4b28ae0789 100644 --- a/anis-server.yaml +++ b/anis-server.yaml @@ -1,6 +1,6 @@ openapi: "3.0.0" info: - version: 3.1.0 + version: 3.3.0 title: Anis Server description: 'AstroNomical Information System is a generic web tool that aims to facilitate the provision of data (Astrophysics), accessible from a database, to a community of scientists.' contact: diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh index 00b936b1120037eacc4f117ff2f35f8afcd15c13..f3457957dc30aea77e0bf0b9c3182b14d295452f 100644 --- a/conf-dev/create-db.sh +++ b/conf-dev/create-db.sh @@ -17,9 +17,9 @@ curl -d '{"name":"colibri","label":"Colibri Project Test","description":"Project # Add default dataset family and ANIS datasets curl -d '{"label":"Default dataset family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"obs_cat","table_ref":"obs_cat","label":"ObsCat dataset","description":"ObsCat","display":10,"count":10000,"vo":false,"data_path":"/mnt/mount","selectable_row":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset -curl -d '{"name":"observations","table_ref":"observations_info","label":"Observations dataset","description":"Observations","display":20,"count":177454,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset -curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":30,"count":1000,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"obs_cat","table_ref":"obs_cat","label":"ObsCat dataset","description":"ObsCat","display":10,"count":10000,"vo":false,"data_path":"/mnt/mount","selectable_row":true,"config":{"cone_search":{"enabled":true,"column_ra":2,"column_dec":3}},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"observations","table_ref":"observations_info","label":"Observations dataset","description":"Observations","display":20,"count":177454,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"config":{},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":30,"count":1000,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"config":{},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset # Add ANIS obs_cat default criteria family, default output family and default output category curl -d '{"label":"Default criteria family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/obs_cat/criteria-family @@ -28,9 +28,9 @@ curl -d '{"label":"Default output category","display":10}' -H "Content-Type: app # Add SVOM dataset family and SVOM datasets curl -d '{"label":"Svom dataset family","display":20}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"l1","table_ref":"public.v_rawproducts","label":"L0 & L1","description":"L0 & L1 products list","display":10,"count":0,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset -curl -d '{"name":"products","table_ref":"public.v_products","label":"Scientific Products","description":"SR3 & SR4 products list","display":20,"count":0,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset -curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":30,"count":100,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"l1","table_ref":"public.v_rawproducts","label":"L0 & L1","description":"L0 & L1 products list","display":10,"count":0,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"config":{},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"products","table_ref":"public.v_products","label":"Scientific Products","description":"SR3 & SR4 products list","display":20,"count":0,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"config":{},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":30,"count":100,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"config":{},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset # Add SVOM l1 criteria families, default output family and default output category curl -d '{"label":"Obs","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/l1/criteria-family @@ -99,7 +99,7 @@ curl -d '{"id":9,"name":"json_schema_uploaded","table_name":"sp_cards","label":" # Add COLIBRI dataset family and COLIBRI dataset curl -d '{"label":"Colibri dataset family","display":30}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"anis_observation","table_ref":"anis_observation","label":"COLIBRI OBS","description":"colibri observations","display":10,"count":0,"vo":true,"data_path":"/mnt/mount","selectable_row":true,"project_name":"colibri"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/3/dataset +curl -d '{"name":"anis_observation","table_ref":"anis_observation","label":"COLIBRI OBS","description":"colibri observations","display":10,"count":0,"vo":true,"data_path":"/mnt/mount","selectable_row":true,"config":{},"project_name":"colibri"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/3/dataset # Add COLIBRI anis_observation default criteria family, output families and output categories curl -d '{"label":"Default criteria family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/anis_observation/criteria-family diff --git a/src/Action/SearchAction.php b/src/Action/SearchAction.php index 58e84b273f5193efc866d046f2925ca928714862..b15d43cce8014dca805567a6bfcc172195ebc539 100644 --- a/src/Action/SearchAction.php +++ b/src/Action/SearchAction.php @@ -103,6 +103,11 @@ final class SearchAction extends AbstractAction $attributes = $this->select($queryBuilder, $dataset, explode(';', $queryParams['a'])); } + // The special parameter cs is not mandatory and represents the Cone Search + if (array_key_exists('cs', $queryParams)) { + $this->coneSearch($queryBuilder, $dataset, $queryParams['cs']); + } + // The parameter c is not mandatory and represents the SQL where clause if (array_key_exists('c', $queryParams)) { $this->where($queryBuilder, $dataset, explode(';', $queryParams['c'])); @@ -156,6 +161,67 @@ final class SearchAction extends AbstractAction return $attributes; } + /** + * Adds the cone search clause to the request + * + * @param QueryBuilder $queryBuilder Represents the query being built + * @param Dataset $dataset Represents the requested dataset + * @param string $param The substring of the url (parameter cs) + */ + private function coneSearch(QueryBuilder $queryBuilder, Dataset $dataset, string $param): void + { + if (count(explode(':', $param)) < 3) { + throw SearchException::badNumberOfParamsForConeSearch(); + } + + list($ra, $dec, $radius) = explode(':', $param); + $coneSearchConfig = $dataset->getConfig()['cone_search']; + + if ($coneSearchConfig['enabled'] !== true) { + throw SearchException::coneSearchUnavailable(); + } + + $attributeRa = $this->getAttribute($dataset, $coneSearchConfig['column_ra']); + $attributeDec = $this->getAttribute($dataset, $coneSearchConfig['column_dec']); + $columnRa = $dataset->getTableRef() . '.' . $attributeRa->getName(); + $columnDec = $dataset->getTableRef() . '.' . $attributeDec->getName(); + + $cdcl2 = pow(cos($dec * (M_PI * 2) / 360), 2); + if ($radius == 0) { + $radius = 1 / 1000000; + } + $radius2 = pow($radius, 2); + + $raddeg = $radius / 3600; + $decmin = $dec - $raddeg; + $decmax = $dec + $raddeg; + if ($decmin < -90 || $decmax > 90) { + $ramin = 0; + $ramax = 360; + } else { + $ra_corrected_radius = $raddeg / cos(deg2rad(abs($dec) + $raddeg)); + $ramin = $ra - $ra_corrected_radius; + $ramax = $ra + $ra_corrected_radius; + } + + $coneSearchValue = '(' . $cdcl2 . ' * (' . $ra . ' - ' . $columnRa . ') * (' . $ra . ' - ' . $columnRa . '))'; + $coneSearchValue .= ' + ((' . $dec . ' - ' . $columnDec . ') * (' . $dec . ' - ' . $columnDec . '))'; + $coneSearchCriterion = $queryBuilder->expr()->lte($coneSearchValue, $radius2); + $raCriterion = (new CompositeExpression(CompositeExpression::TYPE_AND, [ + $queryBuilder->expr()->gte($columnRa, $ramin), + $queryBuilder->expr()->lte($columnRa, $ramax) + ])); + $decCriterion = (new CompositeExpression(CompositeExpression::TYPE_AND, [ + $queryBuilder->expr()->gte($columnDec, $decmin), + $queryBuilder->expr()->lte($columnDec, $decmax) + ])); + $queryBuilder->where(new CompositeExpression(CompositeExpression::TYPE_AND, [ + $coneSearchCriterion, + $raCriterion, + $decCriterion + ])); + } + /** * Adds the where clause to the request * @@ -185,7 +251,7 @@ final class SearchAction extends AbstractAction ); $expressions[] = $operator->getExpression(); } - $queryBuilder->where(new CompositeExpression(CompositeExpression::TYPE_AND, $expressions)); + $queryBuilder->andWhere(new CompositeExpression(CompositeExpression::TYPE_AND, $expressions)); } /** diff --git a/src/Utils/Operator/LessThanEqual.php b/src/Utils/Operator/LessThanEqual.php index ec0315df06ce6a6872e58d60392dd0e8fd6c4fed..0a3bcae1a51fdf6069dfdd84e58bbef95db41a73 100644 --- a/src/Utils/Operator/LessThanEqual.php +++ b/src/Utils/Operator/LessThanEqual.php @@ -49,7 +49,7 @@ class LessThanEqual extends Operator * * @return string */ - public function getExpression() : string + public function getExpression(): string { return $this->expr->lte($this->column, $this->getSqlValue($this->value)); } diff --git a/src/Utils/SearchException.php b/src/Utils/SearchException.php index 67b44dc4e33ffc2870abc4f1de35236599e8b038..1ac20014c117aae22b40b52fe52ffb30068e7bfa 100644 --- a/src/Utils/SearchException.php +++ b/src/Utils/SearchException.php @@ -87,6 +87,22 @@ class SearchException extends Exception return new self("Limit (p) needs 2 params to work"); } + /** + * @return SearchException + */ + public static function badNumberOfParamsForConeSearch(): SearchException + { + return new self("Cone search (cs) needs 3 params to work"); + } + + /** + * @return SearchException + */ + public static function coneSearchUnavailable(): SearchException + { + return new self("The cone search is unavailable for this dataset"); + } + /** * @return SearchException */