Skip to content
Merged
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **SMELL-013: Migrated all classes to `CrazyGoat\ZVec\` namespace with PSR-4 autoloading** (#94)
- All library classes now live under `CrazyGoat\ZVec\` namespace
- Global class names preserved via `class_alias()` for backward compatibility
- Use `CrazyGoat\ZVec\ZVec` with `use` statement or keep using global `ZVec` — both work
- Added `tests/test_namespace_bc.phpt` to verify both namespace styles
- Removed `classmap` from `composer.json` — PSR-4 autoloading now handles everything
- **SMELL-009: Added `queryWithReranker()` method for type-safe reranked queries** (#90)
- New `queryWithReranker()` method on `ZVec` returns `ZVecRerankedDoc[]` — static analysis tools can infer the correct return type
- Supports `string|ZVecVectorQuery` as field name, with all existing query parameters
- Routes FP64 queries via internal `queryWithRerankerFp64()` helper

### Deprecated

- **SMELL-013: Global namespace class names are deprecated** (#94)
- Use `use CrazyGoat\ZVec\ZVec;` instead of global `ZVec`
- Global aliases remain for backward compatibility but may be removed in a future major version
- **SMELL-009: The `$reranker` parameter on `query()` and `queryFp64()` is deprecated** (#90)
- Passing `$reranker` to `query()` now triggers `E_USER_DEPRECATED` and delegates to `queryWithReranker()`
- Existing code continues to work (backward compatible) but should migrate to `queryWithReranker()`
Expand Down
5 changes: 1 addition & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
"autoload": {
"psr-4": {
"CrazyGoat\\ZVec\\": "src/"
},
"classmap": [
"src/"
]
}
},
"bin": [
"bin/zvec-install"
Expand Down
25 changes: 25 additions & 0 deletions src/ZVec.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/ZVecException.php';
Expand All @@ -14,6 +18,10 @@
require_once __DIR__ . '/ZVecGroupByVectorQuery.php';
require_once __DIR__ . '/ZVecSchema.php';
require_once __DIR__ . '/ZVecDoc.php';
require_once __DIR__ . '/ZVecReRanker.php';
require_once __DIR__ . '/ZVecRerankedDoc.php';
require_once __DIR__ . '/ZVecRrfReRanker.php';
require_once __DIR__ . '/ZVecWeightedReRanker.php';

class ZVec
{
Expand Down Expand Up @@ -1644,3 +1652,20 @@ public function getFieldSchema(string $fieldName): ZVecFieldSchema
return new ZVecFieldSchema($out);
}
}

// Backward-compatible aliases for global namespace usage
class_alias(ZVec::class, 'ZVec');
class_alias(ZVecException::class, 'ZVecException');
class_alias(ZVecSchema::class, 'ZVecSchema');
class_alias(ZVecDoc::class, 'ZVecDoc');
class_alias(ZVecCollectionOptions::class, 'ZVecCollectionOptions');
class_alias(ZVecCollectionStats::class, 'ZVecCollectionStats');
class_alias(ZVecFieldSchema::class, 'ZVecFieldSchema');
class_alias(ZVecIndexParams::class, 'ZVecIndexParams');
\class_alias(ZVecQueryInterface::class, 'ZVecQueryInterface');
class_alias(ZVecVectorQuery::class, 'ZVecVectorQuery');
class_alias(ZVecGroupByVectorQuery::class, 'ZVecGroupByVectorQuery');
\class_alias(ZVecReRanker::class, 'ZVecReRanker');
class_alias(ZVecRerankedDoc::class, 'ZVecRerankedDoc');
class_alias(ZVecRrfReRanker::class, 'ZVecRrfReRanker');
class_alias(ZVecWeightedReRanker::class, 'ZVecWeightedReRanker');
2 changes: 2 additions & 0 deletions src/ZVecCollectionOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

class ZVecCollectionOptions
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecCollectionStats.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecCollectionStats
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecDoc
Expand Down
5 changes: 5 additions & 0 deletions src/ZVecException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use RuntimeException;
use Throwable;

if (extension_loaded('zvec')) return;

class ZVecException extends RuntimeException
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecFieldSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecFieldSchema
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecGroupByVectorQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecGroupByVectorQuery implements ZVecQueryInterface
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecIndexParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecIndexParams
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecQueryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

interface ZVecQueryInterface
Expand Down
2 changes: 2 additions & 0 deletions src/ZVecReRanker.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

/**
Expand Down
2 changes: 2 additions & 0 deletions src/ZVecRerankedDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

/**
Expand Down
2 changes: 2 additions & 0 deletions src/ZVecRrfReRanker.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/ZVecReRanker.php';
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecSchema
Expand Down
4 changes: 4 additions & 0 deletions src/ZVecVectorQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

use FFI;

if (extension_loaded('zvec')) return;

class ZVecVectorQuery implements ZVecQueryInterface
Expand Down
2 changes: 2 additions & 0 deletions src/ZVecWeightedReRanker.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/ZVec.php';
Expand Down
4 changes: 4 additions & 0 deletions src/embeddings/EmbeddingInterfaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/../ZVecException.php';

/**
* Interface for dense embedding functions.
* Converts text input into dense vector representations.
Expand Down
2 changes: 2 additions & 0 deletions src/embeddings/OpenAIDenseEmbedding.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/EmbeddingInterfaces.php';
Expand Down
2 changes: 2 additions & 0 deletions src/embeddings/QwenDenseEmbedding.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace CrazyGoat\ZVec;

if (extension_loaded('zvec')) return;

require_once __DIR__ . '/EmbeddingInterfaces.php';
Expand Down
6 changes: 5 additions & 1 deletion tests/test_embeddings_integration.phpt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
--TEST--
Extensions: Embedding Functions - Integration with ZVec
--SKIPIF--
<?php if (!extension_loaded('zvec') && !extension_loaded('ffi')) die('skip Neither zvec extension nor FFI available'); ?>
<?php if (!extension_loaded('ffi')) die('skip FFI extension not available'); ?>
--FILE--
<?php
require_once __DIR__ . '/../src/embeddings/EmbeddingInterfaces.php';

use CrazyGoat\ZVec\ApiEmbeddingFunction;
use CrazyGoat\ZVec\DenseEmbeddingFunction;
use CrazyGoat\ZVec\ZVecException;

/**
* Mock embedding function for testing (simulates API without making HTTP calls)
*/
Expand Down
32 changes: 19 additions & 13 deletions tests/test_embeddings_interfaces.phpt
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
--TEST--
Extensions: Embedding Functions - Interface validation
--SKIPIF--
<?php if (!extension_loaded('zvec') && !extension_loaded('ffi')) die('skip Neither zvec extension nor FFI available'); ?>
<?php if (!extension_loaded('ffi')) die('skip FFI extension not available'); ?>
--FILE--
<?php
require_once __DIR__ . '/../src/embeddings/EmbeddingInterfaces.php';
require_once __DIR__ . '/../src/embeddings/OpenAIDenseEmbedding.php';
require_once __DIR__ . '/../src/embeddings/QwenDenseEmbedding.php';

use CrazyGoat\ZVec\DenseEmbeddingFunction;
use CrazyGoat\ZVec\SparseEmbeddingFunction;
use CrazyGoat\ZVec\ApiEmbeddingFunction;
use CrazyGoat\ZVec\OpenAIDenseEmbedding;
use CrazyGoat\ZVec\QwenDenseEmbedding;

// Test 1: Verify interfaces exist
echo "Interface validation:\n";

if (interface_exists('DenseEmbeddingFunction')) {
if (interface_exists(DenseEmbeddingFunction::class)) {
echo "PASS: DenseEmbeddingFunction interface exists\n";
} else {
echo "FAIL: DenseEmbeddingFunction interface not found\n";
exit(1);
}

if (interface_exists('SparseEmbeddingFunction')) {
if (interface_exists(SparseEmbeddingFunction::class)) {
echo "PASS: SparseEmbeddingFunction interface exists\n";
} else {
echo "FAIL: SparseEmbeddingFunction interface not found\n";
exit(1);
}

// Test 2: Verify OpenAIDenseEmbedding class exists and implements interface
if (class_exists('OpenAIDenseEmbedding')) {
if (class_exists(OpenAIDenseEmbedding::class)) {
echo "PASS: OpenAIDenseEmbedding class exists\n";

$reflection = new ReflectionClass('OpenAIDenseEmbedding');
if ($reflection->implementsInterface('DenseEmbeddingFunction')) {
$reflection = new ReflectionClass(OpenAIDenseEmbedding::class);
if ($reflection->implementsInterface(DenseEmbeddingFunction::class)) {
echo "PASS: OpenAIDenseEmbedding implements DenseEmbeddingFunction\n";
} else {
echo "FAIL: OpenAIDenseEmbedding does not implement DenseEmbeddingFunction\n";
exit(1);
}

if ($reflection->isSubclassOf('ApiEmbeddingFunction')) {
if ($reflection->isSubclassOf(ApiEmbeddingFunction::class)) {
echo "PASS: OpenAIDenseEmbedding extends ApiEmbeddingFunction\n";
} else {
echo "FAIL: OpenAIDenseEmbedding does not extend ApiEmbeddingFunction\n";
Expand All @@ -49,18 +55,18 @@ if (class_exists('OpenAIDenseEmbedding')) {
}

// Test 3: Verify QwenDenseEmbedding class exists and implements interface
if (class_exists('QwenDenseEmbedding')) {
if (class_exists(QwenDenseEmbedding::class)) {
echo "PASS: QwenDenseEmbedding class exists\n";

$reflection = new ReflectionClass('QwenDenseEmbedding');
if ($reflection->implementsInterface('DenseEmbeddingFunction')) {
$reflection = new ReflectionClass(QwenDenseEmbedding::class);
if ($reflection->implementsInterface(DenseEmbeddingFunction::class)) {
echo "PASS: QwenDenseEmbedding implements DenseEmbeddingFunction\n";
} else {
echo "FAIL: QwenDenseEmbedding does not implement DenseEmbeddingFunction\n";
exit(1);
}

if ($reflection->isSubclassOf('ApiEmbeddingFunction')) {
if ($reflection->isSubclassOf(ApiEmbeddingFunction::class)) {
echo "PASS: QwenDenseEmbedding extends ApiEmbeddingFunction\n";
} else {
echo "FAIL: QwenDenseEmbedding does not extend ApiEmbeddingFunction\n";
Expand All @@ -72,7 +78,7 @@ if (class_exists('QwenDenseEmbedding')) {
}

// Test 4: Verify constants
$openaiReflection = new ReflectionClass('OpenAIDenseEmbedding');
$openaiReflection = new ReflectionClass(OpenAIDenseEmbedding::class);
$constants = $openaiReflection->getConstants();

$expectedConstants = ['MODEL_SMALL', 'MODEL_LARGE', 'MODEL_ADA'];
Expand All @@ -85,7 +91,7 @@ foreach ($expectedConstants as $const) {
}
}

$qwenReflection = new ReflectionClass('QwenDenseEmbedding');
$qwenReflection = new ReflectionClass(QwenDenseEmbedding::class);
$constants = $qwenReflection->getConstants();

$expectedConstants = ['MODEL_V4', 'MODEL_V3', 'MODEL_V2', 'MODEL_V1'];
Expand Down
Loading
Loading