public IJsonSearchFilterData GetJsonFilterData()
 {
     return(new EqualJsonFilterData()
     {
         Field = SearchHelpers.GetParameterName(_filterType),
         Value = _value.ToString()
     });
 }
 public RangeJsonFilter(LiveSearchFilterType filterType, T from, T to, bool include_lower = true, bool include_upper = true)
 {
     _rangeJsonFilterData = new RangeJsonFilterData()
     {
         Field        = SearchHelpers.GetParameterName((SearchFieldType)filterType),
         From         = from.ToString(),
         To           = to.ToString(),
         IncludeLower = include_lower == false ? false : default(bool?),
         IncludeUpper = include_upper == false ? false : default(bool?),
     };
 }
Exemplo n.º 3
0
        public static async Task <LiveSearchResponse> GetLiveSearchAsync(
            NiconicoContext context,
            string q,
            int offset,
            int limit,
            SearchTargetType targets    = SearchTargetType.All,
            LiveSearchFieldType fields  = LiveSearchFieldType.ContentId,
            LiveSearchSortType sortType = LiveSearchSortType.StartTime | LiveSearchSortType.SortDecsending,
            ISearchFilter searchFilter  = null
            )
        {
            if (string.IsNullOrWhiteSpace(q))
            {
                throw new ArgumentException("q value must contains any character.");
            }
            if (offset < 0 || offset >= SearchConstants.MaxSearchOffset)
            {
                throw new ArgumentException("offset value out of bounds. (0 <= offset <= 1600)");
            }

            if (limit < 0 || limit >= SearchConstants.MaxSearchLimit)
            {
                throw new ArgumentException("limit value out of bounds. (0 <= limit <= 100)");
            }

            var dict = new Dictionary <string, string>()
            {
                { SearchConstants.QuaryParameter, q },
                { SearchConstants.OffsetParameter, offset.ToString() },
                { SearchConstants.LimitParameter, limit.ToString() },
                { SearchConstants.TargetsParameter, SearchHelpers.ToQueryString(targets) },
            };

            if (context.AdditionalUserAgent != null)
            {
                dict.Add(SearchConstants.ContextParameter, context.AdditionalUserAgent);
            }

            if (fields != LiveSearchFieldType.None)
            {
                dict.Add(SearchConstants.FieldsParameter, SearchHelpers.ToQueryString(fields));
            }

            if (sortType != LiveSearchSortType.None)
            {
                dict.Add(SearchConstants.SortParameter, SearchHelpers.ToQueryString(sortType));
            }

            if (searchFilter != null)
            {
                var filters = searchFilter.GetFilterKeyValues();
                foreach (var f in filters)
                {
                    dict.Add(f.Key, f.Value);
                }
            }

            var json = await context.GetStringAsync(SearchConstants.LiveSearchEndPoint, dict);

            return(JsonSerializerExtensions.Load <LiveSearchResponse>(json));
        }
Exemplo n.º 4
0
 public IEnumerable <KeyValuePair <string, string> > GetFilterKeyValues()
 {
     return(_values.Select((x, i) => new KeyValuePair <string, string>($"filters[{SearchHelpers.GetParameterName(_filterType)}][{i}]", x.ToString())));
 }
Exemplo n.º 5
0
 public IEnumerable <KeyValuePair <string, string> > GetFilterKeyValues()
 {
     return(new[] { new KeyValuePair <string, string>($"filters[{SearchHelpers.GetParameterName(_filterType)}][{SearchHelpers.ToQueryString(_condition)}]", _value.ToString()) });
 }
