Exemplo n.º 1
0
def _cast_json_to_tuple(
        ir_set: irast.Set,
        orig_stype: s_types.Type,
        new_stype: s_types.Tuple,
        cardinality_mod: Optional[qlast.CardinalityModifier],
        *,
        srcctx: Optional[parsing.ParserContext],
        ctx: context.ContextLevel) -> irast.Set:

    with ctx.new() as subctx:
        subctx.anchors = subctx.anchors.copy()
        source_path = subctx.create_anchor(ir_set, 'a')

        # Top-level json->tuple casts should produce an empty set on
        # null inputs, but error on missing fields or null
        # subelements, so filter out json nulls directly here to
        # distinguish those cases.
        if cardinality_mod != qlast.CardinalityModifier.Required:
            pathctx.register_set_in_scope(ir_set, ctx=subctx)

            check = qlast.FunctionCall(
                func=('__std__', 'json_typeof'), args=[source_path]
            )
            filtered = qlast.SelectQuery(
                result=source_path,
                where=qlast.BinOp(
                    left=check,
                    op='!=',
                    right=qlast.StringConstant(value='null'),
                )
            )
            filtered_ir = dispatch.compile(filtered, ctx=subctx)
            source_path = subctx.create_anchor(filtered_ir, 'a')

        # TODO: try using jsonb_to_record instead of a bunch of
        # json_get calls and see if that is faster.
        elements = []
        for new_el_name, new_st in new_stype.iter_subtypes(ctx.env.schema):
            val_e = qlast.FunctionCall(
                func=('__std__', 'json_get'),
                args=[
                    source_path,
                    qlast.StringConstant(value=new_el_name),
                ],
            )

            val = dispatch.compile(val_e, ctx=subctx)

            val = compile_cast(
                val, new_st,
                cardinality_mod=qlast.CardinalityModifier.Required,
                ctx=subctx, srcctx=srcctx)

            elements.append(irast.TupleElement(name=new_el_name, val=val))

        return setgen.new_tuple_set(
            elements,
            named=new_stype.is_named(ctx.env.schema),
            ctx=subctx,
        )
Exemplo n.º 2
0
 def _get_ast(
     self,
     schema: s_schema.Schema,
     context: sd.CommandContext,
     *,
     parent_node: Optional[qlast.DDLOperation] = None,
 ) -> Optional[qlast.DDLOperation]:
     node = super()._get_ast(schema, context, parent_node=parent_node)
     assert isinstance(node, qlast.CreateExtension)
     pkg = self.get_resolved_attribute_value('package',
                                             schema=schema,
                                             context=context)
     node.version = qlast.StringConstant(value=str(pkg.get_version(schema)))
     return node
Exemplo n.º 3
0
 def _apply_field_ast(
     self,
     schema: s_schema.Schema,
     context: sd.CommandContext,
     node: qlast.DDLOperation,
     op: sd.AlterObjectProperty,
 ) -> None:
     assert isinstance(node, qlast.CreateExtensionPackage)
     if op.property == 'script':
         node.body = qlast.NestedQLBlock(
             text=op.new_value,
             commands=qlparser.parse_block(op.new_value),
         )
     elif op.property == 'version':
         node.version = qlast.StringConstant(value=str(op.new_value), )
     else:
         super()._apply_field_ast(schema, context, node, op)
Exemplo n.º 4
0
    def reduce_SCONST(self, str_tok):
        match = lexutils.VALID_STRING_RE.match(str_tok.val)

        if not match:
            raise EdgeQLSyntaxError(f"invalid string literal",
                                    context=str_tok.context)
        if match.group('err_esc'):
            raise EdgeQLSyntaxError(
                f"invalid string literal: invalid escape sequence "
                f"'{match.group('err_esc')}'",
                context=str_tok.context)

        quote = match.group('Q')
        val = match.group('body')

        # handle line continuations
        val = re.sub(r'\\\n', '', val)

        self.val = qlast.StringConstant(value=val, quote=quote)
