Skip to content

Decorators

define_component

define_component(
    _cls=None,
    /,
    *,
    namespace: str = 'default',
    force: bool = False,
    permission=<Permission.USER: 2>,
    volatile=False,
    backend: str = 'default',
    rls_compare: tuple[str, str, str] | None = None,
) -> Callable[[type[hetu.data.component.BaseComponent]], type[hetu.data.component.BaseComponent]] | type[hetu.data.component.BaseComponent]

Source: hetu/data/component.py:353

定义Component组件的schema模型

Parameters

  • namespace (Any) — 你的项目名,主要为了区分不同项目的同名Component。 不同于System,Component的Namespace可以随意填写,只要被System引用了都会加载。 如果为"core",则此Component即使没被任何System引用,也会被加载。

  • volatile (Any) — 是否是易失表,设为True时,每次维护你的数据会被清除,请小心。

  • backend (Any) — 指定Component后端,对应配置文件中BACKENDS的字典key。默认为default,对应BACKENDS配置中第一个

  • permission (Any) — 设置读取权限,只对hetu client sdk连接起作用,服务器端代码不受限制。

  • everybody: 任何客户端连接都可以读,适合读一些服务器状态类的数据,如在线人数

  • user: 只有已登录的客户端都连接可以读

  • admin: 只有管理员权限客户端连接可以读

  • owner: 只能读取到owner属性值==登录的用户id(ctx.caller)的行,未登录的客户端无法读取。 此权限等同rls权限,且rls_compare=('eq', 'owner', 'caller')

  • rls: 行级权限,需要配合rls_compare参数使用,定义具体的行级权限逻辑

  • rls_compare (Any) — 当permission设置为RLS(行级权限)时,定义行级安全的比较函数和属性名。

  • rls_compare[0]: operator比较方法字符串,如"lt", “gt"等。参考python operator标准运算符函数模块

  • rls_compare[1]: 组件属性名字符串

  • rls_compare[2]: Context属性名字符串,或Context.user_data的key名

只有operator比较后返回True时允许读取此行。如果属性不存在,按nan处理(无法和任何值比较)。

  • force (Any) — 强制覆盖同名Component,单元测试用。

  • _cls (Any) — 当所有参数使用默认值时,可以直接无参数使用,如::

    @define_component class Position(BaseComponent): …

Examples

>>> import hetu
>>> import numpy as np
>>> @hetu.define_component(namespace="ssw")
... class Position(hetu.BaseComponent):
...     x: np.float32 = hetu.property_field(default=0)
...     y: np.float32 = hetu.property_field(default=0)
...     owner: np.int64 = hetu.property_field(default=0, unique=True)
...     name: str = hetu.property_field(default="12345678", dtype="U8")

Notes

property_field(default, unique, index, dtype) 是Component的属性定义,可定义默认值和数据类型。 - index 表示此属性开启索引; - unique 表示属性值必须唯一,启动此项默认会同时打开index。

.. warning:: ⚠️ 警告:索引会降低全表性能,请控制数量。其中unique索引降低的更多。

属性值的类型由type hint决定(如 : np.float32),请使用长度明确的np类型。 字符串类型格式为”<U8",U是Unicode,8表示长度,<表示little-endian。 不想看到"<U8"在IDE里标红语法错误的话,可用 name: str = property_field(dtype='<U8') 方式。

每个Component表都有个默认的主键id: np.int64 = property_field(default=雪花uuid, unique=True), 是一个uuid,无法修改。


define_endpoint

define_endpoint(
    namespace: str = 'global',
    force: bool = False,
    permission: hetu.common.permission.Permission = <Permission.USER: 2>,
)

Source: hetu/endpoint/definer.py:90

把一个函数包装成可供客户端远程调用的接口。

大部分情况不需要调用此包装器,你可以把逻辑代码直接写在System中。 System在定义时,如果设置了permission,则会自动生成对应的Endpoint。 如果你需要执行多次System,或不牵涉数据库操作的逻辑,可以使用Endpoint。

Parameters

  • namespace (Any) — 是你的项目名,服务器启动时,一个网络地址只能绑定一个namespace下的Endpoint们。 定义为"global"的Endpoint永远会被绑定并启用,用于在项目间通用。

  • force (Any) — 遇到重复定义是否强制覆盖前一个, 单元测试用

  • permission (Any) — 设置客户端的调用权限,只做些初级检查,具体权限需要自己逻辑中判断。

  • everybody: 任何客户端连接都可以调用执行。(不安全)

  • user: 只有已登录客户端连接可以调用

  • owner: 不可用 OWNER权限这里不可使用,需要自行做安全检查

  • admin: 只有管理员权限客户端连接可以调用

  • rls: 不可用 RLS权限这里不可使用,需要自行做安全检查

Examples

>>> import hetu
>>>
>>> @hetu.define_endpoint(namespace="example", permission=hetu.Permission.EVERYBODY)
... async def pay(ctx: hetu.EndpointContext, order_id, paid):
...     await ctx.systems.call("SystemName", order_id, paid)
...     return hetu.ResponseToClient(['anything', 'blah blah'])

Notes

hetu.system.define_system : define_system装饰器定义System hetu.endpoint.Context : Context类定义


define_system

define_system(
    components: tuple[type[BaseComponent], ...] | None = None,
    namespace: str = 'default',
    force: bool = False,
    permission: hetu.common.permission.Permission | None = None,
    retry: int = 9999,
    depends: tuple[str | function, ...] = (),
    call_lock=False,
)

