Exemplo n.º 1
0
        public static GroupBy Parse(string query, out int code)
        {
            code = 400;
            if (string.IsNullOrEmpty(query))
            {
                return(null);
            }

            var stor   = Storage.Instance;
            var parsed = HttpUtility.ParseQueryString(query);
            var ret    = new GroupBy();

            for (int i = 0; i < parsed.Count; ++i)
            {
                var key    = parsed.GetKey(i);
                var values = parsed.GetValues(i);
                if (values.Length > 1)
                {
                    return(null);           // invalid query
                }
                var value = values[0] ?? string.Empty;
                if (value.Length == 0)
                {
                    return(null);
                }

                switch (key)
                {
                case "query_id": break;

                case "order":
                    if (!int.TryParse(value, out ret.Order))
                    {
                        return(null);
                    }
                    if (ret.Order != -1 && ret.Order != 1)
                    {
                        return(null);
                    }
                    break;

                case "keys":
                    ret.keys        = value.Split(',');
                    ret.byInterests = value == "interests";
                    ret.keySelector = ret.byInterests ? a => 0 : Account.CreateKeySelector(ret.keys);
                    if (ret.keySelector == null)
                    {
                        return(null);
                    }
                    break;

                case "limit":
                    if (!int.TryParse(value, out ret.Limit) || ret.Limit <= 0)
                    {
                        return(null);
                    }
                    break;

                case "sex":
                    if (value != "m" && value != "f")
                    {
                        goto notfound;
                    }
                    ret.predicates.Add(a => a.MatchBySex(value[0]));
                    PickIndex(ret, stor.GetSexIndex(value[0]));
                    break;

                case "email":
                    var dom = stor.emailMap.FindDomain(value);
                    ret.predicates.Add(a => a.MatchByEmailDomain(dom)); break;

                case "status":
                    var istat = Account.FindStatus(value);
                    if (istat < 0)
                    {
                        goto notfound;
                    }
                    ret.predicates.Add(a => a.MatchByStatus(istat));
                    PickIndex(ret, stor.GetStatusIndex((byte)istat));
                    break;

                case "fname":
                    var fid = stor.firstNamesMap.Find(value);
                    ret.emptyQuery = fid == -1;
                    ret.predicates.Add(a => a.MatchByFName((byte)fid)); break;

                case "sname":
                    var sid = stor.surnamesMap.Find(value);
                    ret.emptyQuery = sid == -1;
                    ret.predicates.Add(a => a.MatchBySName((ushort)sid)); break;

                case "phone":
                    ret.predicates.Add(a => a.MatchByPhone(value)); break;

                case "country":
                    var countryId = stor.countriesMap.Find(value);
                    ret.predicates.Add(a => a.MatchByCountry((byte)countryId));
                    ret.emptyQuery = countryId == -1;
                    PickIndex(ret, stor.GetCountryIndex((byte)countryId));
                    break;

                case "city":
                    var cityId = stor.citiesMap.Find(value);
                    ret.predicates.Add(a => a.MatchByCity((ushort)cityId));
                    ret.emptyQuery = cityId == -1;
                    PickIndex(ret, stor.GetCityIndex((ushort)cityId));
                    break;

                case "birth":
                    if (!int.TryParse(value, out var yr))
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchBirthByYear(yr));
                    PickIndex(ret, stor.GetAgeIndex((byte)(yr - 1949)));
                    break;

                case "interests":
                    var match = new Interests(values);
                    ret.predicates.Add(a => a.MatchInterestsAny(match));
                    PickIndex(ret, stor.GetInterestsIndex(match.GetInterestIds()));
                    break;

                case "likes":
                    if (!int.TryParse(value, out var id))
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchByLike(id));
                    PickIndex(ret, stor.GetLikedByIndex(new[] { id }));
                    break;

                case "joined":
                    if (!int.TryParse(value, out var j))
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchJoinedByYear(j));
                    PickIndex(ret, stor.GetJoinedIndex((byte)(j - 2010)));
                    break;

                default:
                    return(null); // unknown query param
                }
            }

            if (ret.keys.Length == 0)
            {
                return(null);
            }
            if (ret.Limit == 0)
            {
                return(null);
            }

            code = 200;
            return(ret);

