Gel/EdgeDB 运算符内省指南:用 EdgeQL 探查 schema::Operator 的完整结构

原创2026-09-21 16:40:111,721 阅读
文章标签:数据库图数据库关系型数据库

Gel/EdgeDB 运算符内省指南:用 EdgeQL 探查 schema::Operator 的完整结构

本指南讲解如何通过 Gel(原 EdgeDB)的 EdgeQL 内省能力,从系统 Schema 中查询运算符(Operator)的定义结构。你将掌握 schema::Operator 与 schema::Parameter 两个内省对象类型的字段构成,学会用 with module schema 查询 std::AND 等内置运算符的参数、类型修饰符与返回类型,并理解这些字段在源码中的底层语义。本文以 docs/reference/datamodel/introspection/operators.rst 为骨架展开,并结合仓库源码补充实现细节。

运算符内省概览

在 Gel 的 Schema 中,运算符(Operator)是一类可调用对象(Callable Object)。与函数(Function)类似,运算符同样拥有参数(params)和返回类型(return type),此外还带有运算符种类(operator kind)等独有特征。通过内省(Introspection),开发者可以用纯 EdgeQL 查询这些元数据,动态生成 API 文档、构建类型系统工具或在运行时验证某个运算符是否存在及如何调用。

内省的核心入口是系统模块 schema 中的 schema::Operator 对象类型。下列查询先用 ObjectType 探查 schema::Operator 自身的结构——包括它拥有的链接(links)与属性(properties):

with module schema
select ObjectType {
    name,
    links: {
        name,
    },
    properties: {
        name,
    }
}
filter .name = 'schema::Operator';

执行结果:

{
    Object {
        name: 'schema::Operator',
        links: {
            Object { name: '__type__' },
            Object { name: 'annotations' },
            Object { name: 'params' },
            Object { name: 'return_type' }
        },
        properties: {
            Object { name: 'id' },
            Object { name: 'name' },
            Object { name: 'operator_kind' },
            Object { name: 'return_typemod' }
        }
    }
}

可见 schema::Operator 的完整形状:

  • links(链接):__type__(对象自身类型)、annotations(注解)、params(参数列表)、return_type(返回类型);
  • properties(属性):id、name(限定名,如 std::AND)、operator_kind(运算符种类)、return_typemod(返回类型的类型修饰符)。

这四类元数据与函数的内省结构高度一致(可对照 functions.rst),区别仅在于多出了 operator_kind 属性。

参数结构:schema::Parameter

运算符与函数的另一个共通点是 params 链接。由于参数对运算符的签名(signature)至关重要,这里单独内省 schema::Parameter 的结构:

with module schema
select ObjectType {
    name,
    links: {
        name,
    },
    properties: {
        name,
    }
}
filter .name = 'schema::Parameter';

执行结果:

{
    Object {
        name: 'schema::Parameter',
        links: {
            Object { name: '__type__' },
            Object { name: 'type' }
        },
        properties: {
            Object { name: 'default' },
            Object { name: 'id' },
            Object { name: 'kind' },
            Object { name: 'name' },
            Object { name: 'num' },
            Object { name: 'typemod' }
        }
    }
}

schema::Parameter 的字段含义如下:

字段 类型 含义
id 属性 参数对象的唯一标识
name 属性 参数名(如 a、b)
num 属性 参数在签名中的序号(从 0 开始)
kind 属性 参数种类,见下文 ParameterKind 枚举
typemod 属性 参数的类型修饰符,见下文 TypeModifier 枚举
default 属性 默认值表达式,无默认值时返回空集 {}
type 链接 参数的类型(指向 schema::Type,可继续取 name)
__type__ 链接 参数对象自身的类型

在源码层面,参数对象对应 edb/schema/functions.py 中的 Parameter 类,它同时继承 so.ObjectFragment 与 so.Object,其 num、default、type、typemod、kind 均以 SchemaField 声明,与内省输出一一对应。

实战:内省 std::AND 运算符

将上述结构组合起来,即可完整探查一个具体运算符的全部元数据。以下查询内省内置的布尔与运算符 std::AND,同时获取运算符种类、注解、每个参数的细节以及返回类型:

with module schema
select Operator {
    name,
    operator_kind,
    annotations: { name, @value },
    params: {
        kind,
        name,
        num,
        typemod,
        type: { name },
        default,
    },
    return_typemod,
    return_type: { name },
}
filter .name = 'std::AND';

执行结果:

{
    Object {
        name: 'std::AND',
        operator_kind: 'Infix',
        annotations: {},
        params: {
            Object {
                kind: 'PositionalParam',
                name: 'a',
                num: 0,
                typemod: 'SingletonType',
                type: Object { name: 'std::bool' },
                default: {}
            },
            Object {
                kind: 'PositionalParam',
                name: 'b',
                num: 1,
                typemod: 'SingletonType',
                type: Object { name: 'std::bool' },
                default: {}
            }
        },
        return_typemod: 'SingletonType',
        return_type: Object { name: 'std::bool' }
    }
}

从结果可以解读出 std::AND 的完整定义:

  • name 为限定名 std::AND,即标准库模块 std 中的 AND 运算符;
  • operator_kind 为 Infix(中缀),即写作 a AND b 的二元写法;
  • annotations 为空集合,说明该运算符未附加注解;
  • 两个参数 a、b 均为 PositionalParam(位置参数),序号分别为 0 和 1,typemod 均为 SingletonType(单例类型,即参数必须为单个值而非集合),类型均为 std::bool,且都没有默认值;
  • return_typemod 为 SingletonType,返回类型为 std::bool。

这意味着 std::AND 的签名可写作 std::bool AND std::bool -> std::bool,与 EdgeQL 中布尔逻辑的语义完全一致。

源码视角:枚举与字段的底层语义

内省输出中的字符串值并非随意命名,而是直接来自源码中的枚举定义,位于 edb/edgeql/qltypes.py。

OperatorKind(运算符种类)——qltypes.py:

枚举值 说明 书写形态示例
Infix 中缀运算符 a AND b
Prefix 前缀运算符 NOT a
Postfix 后缀运算符 a IS NULL 等
Ternary 三元运算符 a ?? b 之外的 if/else 形式

在 edb/schema/operators.py 的 get_display_signature() 方法中,这四种 kind 被转换为可读的显示签名:中缀为 f'{params[0]} {name} {params[1]}',前缀为 f'{name} {params[0]}',后缀为 f'{params[0]} {name}',三元为 f'{name} ({", ".join(params)})'。

ParameterKind(参数种类)——qltypes.py:

  • PositionalParam:位置参数,按位置传入;
  • NamedOnlyParam:仅限命名参数(NAMED ONLY);
  • VariadicParam:可变参数(VARIADIC,在底层被包装为 array 类型,见 functions.py 的 from_ast 处理)。

TypeModifier(类型修饰符)——qltypes.py:

  • SingletonType:单例类型,要求输入/输出为单个值;
  • SetOfType:集合类型(SET OF),对应如 count(s) 这类接受集合的参数;
  • OptionalType:可选类型(OPTIONAL)。

Operator 对象的更多内部字段

除了内省可见的字段,Operator 类在源码中还携带了用于编译与优化运算符调用的内部字段,见 edb/schema/operators.py:

  • language:运算符实现所用的语言;
  • from_operator / from_function:派生运算符的来源运算符或函数名;
  • from_expr:是否由表达式派生;
  • force_return_cast:是否强制对返回值做类型转换;
  • code:运算符的实现代码;
  • derivative_of:派生运算符的源运算符名(例如 std::IN 以 std::= 为源);
  • commutator / negator:可交换运算符与否定运算符的关联名,用于查询优化;
  • recursive:是否为递归运算符。

这些字段多为内部实现细节,不会全部暴露在 schema::Operator 的内省属性中,但它们决定了运算符如何被解析、编译与执行。在 edb/pgsql/compiler/expr.py 中,编译器正是依据 operator_kind 等字段将 EdgeQL 运算符翻译为底层 SQL 表达式。

使用注意事项

  • 运算符内省查询需要 with module schema 显式引入系统模块,否则 Operator、ObjectType 等类型名无法解析;
  • params 是链接而非属性,查询参数细节时必须展开为 params: { ... } 形状,且 type 本身也是一条链接,需继续取 type: { name } 才能获得类型名;
  • default 在无默认值时返回空集 {},并非 null;
  • 从源码看,用户自定义运算符目前不受支持:OperatorCommand._cmd_tree_from_ast 在非标准库、非测试模式下会抛出 UnsupportedFeatureError('user-defined operators are not supported')(见 edb/schema/operators.py)。因此内省查询通常针对标准库与扩展中内置的运算符(如 std::AND、std::=、std::+ 等)。

掌握上述模式后,你可以通过组合 name 过滤、params 展开与 operator_kind 筛选,对任意内置运算符做程序化内省,进而构建类型检查、文档生成或 IDE 补全等工具。

登录后查看全文
edgedb