Source: hetu/system/definer.py:303

定义System,System类似数据库的储存过程,主要用于数据CRUD。 如果permission不为None,则会自动创建一个Endpoint,让客户端可以直接调用System, 并自动判断permission是否符合。

如果需要更多的控制,可以自己写@endpoint()调用System。

Parameters

  • namespace (Any) — 是你的项目名,服务器启动时,一个网络地址只能绑定一个namespace下的System们。 定义为"global"的System永远会被绑定并启用,用于在项目间通用。

  • components (Any) — 引用Component,引用的Component可以在ctx中进行相关的事务操作,保证数据一致性。 所有引用的Components会加入共置簇(Colocation Cluster)中,指放在同一个物理数据库中, 具体见Notes。

  • force (Any) — 遇到重复定义是否强制覆盖前一个, 单元测试用

  • permission (Any) — 设置客户端的调用权限,只做些初级检查,具体权限需要自己逻辑中判断。 设为None时表示客户端SDK不可调用,设置任意权限会创建一个供客户端调用的Endpoint, 然后由此Endpoint调用本System。

  • everybody: 任何客户端连接都可以调用执行。(不安全)

  • user: 只有已登录客户端连接可以调用

  • owner: 不可用 OWNER权限这里不可使用,需要自行做安全检查

  • admin: 只有管理员权限客户端连接可以调用

  • rls: 不可用 RLS权限这里不可使用,需要自行做安全检查

  • retry (Any) — 如果System遇到事务冲突,会重复执行直到成功。设为0关闭

  • depends (Any) — 定义要事务依赖的其他System,调用时会在同一个事务会话中执行。 可传入System函数本身,或字符串,如(“system1”, system2)。 可通过ctx.depend["system1"](ctx, ...)或直接system2(ctx, ...)方式调用定义的函数。 如果希望使用System副本,可以使用字符串式定义,加’:副本名后缀’。具体见Notes。 注意: 所有depends,将被合并进同一个共置簇中。

  • call_lock (Any) — 是否对此System启用调用锁,启用后在调用时可以通过传入调用UUID来防止System重复执行。 如果此System需要给未来调用使用,则此项必须为True。

客户端直接调用的System不需要此功能,主要用于未来调用的幂等性, 或者你需要嵌套执行System,保证其中一个只执行一次等特殊情况,

Examples

>>> import hetu
>>> # 定义Component
>>> @hetu.define_component
... class Stock(hetu.BaseComponent):
...     owner: int = hetu.property_field(0)
...     value: int = hetu.property_field(0)
>>> @hetu.define_component
... class Order(hetu.BaseComponent):
...     owner: int = hetu.property_field(0)
...     paid: bool = hetu.property_field(False)
...     qty: int = hetu.property_field(0)
>>>
>>> # 定义System
>>> @hetu.define_system(namespace="example", components=(Stock, Order), permission=hetu.Permission.USER)
... async def pay(ctx: hetu.SystemContext, order_id, paid):
...     async with ctx.repo[Order].upsert(id=order_id) as order:
...        order.paid = paid
...     async with ctx.repo[Order].upsert(owner=order.owner) as stock:
...        stock.value += order.qty
...     # ctx.commit()  # 可以省略,也可以提前提交
...     return hetu.ResponseToClient(['anything', 'blah blah'])

Notes

hetu.system.SystemContext : SystemContext类定义 hetu.endpoint.endpoint : endpoint装饰器定义Endpoint


property_field

property_field(
    default: Any,
    unique: bool = False,
    index: bool | None = None,
    dtype: str | type = '',
) -> Any

Source: hetu/data/component.py:51

Define a Component field declaration helper.

定义 Component 的属性字段。它通常与 type hint 一起使用,在 @define_component 处理 class 时被解析为内部 Property 定义。

Parameters

  • default (Any) — 属性默认值。所有字段都必须提供默认值,且不能为 None。 HeTu 的 Component 使用 c-struct like 的定长数据模型,不支持 nullable。

  • unique (bool, default False) — 是否为唯一索引。开启后字段值必须唯一,并会自动启用 index

  • index (bool | None, default None) — 是否建立索引。

  • None 表示沿用 unique 的值;

  • False 表示不建立普通索引;

  • True 表示建立普通索引。

unique=True 时,即使显式传入 False,后续定义阶段也会被强制修正为 True

  • dtype (str | type, default "") — 字段数据类型。留空时默认使用属性的 type hint。

推荐使用长度明确的 NumPy dtype,例如 np.int64np.float32"U8""<U32"。字符串类型需要显式指定长度。

Returns

内部 Property 对象。返回类型标注为 Any 是为了减少类型检查器对 class attribute default value 的误报,运行时仍会被当作 Property 处理。

Examples

>>> import numpy as np
>>> class Position(BaseComponent):
...     x: np.float32 = property_field(default=0)
...     owner: np.int64 = property_field(default=0, unique=True)
...     name: str = property_field(default="hero", dtype="U16")

Notes

property_field(...) 只负责声明字段元数据,真正的合法性校验会在 @define_component 执行时完成,包括:

  • 字段名是否合法;
  • defaultdtype 是否兼容;
  • dtype 是否可用于 NumPy structured array;
  • unique/index 组合是否合法。