def amend_empty_set_type(es: irast.EmptySet, t: s_obj.Object, schema) -> None: alias = es.path_id[-1].name.name scls_name = s_name.Name(module='__expr__', name=alias) scls = t.__class__(name=scls_name, bases=[t]) scls.acquire_ancestor_inheritance(schema) es.path_id = irast.PathId(scls) es.scls = t
def resolve_schema_name(name: str, module: str, *, ctx: context.ContextLevel) -> sn.Name: schema_module = ctx.modaliases.get(module) if schema_module is None: return None else: return sn.Name(name=name, module=schema_module)
def __init__(self, source, target, *, optional, cardinality): name = 'optindirection' if optional else 'indirection' super().__init__(name=s_name.Name(module='__type__', name=name), source=source, target=target, direction=s_pointers.PointerDirection.Outbound) self.optional = optional self.cardinality = cardinality
def compile_GroupQuery( expr: qlast.Base, *, ctx: context.ContextLevel) -> irast.Base: with ctx.subquery() as ictx: stmt = irast.GroupStmt() init_stmt(stmt, expr, ctx=ictx, parent_ctx=ctx) c = s_objtypes.ObjectType( name=s_name.Name( module='__group__', name=ctx.aliases.get('Group')), bases=[ctx.schema.get('std::Object')] ) c.acquire_ancestor_inheritance(ctx.schema) stmt.group_path_id = pathctx.get_path_id(c, ctx=ictx) pathctx.register_set_in_scope(stmt.group_path_id, ctx=ictx) with ictx.newscope(fenced=True) as subjctx: subjctx.clause = 'input' subject_set = setgen.scoped_set( dispatch.compile(expr.subject, ctx=subjctx), ctx=subjctx) alias = expr.subject_alias or subject_set.path_id[0].name stmt.subject = stmtctx.declare_inline_view( subject_set, alias, ctx=ictx) with subjctx.new() as grpctx: stmt.groupby = compile_groupby_clause( expr.groupby, singletons=grpctx.singletons, ctx=grpctx) with ictx.subquery() as isctx, isctx.newscope(fenced=True) as sctx: o_stmt = sctx.stmt = irast.SelectStmt() o_stmt.result = compile_result_clause( expr.result, view_scls=ctx.view_scls, view_rptr=ctx.view_rptr, result_alias=expr.result_alias, view_name=ctx.toplevel_result_view_name, ctx=sctx) o_stmt.where = clauses.compile_where_clause( expr.where, ctx=sctx) o_stmt.orderby = clauses.compile_orderby_clause( expr.orderby, ctx=sctx) o_stmt.offset = clauses.compile_limit_offset_clause( expr.offset, ctx=sctx) o_stmt.limit = clauses.compile_limit_offset_clause( expr.limit, ctx=sctx) stmt.result = setgen.scoped_set(o_stmt, ctx=sctx) result = fini_stmt(stmt, expr, ctx=ictx, parent_ctx=ctx) return result
def new_empty_set(schema, *, scls=None, alias): if scls is None: base_scls = schema.get('std::str') else: base_scls = scls cls_name = s_name.Name(module='__expr__', name=alias) cls = base_scls.__class__(name=cls_name, bases=[base_scls]) cls.acquire_ancestor_inheritance(schema) return irast.EmptySet(path_id=irast.PathId(cls), scls=scls)
def get_expression_path_id(t: s_types.Type, alias: str, *, ctx: context.ContextLevel) -> irast.PathId: cls_name = s_name.Name(module='__expr__', name=alias) if isinstance(t, (s_types.Collection, s_types.Tuple)): et = t.copy() et.name = cls_name else: et = t.__class__(name=cls_name, bases=[t]) et.acquire_ancestor_inheritance(ctx.schema) return pathctx.get_path_id(et, ctx=ctx)
def get_schema_object( name: typing.Union[str, qlast.ObjectRef], module: typing.Optional[str] = None, *, item_types: typing.Optional[typing.List[s_obj.ObjectMeta]], ctx: context.ContextLevel, srcctx: typing.Optional[parsing.ParserContext] = None) -> s_obj.Object: if isinstance(name, qlast.ObjectRef): if srcctx is None: srcctx = name.context module = name.module name = name.name if module: name = sn.Name(name=name, module=module) if not module: result = ctx.aliased_views.get(name) if result is not None: return result try: scls = ctx.schema.get(name=name, module_aliases=ctx.modaliases, type=item_types) except s_err.ItemNotFoundError as e: qlerror = qlerrors.EdgeQLError(e.args[0], context=srcctx) s_utils.enrich_schema_lookup_error(qlerror, name, modaliases=ctx.modaliases, schema=ctx.schema, item_types=item_types) raise qlerror except s_err.SchemaError as e: raise qlerrors.EdgeQLError(e.args[0], context=srcctx) result = ctx.aliased_views.get(scls.name) if result is None: result = scls return result
def compile_FunctionCall(expr: qlast.Base, *, ctx: context.ContextLevel) -> irast.Base: with ctx.new() as fctx: if isinstance(expr.func, str): funcname = expr.func else: funcname = sn.Name(expr.func[1], expr.func[0]) funcs = fctx.schema.get_functions(funcname, module_aliases=fctx.modaliases) if funcs is None: raise errors.EdgeQLError( f'could not resolve function name {funcname}', context=expr.context) fctx.in_func_call = True args, kwargs, arg_types = process_func_args(expr, funcname, ctx=fctx) for funcobj in funcs: if check_function(funcobj, arg_types): break else: raise errors.EdgeQLError( f'could not find a function variant {funcname}', context=expr.context) fixup_param_scope(funcobj, args, kwargs, ctx=fctx) node = irast.FunctionCall(func=funcobj, args=args, kwargs=kwargs) if funcobj.initial_value is not None: rtype = irutils.infer_type(node, fctx.schema) iv_ql = qlast.TypeCast(expr=qlparser.parse_fragment( funcobj.initial_value), type=typegen.type_to_ql_typeref(rtype)) node.initial_value = dispatch.compile(iv_ql, ctx=fctx) ir_set = setgen.ensure_set(node, ctx=ctx) return ir_set
def _get_link_view(mcls, schema_cls, field, ptr, refdict, schema): pn = ptr.shortname if refdict: if (issubclass(mcls, s_inheriting.InheritingObject) or mcls is s_named.NamedObject): if mcls is s_named.NamedObject: schematab = 'edgedb.InheritingObject' else: schematab = 'edgedb.{}'.format(mcls.__name__) link_query = ''' SELECT DISTINCT ON ((cls.id, r.bases[1])) cls.id AS {src}, r.id AS {tgt} FROM (SELECT s.id AS id, ancestry.ancestor AS ancestor, ancestry.depth AS depth FROM {schematab} s LEFT JOIN LATERAL UNNEST(s.mro) WITH ORDINALITY AS ancestry(ancestor, depth) ON true UNION ALL SELECT s.id AS id, s.id AS ancestor, 0 AS depth FROM {schematab} s ) AS cls INNER JOIN {reftab} r ON (((r.{refattr}).types[1]).maintype = cls.ancestor) ORDER BY (cls.id, r.bases[1]), cls.depth '''.format( schematab=schematab, reftab='edgedb.{}'.format(refdict.ref_cls.__name__), refattr=q(refdict.backref_attr), src=dbname(sn.Name('std::source')), tgt=dbname(sn.Name('std::target')), ) else: link_query = ''' SELECT {refattr} AS {src}, id AS {tgt} FROM {reftab} '''.format( reftab='edgedb.{}'.format(refdict.ref_cls.__name__), refattr=q(refdict.backref_attr), src=dbname(sn.Name('std::source')), tgt=dbname(sn.Name('std::target')), ) if pn.name == 'attributes': link_query = ''' SELECT q.*, av.value AS {valprop} FROM ({query} ) AS q INNER JOIN edgedb.AttributeValue av ON (q.{tgt} = ((av.attribute).types[1]).maintype AND q.{src} = ((av.subject).types[1]).maintype) '''.format( query=link_query, src=dbname(sn.Name('std::source')), tgt=dbname(sn.Name('std::target')), valprop=dbname(sn.Name('schema::value')), ) # In addition to custom attributes returned by the # generic refdict query above, collect and return # standard system attributes. partitions = [] for metaclass in get_interesting_metaclasses(): fields = metaclass.get_ownfields() attrs = [] for fn in fields: field = metaclass.get_field(fn) if field.ephemeral: continue ftype = field.type[0] if issubclass(ftype, (s_obj.Object, s_obj.ObjectCollection, typed.AbstractTypedCollection, list, dict)): continue aname = 'stdattrs::{}'.format(fn) attrcls = schema.get(aname, default=None) if attrcls is None: raise RuntimeError( 'introspection schema error: {}.{} is not ' 'defined as `stdattrs` Attribute'.format( metaclass.__name__, fn)) aname = ql(aname) + '::text' aval = q(fn) + '::text' if fn == 'name': aval = 'edgedb.get_shortname({})'.format(aval) attrs.append([aname, aval]) if attrs: values = ', '.join('({}, {})'.format(k, v) for k, v in attrs) qry = ''' SELECT id AS subject_id, a.* FROM {schematab}, UNNEST(ARRAY[{values}]) AS a( attr_name text, attr_value text ) '''.format(schematab='edgedb.{}'.format( metaclass.__name__), values=values) partitions.append(qry) if partitions: union = ('\n' + (' ' * 16) + 'UNION \n').join(partitions) stdattrs = ''' SELECT vals.subject_id AS {src}, attrs.id AS {tgt}, vals.attr_value AS {valprop} FROM ({union} ) AS vals INNER JOIN edgedb.Attribute attrs ON (vals.attr_name = attrs.name) '''.format( union=union, src=dbname(sn.Name('std::source')), tgt=dbname(sn.Name('std::target')), valprop=dbname(sn.Name('schema::value')), ) link_query += ('\n' + (' ' * 16) + 'UNION ALL (\n' + stdattrs + '\n' + (' ' * 16) + ')') else: link_query = None if field is not None: ftype = field.type[0] else: ftype = type(None) if issubclass(ftype, (s_obj.ObjectSet, s_obj.ObjectList)): if ptr.singular(): raise RuntimeError( 'introspection schema error: {!r} must not be ' 'singular'.format('(' + schema_cls.name + ')' + '.' + pn.name)) # ObjectSet and ObjectList fields are stored as uuid[], # so we just need to unnest the array here. refattr = 'UNNEST(' + q(pn.name) + ')' elif pn.name == 'params' and mcls is s_funcs.Function: # Func params need special handling as they are defined # in sevaral separate fields. link_query = f''' SELECT q.id AS {dbname('std::source')}, edgedb._derive_uuid(q.id, q.num::smallint) AS {dbname('std::target')} FROM (SELECT s.id AS id, t.num - 1 AS num FROM edgedb.{mcls.__name__} AS s, LATERAL UNNEST((s.paramtypes).types) WITH ORDINALITY AS t(id, maintype, name, collection, subtypes, dimensions, is_root, num) WHERE t.is_root ) AS q ''' elif pn.name == 'params' and mcls is s_constraints.Constraint: # Constraint params need special handling as they are defined # in several separate fields. link_query = f''' SELECT q.id AS {dbname('std::source')}, edgedb._derive_uuid(q.id, q.num::smallint) AS {dbname('std::target')}, q.value AS {dbname('schema::value')} FROM (SELECT s.id AS id, t.num - 1 AS num, tv.value AS value FROM edgedb.{mcls.__name__} AS s, LATERAL UNNEST((s.paramtypes).types) WITH ORDINALITY AS t(id, maintype, name, collection, subtypes, dimensions, is_root, num) LEFT JOIN LATERAL UNNEST(s.args) WITH ORDINALITY AS tv(value, num) ON (t.num = tv.num) WHERE t.is_root ) AS q ''' elif issubclass(ftype, (s_obj.Object, s_obj.ObjectCollection)): # All other type fields are encoded as type_t. link_query = f''' SELECT s.id AS {dbname('std::source')}, (CASE WHEN t.collection IS NULL THEN t.maintype ELSE t.id END) AS {dbname('std::target')} FROM edgedb.{mcls.__name__} AS s, LATERAL UNNEST ((s.{q(pn.name)}).types) AS t( id, maintype, name, collection, subtypes, dimensions, is_root ) WHERE t.is_root ''' else: if not ptr.singular(): raise RuntimeError('introspection schema error: {!r} must be ' 'singular'.format('(' + schema_cls.name + ')' + '.' + pn.name)) refattr = q(pn.name) if link_query is None: link_query = ''' SELECT id AS {src}, {refattr} AS {tgt} FROM {schematab} '''.format( schematab='edgedb.{}'.format(mcls.__name__), refattr=refattr, src=dbname(sn.Name('std::source')), tgt=dbname(sn.Name('std::target')), ) return dbops.View(name=tabname(ptr), query=link_query)
async def generate_views(conn, schema): """Setup views the introspection schema. The introspection views emulate regular type and link tables for the classes in the "schema" module by querying the actual metadata tables. """ commands = dbops.CommandGroup() # We use a separate schema to make it easy to redirect queries. commands.add_command(dbops.CreateSchema(name='edgedbss')) metaclasses = get_interesting_metaclasses() views = collections.OrderedDict() type_fields = [] for mcls in metaclasses: if mcls is s_named.NamedObject: schema_name = 'Object' else: schema_name = mcls.__name__ schema_cls = schema.get(sn.Name(module='schema', name=schema_name), default=None) if schema_cls is None: # Not all schema metaclasses are represented in the # introspection schema, just ignore them. continue cols = [] for pn, ptr in schema_cls.pointers.items(): if ptr.is_pure_computable(): continue field = mcls.get_field(pn.name) refdict = None if field is None: if pn.name == 'attributes': # Special hack to allow generic introspection of # both generic and standard attributes, so we # pretend all classes are AttributeSubjects. refdict = s_attrs.AttributeSubject.attributes elif issubclass(mcls, s_ref.ReferencingObject): fn = classref_attr_aliases.get(pn.name, pn.name) refdict = mcls.get_refdict(fn) if refdict is not None and ptr.singular(): # This is nether a field, nor a refdict, that's # not expected. raise RuntimeError( 'introspection schema error: {!r} must not be ' 'singular'.format('(' + schema_cls.name + ')' + '.' + pn.name)) if field is None and refdict is None: if pn.name == 'id': # Id is present implicitly in schema tables. pass elif pn.name == '__type__': continue elif pn.name == 'params' and (mcls is s_funcs.Function or mcls is s_constraints.Constraint): # Function params need special handling as # they are defined as three separate fields. pass else: # This is nether a field, nor a refdict, that's # not expected. raise RuntimeError( 'introspection schema error: cannot resolve ' '{!r} into metadata reference'.format('(' + schema_cls.name + ')' + '.' + pn.name)) if field is not None: ft = field.type[0] if (issubclass(ft, (s_obj.Object, s_obj.ObjectCollection)) and not issubclass(ft, (s_obj.ObjectSet, s_obj.ObjectList))): type_fields.append((f'edgedb.{mcls.__name__}', pn.name)) ptrstor = types.get_pointer_storage_info(ptr, schema=schema) if ptrstor.table_type == 'ObjectType': if (pn.name == 'name' and issubclass( mcls, (s_inheriting.InheritingObject, s_funcs.Function))): col_expr = 'edgedb.get_shortname(t.{})'.format(q(pn.name)) else: col_expr = f't.{q(pn.name)}' cols.append((col_expr, dbname(ptr.shortname))) else: view = _get_link_view(mcls, schema_cls, field, ptr, refdict, schema) if view.name not in views: views[view.name] = view coltext = textwrap.indent( ',\n'.join(('{} AS {}'.format(*c) for c in cols)), ' ' * 16) view_query = f''' SELECT {coltext.strip()}, no.id AS "std::__type__" FROM edgedb.{mcls.__name__} AS t INNER JOIN pg_class AS c ON (t.tableoid = c.oid) INNER JOIN pg_description AS cmt ON (c.oid = cmt.objoid AND c.tableoid = cmt.classoid) INNER JOIN edgedb.NamedObject AS no ON (no.name = cmt.description) ''' view = dbops.View(name=tabname(schema_cls), query=view_query) views[view.name] = view type_views = _generate_types_views(schema, type_fields) views.update({v.name: v for v in type_views}) for v in type_views: views.move_to_end(v.name, last=False) te_view = _generate_type_element_view(schema, type_fields) views[te_view.name] = te_view fp_view = _generate_param_view(schema) views[fp_view.name] = fp_view types_view = views[tabname(schema.get('schema::Type'))] types_view.query += '\nUNION ALL\n' + '\nUNION ALL\n'.join(f''' ( SELECT "schema::name", "schema::description", "std::id", "std::__type__" FROM {common.qname(*view.name)} ) ''' for view in type_views) for view in views.values(): commands.add_command(dbops.CreateView(view)) await commands.execute(Context(conn))
dbops.CreateFunction(LinkNameToTableNameFunction()), dbops.CreateFunction(IssubclassFunction()), dbops.CreateFunction(IssubclassFunction2()), dbops.CreateFunction(IsinstanceFunction()), dbops.CreateFunction(NormalizeNameFunction()), dbops.CreateFunction(OrFilterFunction()), ]) await commands.execute(Context(conn)) classref_attr_aliases = {'links': 'pointers', 'link_properties': 'pointers'} dbname = lambda n: \ common.quote_ident(common.edgedb_name_to_pg_name(sn.Name(n))) tabname = lambda obj: \ ('edgedbss', common.get_table_name(obj, catenate=False)[1]) q = common.quote_ident ql = common.quote_literal def _get_link_view(mcls, schema_cls, field, ptr, refdict, schema): pn = ptr.shortname if refdict: if (issubclass(mcls, s_inheriting.InheritingObject) or mcls is s_named.NamedObject): if mcls is s_named.NamedObject: schematab = 'edgedb.InheritingObject'
def _cb(name): clsid = class_map.get(name) if clsid: return sn.Name(module='__class__', name=str(clsid)) else: return name
def __init__(self, element_name): super().__init__( name=s_name.Name(module='__tuple__', name=str(element_name)))
import functools import typing from edgedb.lang.ir import utils as irutils from edgedb.lang.schema import scalars as s_scalars from edgedb.lang.schema import objtypes as s_objtypes from edgedb.lang.schema import name as sn from edgedb.lang.schema import objects as s_obj from edgedb.lang.schema import schema as s_schema from edgedb.lang.schema import types as s_types from . import common base_type_name_map = { sn.Name('std::str'): 'text', sn.Name('std::int64'): 'bigint', sn.Name('std::int32'): 'integer', sn.Name('std::int16'): 'smallint', sn.Name('std::decimal'): 'numeric', sn.Name('std::bool'): 'boolean', sn.Name('std::float64'): 'float8', sn.Name('std::float32'): 'float4', sn.Name('std::uuid'): 'uuid', sn.Name('std::datetime'): 'timestamptz', sn.Name('std::date'): 'date', sn.Name('std::time'): 'timetz', sn.Name('std::timedelta'): 'interval', sn.Name('std::bytes'): 'bytea', sn.Name('std::json'): 'jsonb', }