notfound:
            code = 404;
            return(null);

            void PickIndex(GroupBy target, IQueryIndex newIndex, bool resetIndex = false)
            {
                if (target.selectedIndex == null || newIndex.Selectivity < target.selectedIndex.Selectivity)
                {
                    // if 'contains' index is picked - reset removed predicate index.
                    // we cannot remove predicate in this case, since index does not completely match criteria, needs additional filtering
                    target.selectedIndex  = newIndex;
                    target.indexPredicate = resetIndex ? -1 : target.predicates.Count - 1;
                }
            }
        }
Exemplo n.º 2
0
 public bool HasAnyIntersectingInterestsWith(Interests other)
 {
     return((other.bitmap1 & this.bitmap1) != 0 || (other.bitmap2 & this.bitmap2) != 0);
 }
Exemplo n.º 3
0
 public uint CountIntersectingInterestsWith(Interests other)
 {
     return((uint)(NumberOfSetBits64(this.bitmap1 & other.bitmap1) + NumberOfSetBits64(this.bitmap2 & other.bitmap2)));
 }
Exemplo n.º 4
0
 public bool HasAllIntersectingInterestsWith(Interests other)
 {
     return
         (((other.bitmap1 & this.bitmap1) == other.bitmap1) &&
          ((other.bitmap2 & this.bitmap2) == other.bitmap2));
 }
