def _update_lprops( cmd: s_ref.ReferencedObjectCommand, # type: ignore *, classlayout: Dict[Type[so.Object], sr_struct.SchemaTypeLayout], schema: s_schema.Schema, blocks: List[Tuple[str, Dict[str, Any]]], context: sd.CommandContext, is_internal_reflection: bool, stdmode: bool, ) -> None: mcls = cmd.get_schema_metaclass() refctx = cmd.get_referrer_context_or_die(context) refop = refctx.op refcls = refop.get_schema_metaclass() refdict = refcls.get_refdict_for_class(mcls) layout = classlayout[refcls][refdict.attr] lprops = layout.properties if not lprops: return if mcls.get_reflection_method() is so.ReflectionMethod.AS_LINK: target_link = mcls.get_reflection_link() assert target_link is not None target_field = mcls.get_field(target_link) target_obj = cmd.get_ddl_identity(target_link) if target_obj is None: raise AssertionError( f'cannot find link target in ddl_identity of a command for ' f'schema class reflected as link: {cmd!r}' ) target_ref = target_obj.get_name(schema) target_clsname = target_field.type.__name__ else: referrer_cls = refop.get_schema_metaclass() target_field = referrer_cls.get_field(refdict.attr) if issubclass(target_field.type, so.ObjectCollection): target_type = target_field.type.type else: target_type = target_field.type target_clsname = target_type.__name__ target_link = refdict.attr target_ref = cmd.classname shape, append_variables = _build_object_mutation_shape( cmd, classlayout=classlayout, lprop_fields=lprops, lprops_only=True, is_internal_reflection=is_internal_reflection, stdmode=stdmode, schema=schema, context=context, ) if shape: parent_variables = {} parent_variables[f'__{target_link}'] = json.dumps(target_ref) # XXX: we have to do a -= followed by a += because # support for filtered nested link property updates # is currently broken. parent_update_query = f''' UPDATE schema::{refcls.__name__} FILTER .name__internal = <str>$__parent_classname SET {{ {refdict.attr} -= ( SELECT DETACHED (schema::{target_clsname}) FILTER .name__internal = <str>$__{target_link} ) }} ''' parent_variables['__parent_classname'] = ( json.dumps(refop.classname) ) blocks.append((parent_update_query, parent_variables)) parent_update_query = f''' UPDATE schema::{refcls.__name__} FILTER .name__internal = <str>$__parent_classname SET {{ {refdict.attr} += ( SELECT schema::{target_clsname} {{ {shape} }} FILTER .name__internal = <str>$__{target_link} ) }} ''' parent_variables.update(append_variables) blocks.append((parent_update_query, parent_variables))
def _update_lprops( cmd: s_ref.ReferencedObjectCommand, # type: ignore *, classlayout: Dict[Type[so.Object], sr_struct.SchemaTypeLayout], schema: s_schema.Schema, blocks: List[Tuple[str, Dict[str, Any]]], context: sd.CommandContext, internal_schema_mode: bool, stdmode: bool, ) -> None: mcls = cmd.get_schema_metaclass() refctx = cmd.get_referrer_context_or_die(context) refop = refctx.op refcls = refop.get_schema_metaclass() refdict = refcls.get_refdict_for_class(mcls) layout = classlayout[refcls][refdict.attr] lprops = layout.properties if not lprops: return reflect_as_link = (mcls.get_reflection_method() is so.ReflectionMethod.AS_LINK) if reflect_as_link: target_link = mcls.get_reflection_link() assert target_link is not None target_field = mcls.get_field(target_link) target_obj = cmd.get_ddl_identity(target_link) if target_obj is None: raise AssertionError( f'cannot find link target in ddl_identity of a command for ' f'schema class reflected as link: {cmd!r}') target_ref = target_obj.get_name(schema) target_clsname = target_field.type.__name__ else: referrer_cls = refop.get_schema_metaclass() target_field = referrer_cls.get_field(refdict.attr) if issubclass(target_field.type, so.ObjectCollection): target_type = target_field.type.type else: target_type = target_field.type target_clsname = target_type.__name__ target_link = refdict.attr target_ref = cmd.classname shape, append_variables = _build_object_mutation_shape( cmd, classlayout=classlayout, lprop_fields=lprops, lprops_only=True, internal_schema_mode=internal_schema_mode, stdmode=stdmode, schema=schema, context=context, ) if shape: parent_variables = {} parent_variables[f'__{target_link}'] = json.dumps(str(target_ref)) ref_name = context.get_referrer_name(refctx) parent_variables['__parent_classname'] = json.dumps(str(ref_name)) # XXX: we have to do a -= followed by a += because # support for filtered nested link property updates # is currently broken. assignments = [] assignments.append( textwrap.dedent(f'''\ {refdict.attr} -= ( SELECT DETACHED (schema::{target_clsname}) FILTER .name__internal = <str>$__{target_link} )''')) if reflect_as_link: parent_variables[f'__{target_link}_shadow'] = (json.dumps( str(cmd.classname))) assignments.append( textwrap.dedent(f'''\ {refdict.attr}__internal -= ( SELECT DETACHED (schema::{mcls.__name__}) FILTER .name__internal = <str>$__{target_link}_shadow )''')) update_shape = textwrap.indent('\n' + ',\n'.join(assignments), ' ' * 4) parent_update_query = textwrap.dedent(f'''\ UPDATE schema::{refcls.__name__} FILTER .name__internal = <str>$__parent_classname SET {{{update_shape} }} ''') blocks.append((parent_update_query, parent_variables)) assignments = [] shape = textwrap.indent(f'\n{shape}', ' ' * 5) assignments.append( textwrap.dedent(f'''\ {refdict.attr} += ( SELECT schema::{target_clsname} {{{shape} }} FILTER .name__internal = <str>$__{target_link} )''')) if reflect_as_link: shadow_clslayout = classlayout[refcls] shadow_link_layout = shadow_clslayout[f'{refdict.attr}__internal'] shadow_shape, shadow_variables = _build_object_mutation_shape( cmd, classlayout=classlayout, internal_schema_mode=internal_schema_mode, lprop_fields=shadow_link_layout.properties, lprops_only=True, stdmode=stdmode, var_prefix='shadow_', schema=schema, context=context, ) shadow_shape = textwrap.indent(f'\n{shadow_shape}', ' ' * 6) assignments.append( textwrap.dedent(f'''\ {refdict.attr}__internal += ( SELECT schema::{mcls.__name__} {{{shadow_shape} }} FILTER .name__internal = <str>$__{target_link}_shadow )''')) parent_variables.update(shadow_variables) update_shape = textwrap.indent('\n' + ',\n'.join(assignments), ' ' * 4) parent_update_query = textwrap.dedent(f''' UPDATE schema::{refcls.__name__} FILTER .name__internal = <str>$__parent_classname SET {{{update_shape} }} ''') parent_variables.update(append_variables) blocks.append((parent_update_query, parent_variables))