Exemplo n.º 5
0
    def _compile_and_apply_delta_command(self, ctx: CompileContext,
                                         cmd) -> dbstate.BaseQuery:

        current_tx = ctx.state.current_tx()
        schema = current_tx.get_schema()
        context = self._new_delta_context(ctx)

        if current_tx.is_implicit():
            if isinstance(cmd, s_deltas.CreateDelta):
                command = 'CREATE MIGRATION'
            elif isinstance(cmd, s_deltas.GetDelta):
                command = 'GET MIGRATION'
            else:
                command = 'COMMIT MIGRATION'
            raise errors.QueryError(
                f'{command} must be executed in a transaction block')

        if isinstance(cmd, s_deltas.CreateDelta):
            delta = None
        else:
            delta = schema.get(cmd.classname)

        with context(s_deltas.DeltaCommandContext(schema, cmd, delta)):
            if isinstance(cmd, s_deltas.CommitDelta):
                ddl_plan = s_delta.DeltaRoot(canonical=True)
                ddl_plan.update(delta.get_commands(schema))
                return self._compile_and_apply_ddl_command(ctx, ddl_plan)

            elif isinstance(cmd, s_deltas.GetDelta):
                delta_ql = s_ddl.ddl_text_from_delta(schema, delta)
                query_ql = qlast.SelectQuery(result=qlast.StringConstant(
                    quote="'", value=ql_quote.escape_string(delta_ql)))
                return self._compile_ql_query(ctx, query_ql)

            elif isinstance(cmd, s_deltas.CreateDelta):
                schema, _ = cmd.apply(schema, context)
                current_tx.update_schema(schema)
                # We must return *some* SQL; return a no-op command.
                return dbstate.DDLQuery(sql=(b'SELECT NULL LIMIT 0;', ))

            else:
                raise errors.InternalServerError(
                    f'unexpected delta command: {cmd!r}')  # pragma: no cover
Exemplo n.º 6
0
def _cast_json_to_tuple(ir_set: irast.Set, orig_stype: s_types.Type,
                        new_stype: s_types.Tuple, *,
                        srcctx: Optional[parsing.ParserContext],
                        ctx: context.ContextLevel) -> irast.Set:

    with ctx.new() as subctx:
        subctx.anchors = subctx.anchors.copy()
        source_alias = subctx.aliases.get('a')
        subctx.anchors[source_alias] = ir_set

        # TODO: try using jsonb_to_record instead of a bunch of
        # json_get calls and see if that is faster.
        elements = []
        for new_el_name, new_st in new_stype.iter_subtypes(ctx.env.schema):
            val_e = qlast.FunctionCall(
                func=('__std__', 'json_get'),
                args=[
                    qlast.Path(steps=[qlast.ObjectRef(name=source_alias)]),
                    qlast.StringConstant(value=new_el_name),
                ],
            )

            val = dispatch.compile(val_e, ctx=subctx)

            val = compile_cast(
                val,
                new_st,
                cardinality_mod=qlast.CardinalityModifier.Required,
                ctx=subctx,
                srcctx=srcctx)

            elements.append(irast.TupleElement(name=new_el_name, val=val))

        return setgen.new_tuple_set(
            elements,
            named=new_stype.is_named(ctx.env.schema),
            ctx=subctx,
        )
Exemplo n.º 7
0
    def reduce_SCONST(self, str_tok):
        match = lexutils.VALID_STRING_RE.match(str_tok.val)

        if not match:
            raise EdgeQLSyntaxError(f"invalid string literal",
                                    context=str_tok.context)
        if match.group('err_esc'):
            raise EdgeQLSyntaxError(
                f"invalid string literal: invalid escape sequence "
                f"'{match.group('err_esc')}'",
                context=str_tok.context)
        elif match.group('err_cont'):
            raise EdgeQLSyntaxError(
                f"invalid string literal: invalid line continuation",
                hint="newline has to immediately follow '\\'",
                context=str_tok.context)

        quote = match.group('Q')
        val = match.group('body')

        # collapse the whitespace after a line continuation
        val = lexutils.collapse_newline_whitespace(val)

        self.val = qlast.StringConstant(value=val, quote=quote)
Exemplo n.º 8
0
 def reduce_SCONST(self, token):
     self.val = qlast.StringConstant(value=token.clean_value)
Exemplo n.º 9
0
 def visit_EnumValue(self, node):
     return qlast.StringConstant(value=node.value, quote='"')