-
Notifications
You must be signed in to change notification settings - Fork 1
v3.1.0 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## v3.1.0 (2025-12-29)
### Major: Spatial Indexing + MongoDB-Style Comparison Operators
This release introduces **R-tree spatial indexing** for geospatial queries and **MongoDB-style comparison operators** for advanced filtering.
---
### Part 1: R-tree Spatial Indexing
#### GeoJSON Support
Full GeoJSON geometry support:
- **Point** - Single location `[lon, lat]`
- **LineString** - Path/route
- **Polygon** - Area with boundary (supports holes)
- **MultiPoint**, **MultiLineString**, **MultiPolygon**
- **GeometryCollection**
```php
// Insert GeoJSON data
$db->insert("restaurants", [
'name' => 'Ottoman Kitchen',
'location' => [
'type' => 'Point',
'coordinates' => [28.9784, 41.0082] // [longitude, latitude]
]
]);
```
#### Spatial Index Management
```php
// Create R-tree index
$db->createSpatialIndex("restaurants", "location");
// Returns: ["success" => true, "indexed" => 150]
// Check if index exists
$db->hasSpatialIndex("restaurants", "location"); // true/false
// List all spatial indexes
$db->getSpatialIndexes("restaurants"); // ["location"]
// Drop index
$db->dropSpatialIndex("restaurants", "location");
// Rebuild index
$db->rebuildSpatialIndex("restaurants", "location");
```
#### Spatial Query Methods
```php
// Find within radius (km)
$nearby = $db->withinDistance("restaurants", "location", 28.97, 41.00, 5);
// Find in bounding box
$inArea = $db->withinBBox("restaurants", "location", 28.97, 41.00, 29.00, 41.03);
// Find K nearest
$closest = $db->nearest("restaurants", "location", 28.97, 41.00, 10);
// Find within polygon
$inPolygon = $db->withinPolygon("restaurants", "location", $polygon);
```
#### Query Builder Integration
```php
$results = $db->query("restaurants")
->withinDistance('location', 28.97, 41.00, 5)
->where(['open_now' => true])
->withDistance('location', 28.97, 41.00)
->sort('_distance', 'asc')
->limit(10)
->get();
```
#### Spatial Index File Structure
```
hash-dbname.nonedb.sidx.location # R-tree spatial index
hash-dbname.nonedb.gsidx.location # Global spatial index (sharded)
```
---
### Part 2: MongoDB-Style Comparison Operators
#### Operator Reference
| Operator | Description | Example |
|----------|-------------|---------|
| `$gt` | Greater than | `['age' => ['$gt' => 18]]` |
| `$gte` | Greater than or equal | `['price' => ['$gte' => 100]]` |
| `$lt` | Less than | `['stock' => ['$lt' => 10]]` |
| `$lte` | Less than or equal | `['rating' => ['$lte' => 5]]` |
| `$eq` | Equal (explicit) | `['status' => ['$eq' => 'active']]` |
| `$ne` | Not equal | `['role' => ['$ne' => 'guest']]` |
| `$in` | Value in array | `['category' => ['$in' => ['a', 'b']]]` |
| `$nin` | Value not in array | `['tag' => ['$nin' => ['spam']]]` |
| `$exists` | Field exists | `['email' => ['$exists' => true]]` |
| `$like` | Pattern match | `['name' => ['$like' => '^John']]` |
| `$regex` | Regular expression | `['email' => ['$regex' => '@gmail.com$']]` |
| `$contains` | Array/string contains | `['tags' => ['$contains' => 'featured']]` |
#### Usage Examples
```php
// Range query
$results = $db->query("products")
->where([
'price' => ['$gte' => 100, '$lte' => 500],
'stock' => ['$gt' => 0]
])
->get();
// Multiple operators
$results = $db->query("users")
->where([
'role' => ['$in' => ['admin', 'moderator']],
'status' => ['$ne' => 'banned'],
'email' => ['$exists' => true]
])
->get();
// Combined with spatial queries
$results = $db->query("restaurants")
->withinDistance('location', 28.97, 41.00, 5)
->where([
'rating' => ['$gte' => 4.0],
'cuisine' => ['$in' => ['turkish', 'italian']]
])
->get();
```
---
### Part 3: R-tree Performance Optimizations
| Optimization | Description |
|--------------|-------------|
| **Parent Pointer Map** | O(1) parent lookup instead of O(n) tree scan |
| **Linear Split Algorithm** | O(n) seed selection instead of O(n²) quadratic split |
| **Dirty Flag Pattern** | Single disk write per batch instead of n writes |
| **Distance Memoization** | Cached Haversine distance calculations |
| **Centroid Caching** | Cached geometry centroid calculations |
| **Node Size 32** | Fewer tree levels and splits (increased from 16) |
| **Adaptive nearest()** | Exponential radius expansion for efficient k-NN |
#### Performance Results
| Operation | 100 | 1K | 5K |
|-----------|-----|-----|-----|
| createSpatialIndex | 2.4 ms | 81 ms | 423 ms |
| withinDistance (10km) | 3 ms | 32 ms | 166 ms |
| withinBBox | 0.7 ms | 7 ms | 38 ms |
| nearest(10) | 2 ms | 2 ms | 2.4 ms |
#### Comparison Operator Performance
| Operator | 100 | 1K | 5K |
|----------|-----|-----|-----|
| `$gt`, `$gte`, `$lt`, `$lte` | 0.7 ms | 6-7 ms | 33-38 ms |
| `$in`, `$nin` | 0.7 ms | 6.5-7 ms | 36-37 ms |
| `$like`, `$regex` | 0.7 ms | 7 ms | 39 ms |
| Complex (4 operators) | 0.7 ms | 7.5 ms | 43 ms |
---
### New Methods
#### Spatial Index Methods (noneDB)
- `createSpatialIndex($dbname, $field)` - Create R-tree index
- `hasSpatialIndex($dbname, $field)` - Check if index exists
- `getSpatialIndexes($dbname)` - List all spatial indexes
- `dropSpatialIndex($dbname, $field)` - Remove index
- `rebuildSpatialIndex($dbname, $field)` - Rebuild index
- `withinDistance($dbname, $field, $lon, $lat, $km)` - Find within radius
- `withinBBox($dbname, $field, $minLon, $minLat, $maxLon, $maxLat)` - Find in bbox
- `nearest($dbname, $field, $lon, $lat, $k)` - Find K nearest
- `withinPolygon($dbname, $field, $polygon)` - Find in polygon
- `validateGeoJSON($geometry)` - Validate GeoJSON
#### Query Builder Methods (noneDBQuery)
- `withinDistance($field, $lon, $lat, $km)` - Spatial: within radius
- `withinBBox($field, $minLon, $minLat, $maxLon, $maxLat)` - Spatial: within bbox
- `nearest($field, $lon, $lat, $k)` - Spatial: K nearest
- `withinPolygon($field, $polygon)` - Spatial: within polygon
- `withDistance($field, $lon, $lat)` - Add `_distance` field to results
#### Comparison Operators in where()
- `$gt`, `$gte`, `$lt`, `$lte` - Numeric comparisons
- `$eq`, `$ne` - Equality comparisons
- `$in`, `$nin` - Array membership
- `$exists` - Field existence
- `$like` - Pattern matching (case-insensitive)
- `$regex` - Regular expression matching
- `$contains` - Array/string contains
---
### Test Results
- **970 tests, 3079 assertions** (all passing)
- 42 new comparison operator tests
- 24 new spatial + operator combination tests
- 48 new query documentation tests
- Full sharded spatial index support verified
### Documentation
New documentation files in `docs/`:
- `QUERY.md` - Complete query builder reference
- `SPATIAL.md` - Spatial indexing guide
- `CONFIGURATION.md` - Configuration options
- `API.md` - Complete API reference
- `BENCHMARKS.md` - Performance benchmarks
### Breaking Changes
None. All v3.0.x APIs remain backward compatible.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
v3.1.0 (2025-12-29)
Major: Spatial Indexing + MongoDB-Style Comparison Operators
This release introduces R-tree spatial indexing for geospatial queries and MongoDB-style comparison operators for advanced filtering.
Part 1: R-tree Spatial Indexing
GeoJSON Support
Full GeoJSON geometry support:
[lon, lat]Spatial Index Management
Spatial Query Methods
All distance parameters and results are in meters.
Query Builder Integration
Spatial Index File Structure
Part 2: MongoDB-Style Comparison Operators
Operator Reference
$gt['age' => ['$gt' => 18]]$gte['price' => ['$gte' => 100]]$lt['stock' => ['$lt' => 10]]$lte['rating' => ['$lte' => 5]]$eq['status' => ['$eq' => 'active']]$ne['role' => ['$ne' => 'guest']]$in['category' => ['$in' => ['a', 'b']]]$nin['tag' => ['$nin' => ['spam']]]$exists['email' => ['$exists' => true]]$like['name' => ['$like' => '^John']]$regex['email' => ['$regex' => '@gmail.com$']]$contains['tags' => ['$contains' => 'featured']]Usage Examples
Part 3: R-tree Performance Optimizations
Performance Results
Comparison Operator Performance
$gt,$gte,$lt,$lte$in,$nin$like,$regexNew Methods
Spatial Index Methods (noneDB)
createSpatialIndex($dbname, $field)- Create R-tree indexhasSpatialIndex($dbname, $field)- Check if index existsgetSpatialIndexes($dbname)- List all spatial indexesdropSpatialIndex($dbname, $field)- Remove indexrebuildSpatialIndex($dbname, $field)- Rebuild indexwithinDistance($dbname, $field, $lon, $lat, $meters)- Find within radius (meters)withinBBox($dbname, $field, $minLon, $minLat, $maxLon, $maxLat)- Find in bboxnearest($dbname, $field, $lon, $lat, $k)- Find K nearestwithinPolygon($dbname, $field, $polygon)- Find in polygonvalidateGeoJSON($geometry)- Validate GeoJSONQuery Builder Methods (noneDBQuery)
withinDistance($field, $lon, $lat, $meters)- Spatial: within radius (meters)withinBBox($field, $minLon, $minLat, $maxLon, $maxLat)- Spatial: within bboxnearest($field, $lon, $lat, $k)- Spatial: K nearestwithinPolygon($field, $polygon)- Spatial: within polygonwithDistance($field, $lon, $lat)- Add_distancefield to results (meters)Comparison Operators in where()
$gt,$gte,$lt,$lte- Numeric comparisons$eq,$ne- Equality comparisons$in,$nin- Array membership$exists- Field existence$like- Pattern matching (case-insensitive)$regex- Regular expression matching$contains- Array/string containsTest Results
Documentation
New documentation files in
docs/:QUERY.md- Complete query builder referenceSPATIAL.md- Spatial indexing guideCONFIGURATION.md- Configuration optionsAPI.md- Complete API referenceBENCHMARKS.md- Performance benchmarksBreaking Changes
None. Spatial indexing is a new feature in v3.1.0.
Note: All spatial distance parameters and results use meters as the unit:
withinDistance()- distance parameter in meters_distancefield in results is in metersnearest()maxDistanceoption is in meters