Skip to content

Commit

Permalink
Merge branch 'main' into box-stringable
Browse files Browse the repository at this point in the history
  • Loading branch information
ahawlitschek authored Jan 4, 2025
2 parents 2a766b7 + 99161da commit ad2cdb3
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `Castable` to all geometries to use them as casters, instead of the `GeometryWKBCast`
- Added `Castable` to all boxes to use them as casters, instead of the `BBoxCast`
- Added `Aliased` Expression class as wrapper for `AS` in query selects
- Added `->as()` helper method on MagellanBaseExpression
- Added `withMagellanCasts()` as EloquentBuilder macro
- Added `AsGeometry` and `AsGeography` database expressions
- Added `fromString()` to `Box` classes to create a box from a string
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,15 +391,14 @@ Most of the `ST`-prefixed functions can be accessed using the static functions o
```php
use Clickbar\Magellan\Data\Geometries\Point;
use Clickbar\Magellan\Database\PostgisFunctions\ST;
use Clickbar\Magellan\Database\Expressions\Aliased;
```

Assuming we have our ships current position and want to query all ports with their distance:

```php
$currentShipPosition = Point::makeGeodetic(50.107471773560114, 8.679861151457937);
$portsWithDistance = Port::select() // use select() because we want SELECT *, distance and not only the distance
->addSelect(new Aliased(ST::distanceSphere($currentShipPosition, 'location'), 'distance_to_ship'))
->addSelect(ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'))
->get();
```

Expand All @@ -408,7 +407,7 @@ Since we cannot sail over the whole world, let's limit the distance to max. 50.0
```php
$currentShipPosition = Point::makeGeodetic(50.107471773560114, 8.679861151457937);
$portsWithDistance = Port::select()
->addSelect(new Aliased(ST::distanceSphere($currentShipPosition, 'location'), 'distance_to_ship'))
->addSelect(ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'))
->where(ST::distanceSphere($currentShipPosition, 'location'), '<=', 50000)
->get();
```
Expand All @@ -418,7 +417,7 @@ Now let us order them based on the distance:
```php
$currentShipPosition = Point::makeGeodetic(50.107471773560114, 8.679861151457937);
$portsWithDistance = Port::select()
->addSelect(new Aliased(ST::distanceSphere($currentShipPosition, 'location'), 'distance_to_ship'))
->addSelect(ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'))
->where(ST::distanceSphere($currentShipPosition, 'location'), '<=', 50000)
->orderBy(ST::distanceSphere($currentShipPosition, 'location'))
->get();
Expand All @@ -432,16 +431,16 @@ No problem:
$hullsWithArea = Port::query()
->select([
'country',
new Aliased(ST::convexHull(ST::collect('location')), 'hull'),
new Aliased(ST::area(ST::convexHull(ST::collect('location'))), 'area')
ST::convexHull(ST::collect('location'))->as('hull'),
ST::area(ST::convexHull(ST::collect('location')))->as('area')
])
->groupBy('country')
->get();
```
### Alias in select
Since we use Laravel Database Expressions for a seamless integration into the default select(...), where(..) and so on, you need to add an alias using the `Aliased` expression:
Since we use Laravel Database Expressions for a seamless integration into the default select(...), where(..) and so on, you need to use the `as(string)` method on our ST::function expressions:
```php
->select(new Aliased(ST::distanceSphere($currentShipPosition, 'location'), 'distance_to_ship'))
->select(ST::distanceSphere($currentShipPosition, 'location')->as('distance_to_ship'))
//--> leads to SELECT ST_DistanceSphere(<<currentShipPosition, 'location') AS distance_to_ship
```

