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
11 changes: 11 additions & 0 deletions docs/developer-guide/plugin/api-changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ spec:

## 2.22.0

### 自定义模型索引 API 更新

在 2.22.0 中,我们重构了自定义模型索引和查询 API,插件中直接使用索引 API 的代码建议进行以下调整:

1. 使用 `IndexSpecs.single(name, keyType)` 和 `IndexSpecs.multi(name, keyType)` 声明索引,替代 `IndexAttributeFactory.simpleAttribute()`、`IndexAttributeFactory.multiValueAttribute()` 和直接创建 `new IndexSpec()` 的旧写法。
2. 索引值类型不再局限于字符串,可以使用 `String`、`Boolean`、`Integer`、`Long`、`Instant` 等实现 `Comparable` 的类型。
3. 使用 `Queries` 创建 `FieldSelector` 查询条件,替代已过时的 `QueryFactory`。
4. `ReactiveExtensionClient` 和 `ExtensionClient` 新增了 `listAllNames`、`listTopNames`、`listNamesBy` 和 `countBy` 等查询方法,直接使用 `indexedQueryEngine()` 的方式已过时。

详细文档可查阅:[自定义模型使用索引](./api-reference/server/extension.md#using-indexes) 和 [ExtensionClient 查询](./api-reference/server/extension-client.md#query)。

### `@halo-dev/console-shared` 改名

从 Halo 2.11 支持个人中心以后,插件的 UI 项目能同时扩展 Console 和 UC,所以为了避免歧义,我们在 Halo 2.22 中将 UI 的 `@halo-dev/console-shared` 依赖更名为 `@halo-dev/ui-shared`,虽然在 Halo 中兼容了旧版依赖,但仍然推荐使用新版依赖,迁移方案:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,16 @@ public PersonService {

### 查询 {#query}

`ReactiveExtensionClient` 提供了两个方法用于查询数据,`listBy` 和 `listAll`。
`ReactiveExtensionClient` 提供了以下方法用于查询数据:

`listBy` 方法用于分页查询数据,`listAll` 方法用于查询所有数据,它们都需要一个 `ListOptions` 参数,用于传递查询条件:
- `listBy`:分页查询数据。
- `listNamesBy`:分页查询对象名称。
- `listAll`:查询所有数据。
- `listAllNames`:查询所有对象名称。
- `listTopNames`:查询指定数量的对象名称。
- `countBy`:统计符合条件的数据数量。

这些方法都需要一个 `ListOptions` 参数,用于传递查询条件:

```java
public class ListOptions {
Expand All @@ -115,58 +122,61 @@ public class ListOptions {

其中 `LabelSelector` 用于传递标签查询条件,`FieldSelector` 用于传递字段查询条件。

`FieldSelector` 支持比自动生成的 APIs 中更多的查询条件,可以通过 `run.halo.app.extension.index.query.QueryFactory` 来构建。
`FieldSelector` 支持比自动生成的 APIs 中更多的查询条件,可以通过 `run.halo.app.extension.index.query.Queries` 来构建。

```java
import static run.halo.app.extension.index.query.Queries.and;
import static run.halo.app.extension.index.query.Queries.equal;

ListOptions.builder()
.fieldQuery(QueryFactory.and(
QueryFactory.equal("name", "test"),
QueryFactory.equal("age", 18)
.fieldQuery(and(
equal("name", "test"),
equal("age", 18)
))
.build();
```

支持的查询条件如下:

| 方法 | 说明 | 示例 |
| ---------------------------- | ---------------- | ----------------------------------------------------------------------------- |
| equal | 等于 | equal("name", "test"), name 是字段名,test 是字段值 |
| equalOtherField | 等于其他字段 | equalOtherField("name", "otherName"), name 是字段名,otherName 是另一个字段名 |
| notEqual | 不等于 | notEqual("name", "test") |
| notEqualOtherField | 不等于其他字段 | notEqualOtherField("name", "otherName") |
| greaterThan | 大于 | greaterThan("age", 18) |
| greaterThanOtherField | 大于其他字段 | greaterThanOtherField("age", "otherAge") |
| greaterThanOrEqual | 大于等于 | greaterThanOrEqual("age", 18) |
| greaterThanOrEqualOtherField | 大于等于其他字段 | greaterThanOrEqualOtherField("age", "otherAge") |
| lessThan | 小于 | lessThan("age", 18) |
| lessThanOtherField | 小于其他字段 | lessThanOtherField("age", "otherAge") |
| lessThanOrEqual | 小于等于 | lessThanOrEqual("age", 18) |
| lessThanOrEqualOtherField | 小于等于其他字段 | lessThanOrEqualOtherField("age", "otherAge") |
| in | 在范围内 | in("age", 18, 19, 20) |
| and | 且 | and(equal("name", "test"), equal("age", 18)) |
| or | 或 | or(equal("name", "test"), equal("age", 18)) |
| between | 在范围内 | between("age", 18, 20), 包含 18 和 20 |
| betweenExclusive | 在范围内 | betweenExclusive("age", 18, 20), 不包含 18 和 20 |
| betweenLowerExclusive | 在范围内 | betweenLowerExclusive("age", 18, 20), 不包含 18,包含 20 |
| betweenUpperExclusive | 在范围内 | betweenUpperExclusive("age", 18, 20), 包含 18,不包含 20 |
| startsWith | 以指定字符串开头 | startsWith("name", "test") |
| endsWith | 以指定字符串结尾 | endsWith("name", "test") |
| contains | 包含指定字符串 | contains("name", "test") |
| all | 指定字段的所有值 | all("age") |
| 方法 | 说明 | 示例 |
| --- | --- | --- |
| `equal` | 等于 | `equal("name", "test")` |
| `notEqual` | 不等于 | `notEqual("name", "test")` |
| `greaterThan` | 大于,可通过第三个参数控制是否包含边界 | `greaterThan("age", 18)`、`greaterThan("age", 18, true)` |
| `lessThan` | 小于,可通过第三个参数控制是否包含边界 | `lessThan("age", 18)`、`lessThan("age", 18, true)` |
| `between` | 在范围内,可分别控制上下边界是否包含 | `between("age", 18, true, 20, false)` |
| `in` | 在给定值范围内 | `in("age", 18, 19, 20)` |
| `isNull` | 值为空 | `isNull("deletedAt")` |
| `all` | 指定字段的所有值 | `all("age")` |
| `startsWith` | 以指定字符串开头 | `startsWith("name", "test")` |
| `endsWith` | 以指定字符串结尾 | `endsWith("name", "test")` |
| `contains` | 包含指定字符串 | `contains("name", "test")` |
| `and` | 且 | `and(equal("name", "test"), equal("age", 18))` |
| `or` | 或 | `or(equal("name", "test"), equal("age", 18))` |
| `not` | 取反 | `not(equal("name", "test"))` |
| `labelExists` | 标签存在 | `labelExists("halo.run/hidden")` |
| `labelEqual` | 标签等于 | `labelEqual("env", "production")` |
| `labelIn` | 标签值在给定范围内 | `labelIn("env", Set.of("production", "staging"))` |

在 `FieldSelector` 中使用的所有字段都必须添加为索引,否则会抛出异常表示不支持该字段。关于如何使用索引请参考 [自定义模型使用索引](./extension.md#using-indexes)。

:::note

从 2.22.0 开始,`QueryFactory` 已过时,请使用 `Queries` 创建查询条件。取反查询可以通过 `Queries.not(condition)` 或 `condition.not()` 构建。

:::

可以通过 `and` 和 `or` 方法组合和嵌套查询条件:

```java
import static run.halo.app.extension.index.query.QueryFactory.and;
import static run.halo.app.extension.index.query.QueryFactory.equal;
import static run.halo.app.extension.index.query.QueryFactory.greaterThan;
import static run.halo.app.extension.index.query.QueryFactory.or;
import run.halo.app.extension.index.query.Condition;
import static run.halo.app.extension.index.query.Queries.and;
import static run.halo.app.extension.index.query.Queries.equal;
import static run.halo.app.extension.index.query.Queries.or;

Query query = and(
Condition query = and(
or(equal("dept", "A"), equal("dept", "B")),
or(equal("age", "19"), equal("age", "18"))
or(equal("age", 19), equal("age", 18))
);
ListOptions.builder()
.fieldQuery(query)
Expand All @@ -178,11 +188,13 @@ ListOptions.builder()
ListOptions 提供了 `builder` 方法用于构建查询条件,`fieldQuery` 方法用于传递字段查询条件,`labelSelector` 方法用于传递标签查询条件。

```java
import static run.halo.app.extension.index.query.Queries.equal;

ListOptions.builder()
.labelSelector()
.eq("key-1", "value-1")
.end()
.fieldQuery(QueryFactory.equal("key-2", "value-2"))
.fieldQuery(equal("key-2", "value-2"))
.build();
```

Expand All @@ -191,7 +203,7 @@ ListOptions.builder()

### 排序

`listBy` 和 `listAll` 方法都支持传递 `Sort` 参数,用于传递排序条件。
`listBy`、`listNamesBy`、`listAll`、`listAllNames` 和 `listTopNames` 方法都支持传递 `Sort` 参数,用于传递排序条件。

```java
import org.springframework.data.domain.Sort;
Expand Down
61 changes: 39 additions & 22 deletions docs/developer-guide/plugin/api-reference/server/extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,36 +168,49 @@ Halo 提供了一套索引机制,开发者可以通过注册自定义模型时
示例:

```java
import static run.halo.app.extension.index.IndexAttributeFactory.multiValueAttribute;
import static run.halo.app.extension.index.IndexAttributeFactory.simpleAttribute;
import java.time.Instant;
import java.util.Set;
import static run.halo.app.extension.index.IndexSpecs.multi;
import static run.halo.app.extension.index.IndexSpecs.single;

@Override
public void start() {
schemeManager.register(Moment.class, indexSpecs -> {
indexSpecs.add(new IndexSpec()
.setName("spec.tags")
// multiValueAttribute 用于得到一个返回多个值的索引函数
.setIndexFunc(multiValueAttribute(Moment.class, moment -> {
var tags = moment.getSpec().getTags();
return tags == null ? Set.of() : tags;
}))
// simpleAttribute 用于得到一个返回单个值的索引函数,可以返回 null
indexSpecs.add(new IndexSpec()
.setName("spec.owner")
.setIndexFunc(
simpleAttribute(Moment.class, moment -> moment.getSpec().getOwner())));
);
// multi 用于声明一个返回多个值的索引
indexSpecs.add(multi("spec.tags", String.class)
.indexFunc(moment -> {
var tags = moment.getSpec().getTags();
return tags == null ? Set.of() : tags;
}));

// single 用于声明一个返回单个值的索引,可以返回 null
indexSpecs.add(single("spec.owner", String.class)
.indexFunc(moment -> moment.getSpec().getOwner()));

// 索引值不再局限于字符串,也可以使用 Boolean、Integer、Instant 等可比较类型
indexSpecs.add(single("spec.pinned", Boolean.class)
.indexFunc(moment -> moment.getSpec().getPinned()));
indexSpecs.add(single("spec.priority", Integer.class)
.indexFunc(moment -> moment.getSpec().getPriority()));
indexSpecs.add(single("spec.publishTime", Instant.class)
.indexFunc(moment -> moment.getSpec().getPublishTime()));
});
}
```

`IndexSpec` 用于声明索引项,它包含以下属性:
`IndexSpec` 用于声明索引项,推荐通过 `IndexSpecs.single(name, keyType)` 或 `IndexSpecs.multi(name, keyType)` 构建。它包含以下属性:

- name:索引名称,在同一个自定义模型的索引中必须唯一,一般建议使用字段路径作为索引名称,例如 `spec.slug`。
- order:对索引值的排序方式,支持 `ASC` 和 `DESC`,默认为 `ASC`。
- unique:是否唯一索引,如果为 `true` 则索引值必须唯一,如果创建自定义模型对象时检测到此索引字段有重复值则会创建失败。
- indexFunc:索引函数,用于获取索引值,接收当前自定义模型对象,返回一个索引值,索引值必须是字符串任意类型,如果不是字符串类型则需要自己转为字符串,可以使用 `IndexAttributeFactory` 提供的静态方法来创建 `indexFunc`:
- `simpleAttribute()`:用于得到一个返回单个值的索引函数,例如 `moment -> moment.getSpec().getSlug()`。
- `multiValueAttribute()`:用于得到一个返回多个值的索引函数,例如 `moment -> moment.getSpec().getTags()`。
- keyType:索引值类型,必须实现 `Comparable`,例如 `String`、`Boolean`、`Integer`、`Long`、`Instant` 等。
- indexFunc:索引函数,用于获取索引值,接收当前自定义模型对象。单值索引返回一个 `keyType` 类型的值,可以返回 `null`;多值索引返回 `Set<keyType>`。

:::note

从 2.22.0 开始,`IndexAttributeFactory.simpleAttribute()`、`IndexAttributeFactory.multiValueAttribute()` 和直接创建 `new IndexSpec()` 的写法已过时,请优先使用 `IndexSpecs.single()` 和 `IndexSpecs.multi()`。

:::

当注册自定义模型时声明了索引,Halo 会在插件启动时构建索引,在构建索引期间插件处于未启动状态。

Expand Down Expand Up @@ -482,6 +495,10 @@ public class PersonQuery {
但排序、分页、标签查询和字段查询等参数通常是通用的,因此 Halo 提供了 `run.halo.app.extension.router.SortableRequest` 类来封装这些参数,开发者可以直接继承该类来定义额外查询参数:

```java
import static run.halo.app.extension.index.query.Queries.contains;
import static run.halo.app.extension.index.query.Queries.equal;
import static run.halo.app.extension.index.query.Queries.or;

public class PersonQuery extends SortableRequest {

public PersonQuery(ServerWebExchange exchange) {
Expand Down Expand Up @@ -519,9 +536,9 @@ public class PersonQuery extends SortableRequest {
@Override
public ListOptions toListOptions() {
return ListOptions.builder(super.toListOptions())
.fieldQuery(QueryFactory.or(
QueryFactory.equal("metadata.name", getKeyword()),
QueryFactory.contains("spec.name", getKeyword())
.fieldQuery(or(
equal("metadata.name", getKeyword()),
contains("spec.name", getKeyword())
))
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public interface ExtensionMatcher {
比如我们想要观察文章对象,但是只想观察文章对象中 `visible` 字段为 `PUBLIC` 的文章,可以这样

```java
import static run.halo.app.extension.index.query.Queries.equal;

public class PostReconciler implements Reconciler<Reconciler.Request> {
@Override
public Result reconcile(Request request) {
Expand Down Expand Up @@ -131,7 +133,7 @@ public class PostReconciler implements Reconciler<Reconciler.Request> {
return builder
.extension(new Post())
.syncAllListOptions(ListOptions.builder()
.fieldQuery(QueryFactory.equal("spec.owner", "guqing"))
.fieldQuery(equal("spec.owner", "guqing"))
.build()
)
.syncAllOnStart(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ spec:

## 2.22.0

### 自定义模型索引 API 更新

在 2.22.0 中,我们重构了自定义模型索引和查询 API,插件中直接使用索引 API 的代码建议进行以下调整:

1. 使用 `IndexSpecs.single(name, keyType)` 和 `IndexSpecs.multi(name, keyType)` 声明索引,替代 `IndexAttributeFactory.simpleAttribute()`、`IndexAttributeFactory.multiValueAttribute()` 和直接创建 `new IndexSpec()` 的旧写法。
2. 索引值类型不再局限于字符串,可以使用 `String`、`Boolean`、`Integer`、`Long`、`Instant` 等实现 `Comparable` 的类型。
3. 使用 `Queries` 创建 `FieldSelector` 查询条件,替代已过时的 `QueryFactory`。
4. `ReactiveExtensionClient` 和 `ExtensionClient` 新增了 `listAllNames`、`listTopNames`、`listNamesBy` 和 `countBy` 等查询方法,直接使用 `indexedQueryEngine()` 的方式已过时。

详细文档可查阅:[自定义模型使用索引](./api-reference/server/extension.md#using-indexes) 和 [ExtensionClient 查询](./api-reference/server/extension-client.md#query)。

### `@halo-dev/console-shared` 改名

从 Halo 2.11 支持个人中心以后,插件的 UI 项目能同时扩展 Console 和 UC,所以为了避免歧义,我们在 Halo 2.22 中将 UI 的 `@halo-dev/console-shared` 依赖更名为 `@halo-dev/ui-shared`,虽然在 Halo 中兼容了旧版依赖,但仍然推荐使用新版依赖,迁移方案:
Expand Down
Loading
Loading