def to_data(instance: CdmTypeAttributeDefinition, ctx: CdmCorpusContext, res_opt: ResolveOptions, options: CopyOptions) -> TypeAttribute: properties = TypeAttributePersistence.create_properties(instance, res_opt, options) origin_data_type_name = TypeInfo( type_name = '', properties = properties, is_complex_type = False, is_nullable = instance._get_property('isNullable'), type_family = 'cdm') t2pm = TraitToPropertyMap(instance) numeric_traits = t2pm._fetch_trait_reference('is.data_format.numeric.shaped') if numeric_traits is not None: for numeric_traits_arg in numeric_traits.argument: if numeric_traits_arg.name == 'precision': origin_data_type_name.precision = numeric_traits_arg.value if numeric_traits_arg.Name == 'scale': origin_data_type_name.scale = numeric_traits_arg.value data_format = instance._get_property('dataFormat') origin_data_type_name = utils.cdm_data_format_to_syms_data_type(data_format, origin_data_type_name) if origin_data_type_name == None: return None if origin_data_type_name.type_name == None: logger.error(ctx, _TAG, 'toData', instance.at_corpus_path, CdmLogCode.ERR_PERSIST_SYMS_UNKNOWN_DATA_FORMAT, instance.display_name) return None data_col = DataColumn( origin_data_type_name = origin_data_type_name, name = instance.name) return data_col
def apply_default_behavior(entity_attr: 'CdmEntityAttributeDefinition', fk_attr_name: Optional[str], attr_group_name: Optional[str]): '''Applies the replaceAsForeignKey and addAttributeGroup operations to the entity attribute provided.''' ctx = entity_attr.ctx projection = CdmProjection(ctx) # Link for the Source property documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#source projection.source = entity_attr.entity # Link for the RunSequentially property documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#run-sequentially projection.run_sequentially = True entity_attr.entity = CdmEntityReference(ctx, projection, False) if fk_attr_name: foreign_key_attr = CdmTypeAttributeDefinition(ctx, fk_attr_name) foreign_key_attr.data_type = CdmDataTypeReference(ctx, 'entityId', True) # Link for the ReplaceAsForeignKey operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/replaceasforeignkey replace_as_fk_operation = CdmOperationReplaceAsForeignKey(ctx) replace_as_fk_operation.condition = 'referenceOnly' replace_as_fk_operation.reference = 'addressLine' replace_as_fk_operation.replace_with = foreign_key_attr projection.operations.append(replace_as_fk_operation) if attr_group_name: # Link for the AddAttributeGroup operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/addattributegroup add_attr_group_operation = CdmOperationAddAttributeGroup(ctx) add_attr_group_operation.condition = 'structured' add_attr_group_operation.attribute_group_name = attr_group_name projection.operations.append(add_attr_group_operation)
def create_properties(instance: CdmTypeAttributeDefinition, res_opt: ResolveOptions, options: CopyOptions): properties = {} display_name = instance._get_property('display_name') source_name = instance._get_property('source_name') description = instance._get_property('description') is_read_only = instance._get_property('isReadOnly') maximum_length = instance._get_property('maximum_length') maximum_value = instance._get_property('maximum_value') minimum_value = instance._get_property('minimum_value') source_ordering = instance._get_property('source_ordering') value_constrained_to_list = instance._get_property('value_constrained_to_list') is_primary_key = instance._get_property('is_primary_key') def_value = instance._get_property('defaultValue') if display_name is not None: properties['cdm:display_name'] = display_name if instance.explanation is not None: properties['cdm:explanation'] = instance.explanation if source_name is not None: properties['cdm:source_name'] = source_name if description is not None: properties['cdm:description'] = description if instance.applied_traits is not None and len(instance.applied_traits) > 0: applied_traits = \ [trait for trait in instance.applied_traits if isinstance(trait, CdmTraitGroupReference) or not trait.is_from_property] \ if instance.applied_traits else None properties['cdm:traits'] = copy_data_utils._array_copy_data(res_opt, applied_traits, options) if is_read_only is not None: properties['cdm:isReadOnly'] = is_read_only if maximum_length is not None: properties['cdm:maximumLength'] = maximum_length if maximum_value is not None: properties['cdm:maximumValue'] = maximum_value if minimum_value is not None: properties['cdm:minimumValue'] = minimum_value if source_ordering is not None and source_ordering != 0: properties['cdm:sourceOrdering'] = source_ordering if value_constrained_to_list is not None: properties['cdm:valueConstrainedToList'] = value_constrained_to_list if is_primary_key is not None: properties['cdm:isPrimaryKey'] = is_primary_key if def_value is not None: properties['cdm:defaultValue'] = def_value return properties
def test_trait_to_unknown_data_format(self): """Test trait to data format when unknown data format trait is in an attribute.""" cdm_attribute = CdmTypeAttributeDefinition(CdmCorpusContext(CdmCorpusDefinition(), None), 'SomeAttribute') cdm_attribute.applied_traits.append('is.data_format.someRandomDataFormat') trait_to_property_map = TraitToPropertyMap(cdm_attribute) data_format = trait_to_property_map._traits_to_data_format(False) self.assertEqual(CdmDataFormat.UNKNOWN, data_format)
def apply_array_expansion(entity_attr: 'CdmEntityAttributeDefinition', start_ordinal: int, end_ordinal: int, rename_format: str, count_att_name: Optional[str]): '''Applies the arrayExpansion operation to the entity attribute provided. It also takes care of applying a renameattributes operation and optionally applying a addCountAttribute operation.''' ctx = entity_attr.ctx projection = CdmProjection(ctx) projection.source = entity_attr.entity projection.run_sequentially = True # Link for the Condition property documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#condition projection.condition = '!normalized' entity_attr.entity = CdmEntityReference(ctx, projection, False) # Link for the ArrayExpansion operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/arrayexpansion arr_expansion_operation = CdmOperationArrayExpansion(ctx) arr_expansion_operation.start_ordinal = start_ordinal arr_expansion_operation.end_ordinal = end_ordinal projection.operations.append(arr_expansion_operation) # Link for the Renameattributes operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/renameattributes # Doing an ArrayExpansion without a RenameAttributes afterwards will result in the expanded attributes being merged in the final resolved entity. # This is because ArrayExpansion does not rename the attributes it expands by default. The expanded attributes end up with the same name and gets merged. # Example: We expand A to A[1], A[2], A[3], but A[1], A[2], A[3] are still named "A". rename_attrs_operation = CdmOperationRenameAttributes(ctx) rename_attrs_operation.rename_format = rename_format projection.operations.append(rename_attrs_operation) if count_att_name: count_attribute = CdmTypeAttributeDefinition(ctx, count_att_name) count_attribute.data_type = CdmDataTypeReference(ctx, 'integer', True) # Link for the AddCountAttribute operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/addcountattribute # It is recommended, but not mandated, to be used with the ArrayExpansion operation to provide an ArrayExpansion a count attribute that # represents the total number of expanded elements. AddCountAttribute can also be used by itself. add_count_attr_operation = CdmOperationAddCountAttribute(ctx) add_count_attr_operation.count_attribute = count_attribute projection.operations.append(add_count_attr_operation)
def test_trait_to_json_data_format(self): """Test trait to data format when calculated data format should be JSON.""" cdm_attribute = CdmTypeAttributeDefinition(CdmCorpusContext(CdmCorpusDefinition(), None), 'SomeAttribute') cdm_attribute.applied_traits.append('is.dataFormat.array') cdm_attribute.applied_traits.append('means.content.text.JSON') trait_to_property_map = TraitToPropertyMap(cdm_attribute) data_format = trait_to_property_map._traits_to_data_format(False) self.assertEqual(CdmDataFormat.JSON, data_format)
def test_type_attribute_source(self): """Tests if setting the projection "source" on a type attribute triggers an error log""" corpus = CdmCorpusDefinition() error_count = 0 def callback(level: 'CdmStatusLevel', message: str): nonlocal error_count error_count += 1 corpus.set_event_callback(callback, CdmStatusLevel.ERROR) projection = CdmProjection(corpus.ctx) type_attribute = CdmTypeAttributeDefinition(corpus.ctx, 'attribute') type_attribute.projection = projection # First case, a projection without source. projection.validate() self.assertEqual(0, error_count) # Second case, a projection with a nested projection. inner_projection = CdmProjection(corpus.ctx) projection.source = CdmEntityReference(corpus.ctx, inner_projection, False) projection.validate() inner_projection.validate() self.assertEqual(0, error_count) # Third case, a projection with an explicit entity definition. inner_projection.source = CdmEntityReference( corpus.ctx, CdmEntityDefinition(corpus.ctx, 'Entity'), False) projection.validate() inner_projection.validate() self.assertEqual(1, error_count) error_count = 0 # Third case, a projection with a named reference. inner_projection.source = CdmEntityReference(corpus.ctx, 'Entity', False) projection.validate() inner_projection.validate() self.assertEqual(1, error_count)
def apply_array_expansion(entity_attr: 'CdmEntityAttributeDefinition', start_ordinal: int, end_ordinal: int, rename_format: str, count_att_name: Optional[str]): '''Applies the arrayExpansion operation to the entity attribute provided. It also takes care of applying a renameattributes operation and optionally applying a addCountAttribute operation.''' ctx = entity_attr.ctx projection = CdmProjection(ctx) projection.source = entity_attr.entity projection.run_sequentially = True # Link for the Condition property documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#condition projection.condition = '!normalized' entity_attr.entity = CdmEntityReference(ctx, projection, False) # Link for the ArrayExpansion operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/arrayexpansion arr_expansion_operation = CdmOperationArrayExpansion(ctx) arr_expansion_operation.start_ordinal = start_ordinal arr_expansion_operation.end_ordinal = end_ordinal projection.operations.append(arr_expansion_operation) # Link for the Renameattributes operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/renameattributes rename_attrs_operation = CdmOperationRenameAttributes(ctx) rename_attrs_operation.rename_format = rename_format projection.operations.append(rename_attrs_operation) if count_att_name: count_attribute = CdmTypeAttributeDefinition(ctx, count_att_name) count_attribute.data_type = CdmDataTypeReference(ctx, 'integer', True) # Link for the AddCountAttribute operation documentation. # https://docs.microsoft.com/en-us/common-data-model/sdk/projections/addcountattribute add_count_attr_operation = CdmOperationAddCountAttribute(ctx) add_count_attr_operation.count_attribute = count_attribute projection.operations.append(add_count_attr_operation)
async def test_projection_performance_on_load(self): """A test class for testing the performance of projection operations""" corpus = TestHelper.get_local_corpus(self.tests_subpath, 'TestProjectionPerformanceOnLoad') entity = await corpus.fetch_object_async('largeProjectionEntity.cdm.json/largeProjectionEntity') operation = entity.attributes[0].entity.explicit_reference.operations[0] attGroup = operation.new_attribute.explicit_reference # add a large number of attributes to the projection for i in range(10000): attGroup.members.append(CdmTypeAttributeDefinition(corpus.ctx, 'a' + str(i))) start = time.time() # reindex the entity to run through the visit function await entity.in_document._index_if_needed(ResolveOptions(entity.in_document), True) stop = time.time() self.assertLess(stop - start, 500)
def test_update_and_fetch_list_lookup(self): """Test update and fetch list lookup default value without attributeValue and displayOrder.""" corpus = CdmCorpusDefinition() cdm_attribute = CdmTypeAttributeDefinition(corpus.ctx, 'SomeAttribute') trait_to_property_map = TraitToPropertyMap(cdm_attribute) constant_values = [{'languageTag': 'en', 'displayText': 'Fax'}] trait_to_property_map.update_property_value('defaultValue', constant_values) result = trait_to_property_map.fetch_property_value('defaultValue') self.assertEqual(1, len(result)) self.assertEqual('en', result[0].get('languageTag')) self.assertEqual('Fax', result[0].get('displayText')) self.assertIsNone(result[0].get('attributeValue')) self.assertIsNone(result[0].get('displayOrder'))
def to_data(instance: CdmTypeAttributeDefinition, res_opt: ResolveOptions, options: CopyOptions) -> TypeAttribute: if instance is None: return None applied_traits = \ [trait for trait in instance.applied_traits if not trait.is_from_property] \ if instance.applied_traits else None data = TypeAttribute() data.explanation = instance.explanation data.purpose = PurposeReferencePersistence.to_data( instance.purpose, res_opt, options) if instance.purpose else None data.dataType = DataTypeReferencePersistence.to_data( instance.data_type, res_opt, options) if instance.data_type else None data.name = instance.name data.appliedTraits = copy_data_utils._array_copy_data( res_opt, applied_traits, options) data.resolutionGuidance = AttributeResolutionGuidancePersistence.to_data( instance.resolution_guidance, res_opt, options) if instance.resolution_guidance else None data.projection = ProjectionPersistence.to_data( instance.projection, res_opt, options) data.attributeContext = AttributeContextReferencePersistence.to_data( instance.attribute_context, res_opt, options) if instance.attribute_context else None is_read_only = instance._get_property('isReadOnly') if is_read_only: data.isReadOnly = is_read_only is_nullable = instance._get_property('isNullable') if is_nullable: data.isNullable = is_nullable data.sourceName = instance._get_property('sourceName') source_ordering = instance._get_property('sourceOrdering') if source_ordering: data.sourceOrdering = source_ordering data.displayName = instance._get_property('displayName') data.description = instance._get_property('description') value_constrained_to_list = instance._get_property( 'valueConstrainedToList') if value_constrained_to_list: data.valueConstrainedToList = value_constrained_to_list is_primary_key = instance._get_property('isPrimaryKey') if is_primary_key: data.isPrimaryKey = is_primary_key data.maximumLength = instance._get_property('maximumLength') data.maximumValue = instance._get_property('maximumValue') data.minimumValue = instance._get_property('minimumValue') data_format = instance._get_property('dataFormat') if data_format != CdmDataFormat.UNKNOWN: data.dataFormat = data_format.value default_value = instance._get_property('defaultValue') if default_value: data.defaultValue = default_value return data
def _build_fake_tree(self, corpus: 'CdmCorpusDefinition') -> 'ProjectionContext': proj_dir = ProjectionDirective(ResolveOptions(), None) pc = ProjectionContext(proj_dir, None) p1 = ProjectionAttributeState(corpus.ctx) p1._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '1'), '1', None) p2 = ProjectionAttributeState(corpus.ctx) p2._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '2'), '2', None) p4 = ProjectionAttributeState(corpus.ctx) p4._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '4'), '4', None) p5 = ProjectionAttributeState(corpus.ctx) p5._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '5'), '5', None) p6 = ProjectionAttributeState(corpus.ctx) p6._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '6'), '6', None) p7 = ProjectionAttributeState(corpus.ctx) p7._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '7'), '7', None) p8 = ProjectionAttributeState(corpus.ctx) p8._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '8'), '8', None) p9 = ProjectionAttributeState(corpus.ctx) p9._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '9'), '9', None) p10 = ProjectionAttributeState(corpus.ctx) p10._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '10'), '10', None) p11 = ProjectionAttributeState(corpus.ctx) p11._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '11'), '11', None) p12 = ProjectionAttributeState(corpus.ctx) p12._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '12'), '12', None) p13 = ProjectionAttributeState(corpus.ctx) p13._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '13'), '13', None) p14 = ProjectionAttributeState(corpus.ctx) p14._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '14'), '14', None) p15 = ProjectionAttributeState(corpus.ctx) p15._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '15'), '15', None) p16 = ProjectionAttributeState(corpus.ctx) p16._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '16'), '16', None) p17 = ProjectionAttributeState(corpus.ctx) p17._current_resolved_attribute = ResolvedAttribute( proj_dir._res_opt, CdmTypeAttributeDefinition(corpus.ctx, '17'), '17', None) p1._previous_state_list = [] p2._previous_state_list = [] p4._previous_state_list = [] p5._previous_state_list = [] p6._previous_state_list = [] p7._previous_state_list = [] p8._previous_state_list = [] p9._previous_state_list = [] p10._previous_state_list = [] p11._previous_state_list = [] p12._previous_state_list = [] p13._previous_state_list = [] p14._previous_state_list = [] p15._previous_state_list = [] p16._previous_state_list = [] p17._previous_state_list = [] p11._previous_state_list.append(p7) p7._previous_state_list.append(p2) p2._previous_state_list.append(p1) p12._previous_state_list.append(p8) p8._previous_state_list.append(p1) p13._previous_state_list.append(p9) p9._previous_state_list.append(p4) p9._previous_state_list.append(p5) p13._previous_state_list.append(p10) p10._previous_state_list.append(p6) p14._previous_state_list.append(p16) p16._previous_state_list.append(p1) p15._previous_state_list.append(p7) p17._previous_state_list.append(p8) pc._current_attribute_state_set._add(p11) pc._current_attribute_state_set._add(p12) pc._current_attribute_state_set._add(p13) pc._current_attribute_state_set._add(p14) pc._current_attribute_state_set._add(p15) pc._current_attribute_state_set._add(p17) return pc