Exemplo n.º 6
0
        private List <KeyValuePair <string, string> > ConvertToKeyValues(BinaryExpression operation)
        {
            // see@: https://site.nicovideo.jp/search-api-docs/search.html

            // フィルタとして指定できるパラメータにfitlersとjsonFiltersがあり
            // jsonFiltersの方でのみNOTやORの条件検索ができます。ただしクライアント側にしろAPI側にしろ処理が重い。
            // filtersは常にANDのみで除外条件指定もできませんが軽いです。

            // 故に、BinaryExpressionとして OR か NOT が含まれる場合は常にJsonFilterとして構築し
            // 単一の比較、または複数の比較をAndのみで繋げている場合はfiltersとして構築します

            // 事前にBinaryExpressionの左・右辺式を末端まで調べて、OR/NOT が含まれていないかをチェックする
            bool isNeedJsonFilter = false;
            Stack <BinaryExpression> expressions = new Stack <BinaryExpression>();

            expressions.Push(operation);
            while (expressions.Count > 0)
            {
                var exp = expressions.Pop();
                if (exp.Left is BinaryExpression lbe)
                {
                    if (lbe.NodeType == ExpressionType.OrElse || lbe.NodeType == ExpressionType.NotEqual)
                    {
                        isNeedJsonFilter = true;
                        break;
                    }

                    expressions.Push(lbe);
                }
                if (exp.Right is BinaryExpression rbe)
                {
                    if (rbe.NodeType == ExpressionType.OrElse || rbe.NodeType == ExpressionType.NotEqual)
                    {
                        isNeedJsonFilter = true;
                        break;
                    }

                    expressions.Push(rbe);
                }
            }

            expressions.Clear();

            if (!isNeedJsonFilter)
            {
                // filtersで処理する、単一比較かAndで結ばれた複数の比較
                // && 以外の比較演算子の式をcompareExpListに対してフラット化
                var compareExpList = new List <BinaryExpression>();
                expressions.Push(operation);
                while (expressions.Count > 0)
                {
                    var be = expressions.Pop();

                    if (be.NodeType == ExpressionType.Equal ||
                        be.NodeType == ExpressionType.GreaterThan ||
                        be.NodeType == ExpressionType.GreaterThanOrEqual ||
                        be.NodeType == ExpressionType.LessThan ||
                        be.NodeType == ExpressionType.LessThanOrEqual
                        )
                    {
                        compareExpList.Add(be);
                    }
                    else if (be.NodeType == ExpressionType.AndAlso)
                    {
                        expressions.Push((BinaryExpression)be.Left);
                        expressions.Push((BinaryExpression)be.Right);
                    }
                    else
                    {
                        throw new ArgumentException("対応してない演算子が使われています : " + be.NodeType);
                    }
                }

                List <KeyValuePair <string, string> >  sb = new List <KeyValuePair <string, string> >();
                Dictionary <LiveSearchFilterType, int> fieldTypeIndexMap = new Dictionary <LiveSearchFilterType, int>();
                foreach (var be in compareExpList)
                {
                    bool             isNeedInverseCompereOperation = false;
                    MemberExpression memberExpression = null;
                    Expression       valueExpression  = null;
                    if (be.Left is MemberExpression member1 &&
                        member1.Member.DeclaringType == typeof(SearchFilterField)
                        )
                    {
                        memberExpression = member1;
                        valueExpression  = be.Right;
                    }

                    if (be.Right is MemberExpression member2 &&
                        member2.Member.DeclaringType == typeof(SearchFilterField)
                        )
                    {
                        memberExpression = member2;
                        valueExpression  = be.Left;
                        isNeedInverseCompereOperation = true;
                    }

                    if (memberExpression == null)
                    {
                        throw new ArgumentException();
                    }

                    var conditionType = be.NodeType switch
                    {
                        ExpressionType.Equal => SearchFilterCompareCondition.EQ,
                        ExpressionType.GreaterThan => isNeedInverseCompereOperation ? SearchFilterCompareCondition.LT : SearchFilterCompareCondition.GT,
                        ExpressionType.GreaterThanOrEqual => isNeedInverseCompereOperation ? SearchFilterCompareCondition.LTE : SearchFilterCompareCondition.GTE,
                        ExpressionType.LessThan => isNeedInverseCompereOperation ? SearchFilterCompareCondition.GT : SearchFilterCompareCondition.LT,
                        ExpressionType.LessThanOrEqual => isNeedInverseCompereOperation ? SearchFilterCompareCondition.GTE : SearchFilterCompareCondition.LTE,
                        _ => throw new ArgumentException("対応してない演算子が使われています : " + be.NodeType),
                    };

                    var    fieldType = (LiveSearchFilterType)Enum.Parse(typeof(LiveSearchFilterType), memberExpression.Member.Name);
                    object value     = Expression.Lambda(valueExpression).Compile().DynamicInvoke();
                    var    valueText = value is DateTime time?time.ToString("o") : value.ToString();

                    if (conditionType == SearchFilterCompareCondition.EQ)
                    {
                        int count = fieldTypeIndexMap.TryGetValue(fieldType, out count) ? count : 0;
                        sb.Add(new KeyValuePair <string, string>($"filters[{SearchHelpers.ToQueryString((LiveSearchFieldType)fieldType)}][{count}]", valueText));
                        count += 1;
                        fieldTypeIndexMap[fieldType] = count;
                    }
                    else
                    {
                        sb.Add(new KeyValuePair <string, string>($"filters[{SearchHelpers.ToQueryString((LiveSearchFieldType)fieldType)}][{SearchHelpers.ToQueryString(conditionType)}]", valueText));
                    }
                }

                return(sb);
            }
            else
            {
                // jsonFilterで処理する
                // 論理演算の最適化は行わずExpressionTreeを愚直にJsonFilterのデータに変換する
                throw new NotImplementedException("OR/NOT演算は未実装です");
            }
        }