Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
19ceb79
feat(index): Rebuild concurrency lock to prevent data loss from concu…
ykan821 Jun 8, 2026
79534c4
fix(index): restore query state via try-finally after clone, validate…
ykan821 Jun 11, 2026
a34f6b0
feat(dsl): unify ClausesSupport on append semantics
ykan821 Jun 11, 2026
d22085b
fix(index): add totalRelation(), return null from aggregations()
ykan821 Jun 12, 2026
b58fdff
fix(index): Rebuild::rollback() iterates all aliases, validate Index:…
ykan821 Jun 12, 2026
dc76f10
refactor(dsl): split Node/Query constructors into from* methods, upda…
ykan821 Jun 12, 2026
8c359ff
feat(index): onError replaces skipErrors in Bulk/Rebuild, drop rebuil…
ykan821 Jun 12, 2026
1ce2156
refactor(index): rename AggregationShortcut to StatsSupport, add stats()
ykan821 Jun 12, 2026
a9e4686
refactor(index): extract ClientManager, EventDispatcher, Pagination f…
ykan821 Jun 12, 2026
8a5ea87
refactor(index): drop insert/deprecated proxies, add on/newQuery/newD…
ykan821 Jun 12, 2026
b5553f5
docs: update TODO — mark completed items, add PHP 8 modernization and…
ykan821 Jun 12, 2026
789844a
refactor(dsl): rename Shared/ to Support/
ykan821 Jun 12, 2026
fb13313
refactor(index): PHP 8 modernization (Index layer)
ykan821 Jun 13, 2026
32a62eb
docs: remove stray files and clean up 7.x content from README
ykan821 Jun 13, 2026
accae8d
refactor(dsl): PHP 8 modernization and redundancy cleanup (DSL layer)
ykan821 Jun 15, 2026
3fe6ab9
refactor(dsl)!: unify Bucket aggregation naming and simplify Node val…
ykan821 Jun 15, 2026
440729f
refactor(dsl): unify leaf setter parameter name to $value
ykan821 Jun 18, 2026
96d839c
feat(query): add intervals regexp rule
ykan821 Jun 18, 2026
e3b0541
refactor(dsl): unify non-leaf parameter naming and types
ykan821 Jun 18, 2026
fc8cd00
refactor(index): unify named parameters and type Rebuild::source
ykan821 Jun 19, 2026
b64de5a
refactor(index)!: split chunk/cursor iteration API
ykan821 Jun 19, 2026
c518cb7
refactor(index): cursor delegates iteration via yield from
ykan821 Jun 19, 2026
1c8d9d0
refactor(index)!: tighten Rebuild exception handling
ykan821 Jun 23, 2026
c0c020d
chore: upgrade phpunit.xml config, update TODO progress
ykan821 Jun 23, 2026
64f597c
fix(dsl): fix 3 P0 silent data-loss / invalid-DSL issues
ykan821 Jun 24, 2026
7a6e9b5
refactor(dsl): unify Node polymorphic input, array-clause containers …
ykan821 Jun 24, 2026
dccd15e
fix(dsl): Intervals::toArray() merges $_properties, throws on duplica…
ykan821 Jun 24, 2026
a25afdd
refactor(index)!: Manager::delete() refuses to delete alias backing i…
ykan821 Jun 24, 2026
4d03114
fix(index)!: Bulk execute() keeps the queue on error, onError switche…
ykan821 Jun 25, 2026
f2358d5
fix(index): Bulk::create() supports null id for auto-generation
ykan821 Jun 25, 2026
3a1a690
feat(dsl): DeepClone trait for reflective deep-copy of Query/Agg/Node
ykan821 Jun 25, 2026
649c2fa
refactor(index)!: rename Bulk execute() to flush(), sync event names
ykan821 Jun 25, 2026
37a118e
fix: toJson preserves floats / lastPage perPage=0 guard / retryOnConf…
ykan821 Jun 25, 2026
f823cec
refactor: input validation + dead code/symmetry + error message cleanup
ykan821 Jun 25, 2026
daf749a
refactor(index)!: remove Results::hasMore(), use isEmpty() uniformly
ykan821 Jun 25, 2026
cd7e9a9
fix(dsl): AllOf::filter() wraps the value in a Filter node, aligned w…
ykan821 Jun 25, 2026
8a77e28
refactor(dsl): Composite::sources() tightens to array (native source …
ykan821 Jun 25, 2026
30ff8ae
refactor(index)!: Event uses real typed properties, drop magic __get/…
ykan821 Jun 25, 2026
846d1f6
docs: translate tests, CLAUDE.md, and CHANGELOG to English
ykan821 Jun 26, 2026
b35fa03
fix: accept '0' index name, reject empty target, add gapPolicy/@depre…
ykan821 Jun 26, 2026
523498c
feat(dsl): support _name (named query) on all nodes via Node::__call
ykan821 Jun 26, 2026
de3fdb7
test: split ES validation into integration layer
ykan821 Jun 26, 2026
4458723
test(integration): add core DSL ES contract tests
ykan821 Jun 26, 2026
880815c
test(integration): add specialized + aggregation ES contract tests
ykan821 Jun 26, 2026
c9fe00b
test(integration): add Search + Doc contract tests, drop matching mocks
ykan821 Jun 26, 2026
617df8e
test(integration): add Bulk + Manager contract tests, drop matching m…
ykan821 Jun 26, 2026
0714ee9
test(integration): add Rebuild contract tests, drop matching mock
ykan821 Jun 26, 2026
8373c84
test(integration): add StatsSupport contract tests, drop matching mock
ykan821 Jun 26, 2026
1708adf
test: drop mock layer, Event to integration, Results alongside search
ykan821 Jun 26, 2026
5c9e44a
test: class-level index sharing for integration, drop dead code
ykan821 Jun 26, 2026
6fd146e
test: pin Node::toArray invariants; fix when() doc/signature mismatch
ykan821 Jun 26, 2026
c7516fd
refactor(index): move infra classes to Support/ namespace
ykan821 Jun 26, 2026
ed946da
docs: make English the primary README, Chinese at README.zh.md
ykan821 Jun 27, 2026
6dd3b12
fix(index): correct class name in toPaginator() error message
ykan821 Jun 27, 2026
797a024
test: strengthen assertions, move ResultsTest to unit, drop dead ensu…
ykan821 Jun 27, 2026
e8a8a26
test(integration): cover Rebuild lifecycle (rollback/clean/forceUnloc…
ykan821 Jun 27, 2026
6437323
refactor(dsl): precise PHPDoc unions for core builder params + hasPar…
ykan821 Jun 27, 2026
6c970b6
ci: run integration suite in ES job; drop composer audit block-insecure
ykan821 Jun 27, 2026
07f8341
fix: CI integration suite, scalar clause validation, agg dup, rescore…
ykan821 Jun 27, 2026
e85092e
chore: cs-fixer now covers tests/ (was src-only)
ykan821 Jun 27, 2026
3549e6f
fix(dsl): aggs duplicate alias throws for all input forms (was closur…
ykan821 Jun 27, 2026
9ba5bfd
perf: cache DeepClone reflection + avoid clone in Search hot paths
ykan821 Jun 27, 2026
9f1cb94
refactor: extract RegistersAgg trait to Support/
ykan821 Jun 27, 2026
0a0e9b0
fix(index): Doc retryOnConflict/refresh persist across writes (was re…
ykan821 Jun 27, 2026
1a16f9f
fix(dsl): serialization correctness across field-keyed/agg/range/span
ykan821 Jun 28, 2026
6a80c31
feat(index)!: opt-in track_total_hits, rebuild swap rollback
ykan821 Jun 28, 2026
9713576
docs: refresh stale TODO, static-state warning, phpstan stub note
ykan821 Jun 28, 2026
d78eba1
fix: review findings — field-keyed toArray guard, hasMorePages, toPag…
ykan821 Jun 28, 2026
4981cde
docs: track_total_hits defaults to false; property is int|bool
ykan821 Jun 28, 2026
9e6619d
docs(changelog): 8.0.0-beta.5
ykan821 Jun 28, 2026
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
run: composer install --no-interaction --prefer-dist

- name: PHPUnit (with ES validation)
run: vendor/bin/phpunit --testsuite unit
run: vendor/bin/phpunit --testsuite integration
env:
ELASTICKIT_TEST_HOST: http://localhost:9200

Expand All @@ -79,7 +79,7 @@ jobs:
run: composer install --no-interaction --prefer-dist

- name: PHPStan
run: vendor/bin/phpstan analyse
run: vendor/bin/phpstan analyse --memory-limit=256M

- name: PHP-CS-Fixer
run: PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run --diff
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Thumbs.db
.env
.php-cs-fixer.cache
.phpunit.result.cache
.phpunit.cache/
5 changes: 3 additions & 2 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src');
->in([__DIR__ . '/src', __DIR__ . '/tests']);

return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true,
'no_unused_imports' => true,
])
->setFinder($finder);
->setFinder($finder)
->setUnsupportedPhpVersionAllowed(true);
47 changes: 38 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
# Changelog

## [8.0.0-beta.5] - 2026-06-28

### Added

- `Index::$trackTotalHits` (int|bool, default `false`) — opt-in total-hit tracking per index; `true` counts every hit, an int caps the count, `false` omits it.
- `Results::hasMorePages()` — next-page signal that works with or without a total (full-page heuristic when `track_total_hits` is false).
- `PaginationTotalUnavailableException` (in `ElasticKit\Index\Exception`) — thrown by `Results::toPaginator()` when no total is available.

### Changed

- **BC:** `Index` now defaults `track_total_hits` to `false`, so Elasticsearch omits the hit total. `Results::total()`/`lastPage()` return `?int` (null when the total is unavailable), and `toPaginator()` throws unless the index sets `$trackTotalHits = true` (or a count cap). Set `protected int|bool $trackTotalHits = true;` on indexes that paginate.
- `Results::isEmpty()` docblock now points to `hasMorePages()` for "has next page".

### Fixed

- `Node::toArray()` (and field-keyed overrides such as `Intervals`) throw `LogicException` when a field-keyed node has no field set, instead of an uncatchable typed-property `Error`.
- `Agg` empty aggregation body serializes to `{}`, not `[]` (which Elasticsearch rejects).
- `RangeSupport` rejects positional elements beyond the `[start, end]` shorthand instead of leaking them as numeric keys.
- `SpanTerm::term()` emits Elasticsearch's `{value}` key (was `{term}`).
- `Rebuild` alias-swap failures now delete the orphaned new index.

### Deprecated

- `DateHistogram::interval()` — Elasticsearch deprecated the bare `interval` key; use `calendarInterval()`/`fixedInterval()`.

### Removed

- Composer scripts (`analyse` / `cs-check` / `cs-fix`) — run the binaries via your Docker workflow instead.

## [8.0.0-beta.4] - 2026-06-07

### 新增
### Added

- DSL 查询构建器,支持多态参数(字符串/数组/闭包/对象)
- 全量查询类型覆盖:TermLevelFullTextCompoundGeoJoiningSpanShapeSpecialized
- 聚合支持:BucketMetricPipeline 三大类
- 搜索参数:sorthighlightrescorecollapsesuggestpost_filterknn
- Index 层:CRUD、分页、游标遍历、批量写入(Bulk)、零停机重建(Rebuild
- 事件系统:搜索、批量操作、重建各阶段的事件监听
- OOP 风格:每个查询/聚合类型独立 Node 类,支持链式调用和增量构建
- 原生 DSL 透传:未覆盖的 ES 特性直接传数组
- DSL query builder with polymorphic parameters (string/array/closure/object)
- Full query-type coverage: TermLevel, FullText, Compound, Geo, Joining, Span, Shape, Specialized
- Aggregations: Bucket, Metric, and Pipeline categories
- Search parameters: sort, highlight, rescore, collapse, suggest, post_filter, knn, etc.
- Index layer: CRUD, pagination, cursor iteration, bulk writes (Bulk), zero-downtime rebuild (Rebuild)
- Event system: listeners for each phase of search, bulk operations, and rebuild
- OOP style: each query/aggregation type is a dedicated Node class, supporting chaining and incremental building
- Raw DSL pass-through: uncovered ES features can be passed directly as arrays
68 changes: 38 additions & 30 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,67 @@
# ElasticKit - Elasticsearch DSL Query Builder

PHP Elasticsearch DSL 查询构建库。
A PHP Elasticsearch DSL query builder library.

> 本文件提交到仓库。本地环境变量放在 `CLAUDE.local.md`(已 gitignore),Claude Code 自动加载两者。
> This file is committed to the repository. Local environment variables live in `CLAUDE.local.md` (gitignored); Claude Code loads both automatically.

**版本管理:** a.b.c,a 对齐 ES 主版本,`^8` 即可。
**Versioning:** a.b.c, where `a` tracks the ES major version. `^8` suffices.

> master 对应 v8.xES 8.xPHP 8.1+),7.x 分支独立维护(ES 7.xPHP 7.2+)。两条线不互合并,CLAUDE.md 各分支独立维护。
> `master` tracks v8.x (ES 8.x, PHP 8.1+); the 7.x branch is maintained separately (ES 7.x, PHP 7.2+). The two lines are never merged into each other; CLAUDE.md is maintained per branch.

### 提交信息规范
### Commit message conventions

- **参数名锁定**:公开方法参数名是 API 的一部分(支持命名参数),minor 版本禁止重命名
- **Parameter names are locked**: public method parameter names are part of the API (named arguments are supported); renaming is forbidden in minor versions

[Conventional Commits](https://www.conventionalcommits.org/),中文描述:`feat(query): 新增 knn 向量搜索`
[Conventional Commits](https://www.conventionalcommits.org/), with an English description: `feat(query): add knn vector search`

Scope 可选:dsl / index / agg / query / docs。Breaking change 加 `!` 后缀。
Scope is optional: dsl / index / agg / query / docs. Append `!` for breaking changes.

### Changelog 规范
### Changelog conventions

[Keep a Changelog](https://keepachangelog.com),中文分类:
[Keep a Changelog](https://keepachangelog.com), with English categories:

- **新增** / **变更** / **弃用** / **移除** / **修复** / **安全**
- 只记录对用户有影响的变更
- 相关改动合并为一条
- Breaking change 以 `**BC:**` 前缀标记
- **Added** / **Changed** / **Deprecated** / **Removed** / **Fixed** / **Security**
- Record only user-facing changes
- Merge related changes into a single entry
- Mark breaking changes with the `**BC:**` prefix

### 发版流程
### Release flow

1. 跑全部测试
2. 更新 CHANGELOG.md
3. 提交并推送
4. 确认版本号后打 tag 并推送
1. Run the full test suite
2. Update CHANGELOG.md
3. Commit and push
4. Confirm the version, then tag and push

### PHPDoc 规范
### PHPDoc conventions

PSR-5 规范。
Follow PSR-5.

## 测试
## TODO

测试在 Docker 容器中运行,需要设置以下环境变量:
- [ ] **Add integration contract tests for Span and Shape queries**: unit DSL tests exist, but there is no Elasticsearch execution coverage (other query families have `tests/Integration/Dsl/*ContractTest.php`)
- [ ] **Cover Rebuild import-failure rollback**: the `createIndex`→`import` try/catch (deletes the new index on failure) is untested; only the alias-swap rollback path is covered

| 变量 | 用途 |
## Tests

Tests run inside a Docker container and require these environment variables:

| Variable | Purpose |
|---|---|
| `PHP_CONTAINER` | Docker 容器名 |
| `PROJECT_PATH` | 项目在容器内的路径 |
| `PROXY_PORT` | HTTP 代理端口(推送用) |
| `PHP_CONTAINER` | Docker container name |
| `PROJECT_PATH` | Project path inside the container |
| `PROXY_PORT` | HTTP proxy port (for pushing) |
| `ELASTICKIT_TEST_HOST` | ES endpoint for integration tests (e.g. `https://localhost:9200`); integration tests are skipped when unset |

## Pre-push checklist

```bash
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpunit --testsuite unit"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpunit --testsuite index"
docker exec -e ELASTICKIT_TEST_HOST=https://elasticsearch:9200 $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpunit --testsuite integration"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpunit"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpstan analyse"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpstan analyse --memory-limit=256M"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && vendor/bin/phpmd src text phpmd.xml"
docker exec $PHP_CONTAINER sh -c "cd $PROJECT_PATH && PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --diff"

# GitHub 不可达时走代理
# Route through the proxy when GitHub is unreachable
https_proxy=http://127.0.0.1:$PROXY_PORT http_proxy=http://127.0.0.1:$PROXY_PORT git push
```
Loading
Loading