def _get_ast(self, context): value = self.new_value new_value_empty = \ (value is None or (isinstance(value, collections.Container) and not value)) old_value_empty = \ (self.old_value is None or (isinstance(self.old_value, collections.Container) and not self.old_value)) if new_value_empty and not old_value_empty: op = qlast.DropAttributeValue( name=qlast.ObjectRef(module='', name=self.property)) return op if new_value_empty and old_value_empty: return if isinstance(value, s_expr.ExpressionText): value = edgeql.parse(str(value)) elif utils.is_nontrivial_container(value): value = qlast.Tuple(elements=[ qlast.Constant(value=el) for el in value ]) elif isinstance(value, nlang.WordCombination): forms = value.as_dict() if len(forms) > 1: items = [] for k, v in forms.items(): items.append(( qlast.Constant(value=k), qlast.Constant(value=v) )) value = qlast.Array(elements=[ qlast.Tuple(elements=[k, v]) for k, v in items ]) else: value = qlast.Constant(value=str(value)) else: value = qlast.Constant(value=value) as_expr = isinstance(value, qlast.ExpressionText) op = qlast.CreateAttributeValue( name=qlast.ObjectRef(module='', name=self.property), value=value, as_expr=as_expr) return op
def _apply_field_ast(self, context, node, op): if op.property == 'spectargets': if op.new_value: node.commands.append( qlast.AlterTarget(targets=[ qlast.ObjectRef(name=t.classname.name, module=t.classname.module) for t in op.new_value ])) elif op.property == 'target': if op.new_value: node.commands.append( qlast.AlterTarget(targets=[ qlast.ObjectRef(name=op.new_value.classname.name, module=op.new_value.classname.module) ])) elif op.property == 'source': pass elif op.property == 'search': if op.new_value: v = qlast.Constant(value=str(op.new_value.weight)) self._set_attribute_ast(context, node, 'search_weight', v) else: self._drop_attribute_ast(context, node, 'search_weight') else: super()._apply_field_ast(context, node, op)
def _apply_field_ast(self, context, node, op): objtype = context.get(LinkSourceCommandContext) if op.property == 'is_derived': pass elif op.property == 'spectargets': if op.new_value: node.targets = [ qlast.ObjectRef(name=t.classname.name, module=t.classname.module) for t in op.new_value ] elif op.property == 'default': self._encode_default(context, node, op) elif op.property == 'required': node.is_required = op.new_value elif op.property == 'source': pass elif op.property == 'search': if op.new_value: v = qlast.Constant(value=str(op.new_value.weight)) self._set_attribute_ast(context, node, 'search_weight', v) elif op.property == 'target' and objtype: if not node.targets: t = op.new_value node.targets = [utils.typeref_to_ast(t)] else: super()._apply_field_ast(context, node, op)
def _encode_default(self, context, node, op): if op.new_value: expr = op.new_value if not isinstance(expr, sexpr.ExpressionText): expr_t = qlast.SelectQuery(result=qlast.Constant(value=expr)) expr = edgeql.generate_source(expr_t, pretty=False) op.new_value = sexpr.ExpressionText(expr) super()._apply_field_ast(context, node, op)
def _apply_field_ast(self, context, node, op): if op.property == 'value': node.value = qlast.Constant(value=op.new_value) elif op.property == 'is_derived': pass elif op.property == 'attribute': pass elif op.property == 'subject': pass else: super()._apply_field_ast(context, node, op)
def visit_Constant(self, node): return qlast.Constant(value=node.value)
def reduce_FALSE(self, *kids): self.val = qlast.Constant(value=False)
def reduce_TRUE(self, *kids): self.val = qlast.Constant(value=True)
def reduce_SCONST(self, *kids): self.val = qlast.Constant(value=str(kids[0].string))
def reduce_FCONST(self, *kids): self.val = qlast.Constant(value=float(kids[0].val))
def computable_ptr_set(rptr: irast.Pointer, *, unnest_fence: bool = False, ctx: context.ContextLevel) -> irast.Set: """Return ir.Set for a pointer defined as a computable.""" ptrcls = rptr.ptrcls # Must use an entirely separate context, as the computable # expression is totally independent from the surrounding query. subctx = stmtctx.init_context(schema=ctx.schema) self_ = rptr.source source_scls = self_.scls # process_view() may generate computable pointer expressions # in the form "self.linkname". To prevent infinite recursion, # self must resolve to the parent type of the view NOT the view # type itself. Similarly, when resolving computable link properties # make sure that we use rptr.ptrcls.derived_from. if source_scls.is_view(): self_ = copy.copy(self_) self_.scls = source_scls.peel_view() self_.shape = [] if self_.rptr is not None: derived_from = self_.rptr.ptrcls.derived_from if (derived_from is not None and not derived_from.generic() and derived_from.derived_from is not None and ptrcls.is_link_property()): self_.rptr.ptrcls = derived_from subctx.anchors[qlast.Source] = self_ subctx.aliases = ctx.aliases subctx.stmt = ctx.stmt subctx.view_scls = ptrcls.target subctx.view_rptr = context.ViewRPtr(source_scls, ptrcls=ptrcls, rptr=rptr) subctx.toplevel_stmt = ctx.toplevel_stmt subctx.path_scope = ctx.path_scope subctx.pending_cardinality = ctx.pending_cardinality subctx.completion_work = ctx.completion_work subctx.pointer_derivation_map = ctx.pointer_derivation_map subctx.class_shapes = ctx.class_shapes subctx.all_sets = ctx.all_sets subctx.path_scope_map = ctx.path_scope_map subctx.scope_id_ctr = ctx.scope_id_ctr subctx.expr_exposed = ctx.expr_exposed if ptrcls.is_link_property(): source_path_id = rptr.source.path_id.ptr_path() else: source_path_id = rptr.target.path_id.src_path() path_id = source_path_id.extend(ptrcls, s_pointers.PointerDirection.Outbound, ptrcls.target) subctx.path_scope.contain_path(path_id) try: qlexpr, qlctx = ctx.source_map[ptrcls] except KeyError: if not ptrcls.default: raise ValueError( f'{ptrcls.shortname!r} is not a computable pointer') if isinstance(ptrcls.default, s_expr.ExpressionText): qlexpr = astutils.ensure_qlstmt(qlparser.parse(ptrcls.default)) else: qlexpr = qlast.Constant(value=ptrcls.default) qlctx = None else: subctx.modaliases = qlctx.modaliases.copy() subctx.aliased_views = qlctx.aliased_views.new_child() if source_scls.is_view(): subctx.aliased_views[self_.scls.name] = None subctx.source_map = qlctx.source_map.copy() subctx.view_nodes = qlctx.view_nodes.copy() subctx.view_sets = qlctx.view_sets.copy() subctx.view_map = qlctx.view_map.new_child() subctx.singletons = qlctx.singletons.copy() subctx.path_id_namespce = qlctx.path_id_namespace if qlctx is None: # This is a schema-level computable expression, put all # class refs into a separate namespace. subctx.path_id_namespace = (subctx.aliases.get('ns'), ) else: subctx.pending_stmt_own_path_id_namespace = \ irast.WeakNamespace(ctx.aliases.get('ns')) subns = subctx.pending_stmt_full_path_id_namespace = \ {subctx.pending_stmt_own_path_id_namespace} self_view = ctx.view_sets.get(self_.scls) if self_view: if self_view.path_id.namespace: subns.update(self_view.path_id.namespace) inner_path_id = self_view.path_id.merge_namespace( subctx.path_id_namespace + tuple(subns)) else: if self_.path_id.namespace: subns.update(self_.path_id.namespace) inner_path_id = pathctx.get_path_id( self_.scls, ctx=subctx).merge_namespace(subns) remapped_source = new_set_from_set(rptr.source, ctx=subctx) remapped_source.path_id = \ remapped_source.path_id.merge_namespace(subns) subctx.view_map[inner_path_id] = remapped_source if isinstance(qlexpr, qlast.Statement) and unnest_fence: subctx.stmt_metadata[qlexpr] = context.StatementMetadata( is_unnest_fence=True) comp_ir_set = dispatch.compile(qlexpr, ctx=subctx) if ptrcls in ctx.pending_cardinality: comp_ir_set_copy = copy.copy(comp_ir_set) stmtctx.get_pointer_cardinality_later(ptrcls=ptrcls, irexpr=comp_ir_set_copy, ctx=ctx) def _check_cardinality(ctx): if ptrcls.singular(): stmtctx.enforce_singleton_now(comp_ir_set_copy, ctx=ctx) stmtctx.at_stmt_fini(_check_cardinality, ctx=ctx) comp_ir_set.scls = ptrcls.target comp_ir_set.path_id = path_id comp_ir_set.rptr = rptr rptr.target = comp_ir_set return comp_ir_set
def reduce_COLONGT_NL_INDENT_RawString_NL_DEDENT(self, *kids): text = kids[3].val.value text = textwrap.dedent(text).strip() self.val = qlast.Constant(value=text)
def _apply_fields_ast(self, context, node): super()._apply_fields_ast(context, node) for op in self(sd.AlterObjectProperty): if op.property == 'value': node.value = qlast.Constant(value=op.new_value)
def computable_ptr_set(rptr: irast.Pointer, *, unnest_fence: bool = False, ctx: context.ContextLevel) -> irast.Set: """Return ir.Set for a pointer defined as a computable.""" ptrcls = rptr.ptrcls source_set = rptr.source source_scls = source_set.scls # process_view() may generate computable pointer expressions # in the form "self.linkname". To prevent infinite recursion, # self must resolve to the parent type of the view NOT the view # type itself. Similarly, when resolving computable link properties # make sure that we use rptr.ptrcls.derived_from. if source_scls.is_view(): source_set = new_set_from_set(source_set, preserve_scope_ns=True, ctx=ctx) source_set.scls = source_scls.peel_view() source_set.shape = [] if source_set.rptr is not None: derived_from = source_set.rptr.ptrcls.derived_from if (derived_from is not None and not derived_from.generic() and derived_from.derived_from is not None and ptrcls.is_link_property()): source_set.rptr.ptrcls = derived_from try: qlexpr, qlctx, inner_source_path_id = ctx.source_map[ptrcls] except KeyError: if not ptrcls.default: raise ValueError( f'{ptrcls.shortname!r} is not a computable pointer') if isinstance(ptrcls.default, s_expr.ExpressionText): qlexpr = astutils.ensure_qlstmt(qlparser.parse(ptrcls.default)) else: qlexpr = qlast.Constant(value=ptrcls.default) qlctx = None inner_source_path_id = None if qlctx is None: # Schema-level computable, completely detached context newctx = ctx.detached else: newctx = _get_computable_ctx(rptr=rptr, source=source_set, source_scls=source_scls, inner_source_path_id=inner_source_path_id, qlctx=qlctx, ctx=ctx) if ptrcls.is_link_property(): source_path_id = rptr.source.path_id.ptr_path() else: source_path_id = rptr.target.path_id.src_path() path_id = source_path_id.extend(ptrcls, s_pointers.PointerDirection.Outbound, ptrcls.target) with newctx() as subctx: subctx.view_scls = ptrcls.target subctx.view_rptr = context.ViewRPtr(source_scls, ptrcls=ptrcls, rptr=rptr) subctx.anchors[qlast.Source] = source_set subctx.path_scope.contain_path(path_id) subctx.empty_result_type_hint = ptrcls.target if isinstance(qlexpr, qlast.Statement) and unnest_fence: subctx.stmt_metadata[qlexpr] = context.StatementMetadata( is_unnest_fence=True) comp_ir_set = dispatch.compile(qlexpr, ctx=subctx) if ptrcls in ctx.pending_cardinality: comp_ir_set_copy = copy.copy(comp_ir_set) stmtctx.get_pointer_cardinality_later(ptrcls=ptrcls, irexpr=comp_ir_set_copy, ctx=ctx) def _check_cardinality(ctx): if ptrcls.singular(): stmtctx.enforce_singleton_now(comp_ir_set_copy, ctx=ctx) stmtctx.at_stmt_fini(_check_cardinality, ctx=ctx) comp_ir_set.scls = ptrcls.target comp_ir_set.path_id = path_id comp_ir_set.rptr = rptr rptr.target = comp_ir_set return comp_ir_set
def _visit_arguments(self, arguments): where = offset = limit = None orderby = [] first = last = before = after = None for arg in arguments: try: if arg.name == 'filter': where = self.visit(arg.value) elif arg.name == 'order': orderby = self.visit_order(arg.value) elif arg.name == 'first': first = arg.value.value if first < 0: raise ValueError(f"{arg.name!r} cannot be negative") elif arg.name == 'last': last = arg.value.value last_context = arg.context if last < 0: raise ValueError(f"{arg.name!r} cannot be negative") elif arg.name == 'before': before = int(arg.value.value) if before < 0: raise ValueError(f"{arg.name!r} cannot be negative") elif arg.name == 'after': after = int(arg.value.value) if after < 0: raise ValueError(f"{arg.name!r} cannot be negative") # The +1 is to make 'after' into an appropriate index. # # 0--a--1--b--2--c--3-- ... we call element at # index 0 (or "element 0" for short), the element # immediately after the mark 0. So after "element # 0" really means after "index 1". after += 1 except Exception: raise g_errors.GraphQLValidationError( f"invalid value for {arg.name!r}: {arg.value.value!r}", context=arg.context) from None # convert before, after, first and last into offset and limit if after is not None: offset = after if before is not None: limit = before - (after or 0) if first is not None: if limit is None: limit = first else: limit = min(first, limit) if last is not None: if limit is not None: if last < limit: offset = (offset or 0) + limit - last limit = last else: # FIXME: there wasn't any limit, so we can define last # in terms of offset alone without negative OFFSET # implementation raise g_errors.GraphQLTranslationError( f'last={last} translates to a negative OFFSET in ' f'EdgeQL which is currently unsupported', context=last_context) # convert integers into qlast literals if offset is not None and not isinstance(offset, qlast.Base): offset = qlast.Constant(value=max(0, offset)) if limit is not None: limit = qlast.Constant(value=max(0, limit)) return where, orderby, offset, limit