<commit_before>﻿using Serenity;
using Serenity.Data;
using Serenity.Data.Mapping;
using Serenity.Reflection;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
#if COREFX
using System.Reflection;
#endif

namespace Serenity.Services
{
    public class MasterDetailRelationBehavior : BaseSaveDeleteBehavior, 
        IImplicitBehavior, IRetrieveBehavior, IListBehavior, IFieldBehavior
    {
        public Field Target { get; set; }

        private MasterDetailRelationAttribute attr;
        private Func<IList> rowListFactory;
        private Func<Row> rowFactory;
        private Type rowType;
        private Field foreignKeyField;
        private BaseCriteria foreignKeyCriteria;
        private Field filterField;
        private Field masterKeyField;
        private object filterValue;
        private BaseCriteria filterCriteria;
        private BaseCriteria queryCriteria;
        private HashSet<string> includeColumns;

        public bool ActivateFor(Row row)
        {
            if (ReferenceEquals(null, Target))
                return false;

            attr = Target.GetAttribute<MasterDetailRelationAttribute>();
            if (attr == null)
                return false;

            var rowListType = Target.ValueType;
            if (!rowListType.IsGenericType ||
                rowListType.GetGenericTypeDefinition() != typeof(List<>))
            {
                throw new ArgumentException(String.Format("Field '{0}' in row type '{1}' has a MasterDetailRelationAttribute " +
                    "but its property type is not a generic List (e.g. List<Row>)!",
                    Target.PropertyName ?? Target.Name, row.GetType().FullName));
            }

            rowType = rowListType.GetGenericArguments()[0];
            if (rowType.IsAbstract ||
                !typeof(Row).IsAssignableFrom(rowType))
            {
                throw new ArgumentException(String.Format(
                    "Field '{0}' in row type '{1}' has a MasterDetailRelationAttribute " +
                    "but its property type is not a generic list of rows (e.g. List<Row>)!",
                        Target.PropertyName ?? Target.Name, row.GetType().FullName));
            }

            rowListFactory = FastReflection.DelegateForConstructor<IList>(rowListType);
            rowFactory = FastReflection.DelegateForConstructor<Row>(rowType);

            //listHandlerFactory = FastReflection.DelegateForConstructor<IListRequestProcessor>(
            //    typeof(ListRequestHandler<>).MakeGenericType(rowType));

            //saveHandlerFactory = FastReflection.DelegateForConstructor<ISaveRequestProcessor>(
            //    typeof(SaveRequestHandler<>).MakeGenericType(rowType));

            //saveRequestFactory = FastReflection.DelegateForConstructor<ISaveRequest>(
            //    typeof(SaveRequest<>).MakeGenericType(rowType));

            //deleteHandlerFactory = FastReflection.DelegateForConstructor<IDeleteRequestProcessor>(
            //    typeof(DeleteRequestHandler<>).MakeGenericType(rowType));

            if (attr.MasterKeyField != null)
            {
                // Use field from AltIdField
                masterKeyField = row.FindFieldByPropertyName(attr.MasterKeyField) ??
                    row.FindField(attr.MasterKeyField);
                if (ReferenceEquals(masterKeyField, null))
                    throw new ArgumentException(String.Format("Field '{0}' doesn't exist in row of type '{1}'." +
                        "This field is specified for a master detail relation in field '{2}'.",
                        attr.MasterKeyField, row.GetType().FullName,
                        Target.PropertyName ?? Target.Name));
            }
            else
            {
                // Default behaviour: use id field
                masterKeyField = (Field)((row as IIdRow).IdField);
            }

            var detailRow = rowFactory();
            foreignKeyField = detailRow.FindFieldByPropertyName(attr.ForeignKey) ??
                detailRow.FindField(attr.ForeignKey);

            if (ReferenceEquals(foreignKeyField, null))
                throw new ArgumentException(String.Format("Field '{0}' doesn't exist in row of type '{1}'." +
                    "This field is specified for a master detail relation in field '{2}' of row type '{3}'.",
                    attr.ForeignKey, detailRow.GetType().FullName,
                    Target.PropertyName ?? Target.Name, row.GetType().FullName));

            this.foreignKeyCriteria = new Criteria(foreignKeyField.PropertyName ?? foreignKeyField.Name);

            if (!string.IsNullOrEmpty(attr.FilterField))<commit_msg>remove commented lines<commit_after>﻿using Serenity;
using Serenity.Data;
using Serenity.Data.Mapping;
using Serenity.Reflection;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
#if COREFX
using System.Reflection;
#endif

namespace Serenity.Services
{
    public class MasterDetailRelationBehavior : BaseSaveDeleteBehavior, 
        IImplicitBehavior, IRetrieveBehavior, IListBehavior, IFieldBehavior
    {
        public Field Target { get; set; }

        private MasterDetailRelationAttribute attr;
        private Func<IList> rowListFactory;
        private Func<Row> rowFactory;
        private Type rowType;
        private Field foreignKeyField;
        private BaseCriteria foreignKeyCriteria;
        private Field filterField;
        private Field masterKeyField;
        private object filterValue;
        private BaseCriteria filterCriteria;
        private BaseCriteria queryCriteria;
        private HashSet<string> includeColumns;

        public bool ActivateFor(Row row)
        {
            if (ReferenceEquals(null, Target))
                return false;

            attr = Target.GetAttribute<MasterDetailRelationAttribute>();
            if (attr == null)
                return false;

            var rowListType = Target.ValueType;
            if (!rowListType.IsGenericType ||
                rowListType.GetGenericTypeDefinition() != typeof(List<>))
            {
                throw new ArgumentException(String.Format("Field '{0}' in row type '{1}' has a MasterDetailRelationAttribute " +
                    "but its property type is not a generic List (e.g. List<Row>)!",
                    Target.PropertyName ?? Target.Name, row.GetType().FullName));
            }

            rowType = rowListType.GetGenericArguments()[0];
            if (rowType.IsAbstract ||
                !typeof(Row).IsAssignableFrom(rowType))
            {
                throw new ArgumentException(String.Format(
                    "Field '{0}' in row type '{1}' has a MasterDetailRelationAttribute " +
                    "but its property type is not a generic list of rows (e.g. List<Row>)!",
                        Target.PropertyName ?? Target.Name, row.GetType().FullName));
            }

            rowListFactory = FastReflection.DelegateForConstructor<IList>(rowListType);
            rowFactory = FastReflection.DelegateForConstructor<Row>(rowType);

            if (attr.MasterKeyField != null)
            {
                // Use field from AltIdField
                masterKeyField = row.FindFieldByPropertyName(attr.MasterKeyField) ??
                    row.FindField(attr.MasterKeyField);
                if (ReferenceEquals(masterKeyField, null))
                    throw new ArgumentException(String.Format("Field '{0}' doesn't exist in row of type '{1}'." +
                        "This field is specified for a master detail relation in field '{2}'.",
                        attr.MasterKeyField, row.GetType().FullName,
                        Target.PropertyName ?? Target.Name));
            }
            else
            {
                // Default behaviour: use id field
                masterKeyField = (Field)((row as IIdRow).IdField);
            }

            var detailRow = rowFactory();
            foreignKeyField = detailRow.FindFieldByPropertyName(attr.ForeignKey) ??
                detailRow.FindField(attr.ForeignKey);

            if (ReferenceEquals(foreignKeyField, null))
                throw new ArgumentException(String.Format("Field '{0}' doesn't exist in row of type '{1}'." +
                    "This field is specified for a master detail relation in field '{2}' of row type '{3}'.",
                    attr.ForeignKey, detailRow.GetType().FullName,
                    Target.PropertyName ?? Target.Name, row.GetType().FullName));

            this.foreignKeyCriteria = new Criteria(foreignKeyField.PropertyName ?? foreignKeyField.Name);

            if (!string.IsNullOrEmpty(attr.FilterField))
{'fraction_non_alphanumeric': 0.09145854715474969, 'fraction_numerical': 0.0027369141293191925, 'mean_word_length': 2.1995622035753373, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3233820', 'n_tokens_mistral': 2146, 'n_tokens_neox': 2057, 'n_words': 525}