def _create_begin(self, schema, context): fullname = self.classname shortname = sn.shortname_from_fullname(fullname) cp = self._get_param_desc_from_delta(schema, self) signature = f'{shortname}({", ".join(p.as_str(schema) for p in cp)})' func = schema.get(fullname, None) if func: raise errors.InvalidOperatorDefinitionError( f'cannot create the `{signature}` operator: ' f'an operator with the same signature ' f'is already defined', context=self.source_context) schema = super()._create_begin(schema, context) params: s_func.FuncParameterList = self.scls.get_params(schema) fullname = self.scls.get_name(schema) shortname = sn.shortname_from_fullname(fullname) return_type = self.scls.get_return_type(schema) return_typemod = self.scls.get_return_typemod(schema) get_signature = lambda: f'{shortname}{params.as_str(schema)}' for oper in schema.get_operators(shortname, ()): oper_return_typemod = oper.get_return_typemod(schema) if oper_return_typemod != return_typemod: raise errors.DuplicateOperatorDefinitionError( f'cannot create the `{get_signature()} -> ' f'{return_typemod.to_edgeql()} {return_type.name}` ' f'operator: overloading another operator with different ' f'return type {oper_return_typemod.to_edgeql()} ' f'{oper.get_return_type(schema).name}', context=self.source_context) return schema
def _create_begin(self, schema, context): fullname = self.classname shortname = sn.shortname_from_fullname(fullname) cp = self._get_param_desc_from_delta(schema, self) signature = f'{shortname}({", ".join(p.as_str(schema) for p in cp)})' func = schema.get(fullname, None) if func: raise errors.InvalidOperatorDefinitionError( f'cannot create the `{signature}` operator: ' f'an operator with the same signature ' f'is already defined', context=self.source_context) schema = super()._create_begin(schema, context) params: s_func.FuncParameterList = self.scls.get_params(schema) fullname = self.scls.get_name(schema) shortname = sn.shortname_from_fullname(fullname) return_type = self.scls.get_return_type(schema) return_typemod = self.scls.get_return_typemod(schema) recursive = self.scls.get_recursive(schema) get_signature = lambda: f'{shortname}{params.as_str(schema)}' # an operator must have operands if len(params) == 0: raise errors.InvalidOperatorDefinitionError( f'cannot create the `{signature}` operator: ' f'an operator must have operands', context=self.source_context) # We'll need to make sure that there's no mix of recursive and # non-recursive operators being overloaded. all_arrays = all_tuples = True for param in params.objects(schema): ptype = param.get_type(schema) all_arrays = all_arrays and ptype.is_array() all_tuples = all_tuples and ptype.is_tuple() # It's illegal to declare an operator as recursive unless all # of its operands are the same basic type of collection. if recursive and not (all_arrays or all_tuples): raise errors.InvalidOperatorDefinitionError( f'cannot create the `{signature}` operator: ' f'operands of a recursive operator must either be ' f'all arrays or all tuples', context=self.source_context) for oper in schema.get_operators(shortname, ()): oper_return_typemod = oper.get_return_typemod(schema) if oper_return_typemod != return_typemod: raise errors.DuplicateOperatorDefinitionError( f'cannot create the `{get_signature()} -> ' f'{return_typemod.to_edgeql()} {return_type.name}` ' f'operator: overloading another operator with different ' f'return type {oper_return_typemod.to_edgeql()} ' f'{oper.get_return_type(schema).name}', context=self.source_context) # Check if there is a recursive/non-recursive operator # overloading. oper_recursive = oper.get_recursive(schema) if recursive != oper_recursive: oper_signature = oper.get_display_signature(schema) oper_all_arrays = oper_all_tuples = True for param in oper.get_params(schema).objects(schema): ptype = param.get_type(schema) oper_all_arrays = oper_all_arrays and ptype.is_array() oper_all_tuples = oper_all_tuples and ptype.is_tuple() if (all_arrays == oper_all_arrays and all_tuples == oper_all_tuples): new_rec = 'recursive' if recursive else 'non-recursive' oper_rec = \ 'recursive' if oper_recursive else 'non-recursive' raise errors.InvalidOperatorDefinitionError( f'cannot create the {new_rec} `{signature}` operator: ' f'overloading a {oper_rec} operator ' f'`{oper_signature}` with a {new_rec} one ' f'is not allowed', context=self.source_context) return schema
def _process_operator_body(self, block, abstract: bool=False): props = {} commands = [] from_operator = None from_function = None from_expr = False code = None for node in block.val: if isinstance(node, qlast.OperatorCode): if abstract: raise errors.InvalidOperatorDefinitionError( 'unexpected FROM clause in abstract ' 'operator definition', context=node.context, ) if node.from_function: if from_function is not None: raise errors.InvalidOperatorDefinitionError( 'more than one FROM FUNCTION clause', context=node.context) from_function = node.from_function elif node.from_operator: if from_operator is not None: raise errors.InvalidOperatorDefinitionError( 'more than one FROM OPERATOR clause', context=node.context) from_operator = node.from_operator elif node.code: if code is not None: raise errors.InvalidOperatorDefinitionError( 'more than one FROM <code> clause', context=node.context) code = node.code else: # FROM SQL EXPRESSION from_expr = True else: commands.append(node) if not abstract: if (code is None and from_operator is None and from_function is None and not from_expr): raise errors.InvalidOperatorDefinitionError( 'CREATE OPERATOR requires at least one FROM clause', context=block.context) else: if from_expr and (from_operator or from_function or code): raise errors.InvalidOperatorDefinitionError( 'FROM SQL EXPRESSION is mutually exclusive with other ' 'FROM variants', context=block.context) props['code'] = qlast.OperatorCode( language=qlast.Language.SQL, from_function=from_function, from_operator=from_operator, from_expr=from_expr, code=code, ) if commands: props['commands'] = commands return props