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, )
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
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)
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)
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
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, )
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)
def reduce_SCONST(self, token): self.val = qlast.StringConstant(value=token.clean_value)
def visit_EnumValue(self, node): return qlast.StringConstant(value=node.value, quote='"')