Exemplo n.º 5
0
        public static Query Parse(string query)
        {
            if (string.IsNullOrEmpty(query))
            {
                return(null);
            }

            var stor   = Storage.Instance;
            var parsed = HttpUtility.ParseQueryString(query);

            var ret = new Query();

            for (int i = 0; i < parsed.Count; ++i)
            {
                var key    = parsed.GetKey(i);
                var values = parsed.GetValues(i);
                if (values.Length > 1)
                {
                    return(null);           // invalid query
                }
                var value = values[0] ?? string.Empty;
                if (value.Length == 0)
                {
                    return(null);
                }

                switch (key)
                {
                case "query_id":
                    break;

                case "limit":
                    if (!int.TryParse(value, out ret.Limit) || ret.Limit <= 0)
                    {
                        return(null);
                    }
                    break;

                case "sex_eq":
                    if (value != "m" && value != "f")
                    {
                        return(null);
                    }
                    ret.converters.Add((j, a) => j.Add("sex", a.sex == 'm' ? "m" : "f"));
                    ret.predicates.Add(a => a.MatchBySex(value[0]));
                    PickIndex(ret, stor.GetSexIndex(value[0]));
                    break;

                case "email_domain": // dont add email to converters, always included
                    var dom = stor.emailMap.FindDomain(value);
                    ret.predicates.Add(a => a.MatchByEmailDomain(dom)); break;

                case "email_lt":
                    ret.predicates.Add(a => a.EmailLessThan(value)); break;

                case "email_gt":
                    ret.predicates.Add(a => a.EmailGreaterThan(value)); break;

                case "status_eq":
                    var istat = (byte)(value[0] == 'с' ? 2 : value[0] == 'в' ? 1 : 0);
                    ret.converters.Add((j, a) => j.Add("status", a.status));
                    ret.predicates.Add(a => a.MatchByStatus(istat));
                    PickIndex(ret, stor.GetStatusIndex(istat));
                    break;

                case "status_neq":
                    var istat2    = (byte)(value[0] == 'с' ? 2 : value[0] == 'в' ? 1 : 0);
                    var istat2arr = (value[0] == 'с' ? new byte[] { 0, 1 } : value[0] == 'в' ? new byte[] { 0, 2 } : new byte[] { 1, 2 });
                    ret.converters.Add((j, a) => j.Add("status", a.status));
                    ret.predicates.Add(a => a.MatchByStatusNot(istat2));
                    PickIndex(ret, stor.GetStatusIndex(istat2arr));
                    break;

                case "fname_eq":
                    var fid = stor.firstNamesMap.Find(value);
                    ret.converters.Add((j, a) => j.Add("fname", a.fname));
                    ret.predicates.Add(a => a.MatchByFName((byte)fid)); break;

                case "fname_any":
                    var fnameMatch = value.Split(',').Select(x => (byte)stor.firstNamesMap.Find(x)).ToArray();
                    ret.converters.Add((j, a) => j.Add("fname", a.fname));
                    ret.predicates.Add(a => a.MatchByFName(fnameMatch)); break;

                case "fname_null":
                    bool z = value == "0";
                    if (!z && value != "1")
                    {
                        return(null);
                    }
                    if (z)
                    {
                        ret.converters.Add((j, a) => j.Add("fname", a.fname));
                    }
                    ret.predicates.Add(a => a.MatchHasFName(z)); break;

                case "sname_eq":
                    var sid = stor.surnamesMap.Find(value);
                    ret.converters.Add((j, a) => j.Add("sname", a.sname));
                    ret.predicates.Add(a => a.MatchBySName((ushort)sid)); break;

                case "sname_starts":
                    ret.converters.Add((j, a) => j.Add("sname", a.sname));
                    ret.predicates.Add(a => a.MatchSNameStarts(value)); break;

                case "sname_null":
                    if (value != "0" && value != "1")
                    {
                        return(null);
                    }
                    if (value == "0")
                    {
                        ret.converters.Add((j, a) => j.Add("sname", a.sname));
                    }
                    ret.predicates.Add(a => a.MatchHasSName(value == "0")); break;

                case "phone_code":
                    if (!ushort.TryParse(value, out var c))
                    {
                        return(null);
                    }
                    ret.converters.Add((j, a) => j.Add("phone", a.phone));
                    ret.predicates.Add(a => a.MatchByPhoneCode(c));
                    PickIndex(ret, stor.GetPhoneCodeIndex(c));
                    break;

                case "phone_null":
                    if (value != "0" && value != "1")
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchHasPhone(value == "0"));
                    if (value == "0")
                    {
                        ret.converters.Add((j, a) => j.Add("phone", a.phone));
                    }
                    else
                    {
                        PickIndex(ret, stor.GetPhoneCodeIndex(0));
                    }
                    break;

                case "country_eq":
                    var countryId = stor.countriesMap.Find(value);
                    ret.converters.Add((j, a) => j.Add("country", a.country));
                    ret.predicates.Add(a => a.MatchByCountry((byte)countryId));
                    ret.emptyQuery = countryId == -1;
                    PickIndex(ret, stor.GetCountryIndex((byte)countryId));
                    break;

                case "country_null":
                    if (value != "0" && value != "1")
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchHasCountry(value == "0"));
                    if (value == "0")
                    {
                        ret.converters.Add((j, a) => j.Add("country", a.country));
                    }
                    else
                    {
                        PickIndex(ret, stor.GetCountryIndex(0));
                    }
                    break;

                case "city_eq":
                    var cityId = stor.citiesMap.Find(value);
                    ret.converters.Add((j, a) => j.Add("city", a.city));
                    ret.predicates.Add(a => a.MatchByCity((ushort)cityId));
                    ret.emptyQuery = cityId == -1;
                    PickIndex(ret, stor.GetCityIndex((ushort)cityId));
                    break;

                case "city_any":
                    var lookupCity = value.Split(',');
                    ret.converters.Add((j, a) => j.Add("city", a.city));
                    var cityIds = new List <ushort>();
                    foreach (var city in lookupCity)
                    {
                        cityId = stor.citiesMap.Find(city);
                        if (cityId != -1)
                        {
                            cityIds.Add((ushort)cityId);
                        }
                    }
                    ret.predicates.Add(a => a.MatchByCity(cityIds.ToArray()));
                    ret.emptyQuery = cityIds.Count == 0;
                    PickIndex(ret, stor.GetCityIndex(cityIds.ToArray()));
                    break;

                case "city_null":
                    if (value != "0" && value != "1")
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchHasCity(value == "0"));
                    if (value == "0")
                    {
                        ret.converters.Add((j, a) => j.Add("city", a.city));
                    }
                    else
                    {
                        PickIndex(ret, stor.GetCityIndex(0));
                    }
                    break;

                case "birth_lt":
                    if (!int.TryParse(value, out var ts1))
                    {
                        return(null);
                    }
                    ret.converters.Add((j, a) => j.Add("birth", a.birth));
                    ret.predicates.Add(a => a.BirthLessThan(ts1)); break;

                case "birth_gt":
                    if (!int.TryParse(value, out var ts2))
                    {
                        return(null);
                    }
                    ret.converters.Add((j, a) => j.Add("birth", a.birth));
                    ret.predicates.Add(a => a.BirthGreaterThan(ts2)); break;

                case "birth_year":
                    if (!int.TryParse(value, out var yr))
                    {
                        return(null);
                    }
                    ret.converters.Add((j, a) => j.Add("birth", a.birth));
                    ret.predicates.Add(a => a.MatchBirthByYear(yr));
                    PickIndex(ret, stor.GetAgeIndex((byte)(yr - 1949)));
                    break;

                case "interests_contains":
                    var otherc = new Interests(value.Split(','));
                    ret.predicates.Add(a => a.MatchInterestsContains(otherc));
                    PickIndex(ret, stor.GetInterestsIndex(otherc.GetInterestIds()), true);
                    break;

                case "interests_any":
                    var othera = new Interests(value.Split(','));
                    ret.predicates.Add(a => a.MatchInterestsAny(othera));
                    PickIndex(ret, stor.GetInterestsIndex(othera.GetInterestIds()));
                    break;

                case "likes_contains":
                    var hs = value.Split(',').Select(x => int.TryParse(x, out var id) ? id : -1).ToHashSet();
                    if (hs.Contains(-1))
                    {
                        return(null);
                    }
                    ret.predicates.Add(a => a.MatchByLikes(hs));
                    PickIndex(ret, stor.GetLikedByIndex(hs), true);
                    break;

                case "premium_now":
                    ret.converters.Add((j, a) => j.Add("premium", new JObject {
                        ["start"] = a.premium.start, ["finish"] = a.premium.finish
                    }));
                    ret.predicates.Add(a => a.MatchIsPremium(stor.timestamp)); break;

                case "premium_null":
                    if (value != "0" && value != "1")
                    {
                        return(null);
                    }
                    if (value == "0")
                    {
                        ret.converters.Add((j, a) => j.Add("premium", new JObject {
                            ["start"] = a.premium.start, ["finish"] = a.premium.finish
                        }));
                    }
                    ret.predicates.Add(a => a.MatchHasPremium(value == "0")); break;

                default: return(null); // unknown query param
                }
            }

            if (ret.Limit == 0)
            {
                return(null);          // no mandatory limit parameter was present
            }
            return(ret);

            void PickIndex(Query target, IQueryIndex newIndex, bool resetIndex = false)
            {
                if (target.selectedIndex == null || newIndex.Selectivity < target.selectedIndex.Selectivity)
                {
                    // if 'contains' index is picked - reset removed predicate index.
                    // we cannot remove predicate in this case, since index does not completely match criteria, needs additional filtering
                    target.selectedIndex  = newIndex;
                    target.indexPredicate = resetIndex ? -1 : target.predicates.Count - 1;
                }
            }
        }