Expand All @@ -457,7 +456,7 @@ Considering we want to buffer the location of our ports by 50 meters. Looking in
Therefore, we need to cast our points from the location colum to geography before handing them over to the buffer function:
```php
$bufferedPorts = Port::query()
->select(new Aliased(ST::buffer(new AsGeography('location'), 50), as: 'buffered_location'))
->select(ST::buffer(new AsGeography('location'), 50)->as('buffered_location'))
->withCasts(['buffered_location' => Polygon::class])
->get();
```
Expand All @@ -475,8 +474,8 @@ Since "hull" will return a geometry we need a cast for it. Instead of adding eac
$hullWithArea = Port::query()
->select([
'country',
new Aliased(ST::convexHull(ST::collect('location')), 'hull'),
new Aliased(ST::area(ST::convexHull(ST::collect('location'))), 'area')
ST::convexHull(ST::collect('location'))->as('hull'),
ST::area(ST::convexHull(ST::collect('location')))->as('area')
])
->groupBy('country')
->withMagellanCasts() /* <======= */
Expand All @@ -487,8 +486,8 @@ $hullWithArea = Port::query()
$hullWithArea = Port::query()
->select([
'country',
new Aliased(ST::convexHull(ST::collect('location')), 'hull'),
new Aliased(ST::area(ST::convexHull(ST::collect('location'))), 'area')
ST::convexHull(ST::collect('location'))->as('hull'),
ST::area(ST::convexHull(ST::collect('location')))->as('area')
])
->groupBy('country')
->withCasts(['hull' => Polygon::class]) /* <======= */
Expand Down
6 changes: 6 additions & 0 deletions src/Database/MagellanExpressions/MagellanBaseExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Clickbar\Magellan\Database\Builder\StringifiesQueryParameters;
use Clickbar\Magellan\Database\Builder\ValueParameter;
use Clickbar\Magellan\Database\Expressions\Aliased;
use Clickbar\Magellan\IO\Generator\BaseGenerator;
use Clickbar\Magellan\IO\Generator\WKT\WKTGenerator;
use Illuminate\Contracts\Database\Query\Expression;
Expand Down Expand Up @@ -65,6 +66,11 @@ public function returnsBbox(): bool
return $this instanceof MagellanBBoxExpression;
}

public function as(string $name): Expression
{
return new Aliased($this, $name);
}

// ######################## Database Expression Building ########################

public function getValue(Grammar $grammar): float|int|string
Expand Down
15 changes: 7 additions & 8 deletions tests/Models/SpatialQueriesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Clickbar\Magellan\Data\Geometries\MultiPoint;
use Clickbar\Magellan\Data\Geometries\Point;
use Clickbar\Magellan\Data\Geometries\Polygon;
use Clickbar\Magellan\Database\Expressions\Aliased;
use Clickbar\Magellan\Database\Expressions\AsGeography;
use Clickbar\Magellan\Database\PostgisFunctions\ST;
use Clickbar\Magellan\IO\Parser\WKB\WKBParser;
Expand Down Expand Up @@ -93,7 +92,7 @@
$distances = Location::query()
->select([
'name',
new Aliased(ST::distance(new AsGeography('location'), new AsGeography($berlinPoint)), 'distance_in_meters'),
ST::distance(new AsGeography('location'), new AsGeography($berlinPoint))->as('distance_in_meters'),
])
->orderBy('distance_in_meters')
->get();
Expand Down Expand Up @@ -123,7 +122,7 @@

$closestPoint = Location::query()
->where('name', 'Berlin')
->select(new Aliased(ST::closestPoint('location', $hamburg), 'closest_point'))
->select(ST::closestPoint('location', $hamburg)->as('closest_point'))
->withMagellanCasts()
->first();

Expand All @@ -147,7 +146,7 @@

$shortestLine = Location::query()
->where('name', 'Berlin')
->select(new Aliased(ST::shortestLine('location', $hamburg), 'shortest_line'))
->select(ST::shortestLine('location', $hamburg)->as('shortest_line'))
->withMagellanCasts()
->first();

Expand All @@ -164,7 +163,7 @@
// Check if the point is valid and simple
$validation = Location::query()
->where('id', $berlin->id)
->select(new Aliased(ST::isSimple('location'), 'is_simple'))
->select(ST::isSimple('location')->as('is_simple'))
->first();

expect($validation->is_simple)->toBeTrue();
Expand All @@ -181,8 +180,8 @@
$dimensions = Location::query()
->where('id', $berlin->id)
->select([
new Aliased(ST::coordDim('location'), 'coord_dim'),
new Aliased(ST::nDims('location'), 'n_dims'),
ST::coordDim('location')->as('coord_dim'),
ST::nDims('location')->as('n_dims'),
])
->first();

Expand Down Expand Up @@ -214,7 +213,7 @@
// Calculate 3D distance
$distances = $location3d::query()
->where('name', 'Berlin')
->select(new Aliased(ST::distance3D('location', $hamburgWithAltitude), 'distance_3d'))
->select(ST::distance3D('location', $hamburgWithAltitude)->as('distance_3d'))
->first();

expect((float) $distances->distance_3d)->toBeFloat();
Expand Down

0 comments on commit ad2cdb3

Please sign in to comment.