Exemple #1
0
        public override async Task <ICollection <FilterValue> > GetAvailableValuesAsync(IEnumerable <Guid> necessaryMIATypeIds, IFilter selectAttributeFilter, IFilter filter)
        {
            IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory;

            if (cd == null)
            {
                throw new NotConnectedException("The MediaLibrary is not connected");
            }

            bool showVirtual = VirtualMediaHelper.ShowVirtualMedia(necessaryMIATypeIds);

            IFilter emptyFilter      = new EmptyFilter(AudioAlbumAspect.ATTR_COMPILATION);
            IFilter compiledFilter   = new RelationalFilter(AudioAlbumAspect.ATTR_COMPILATION, RelationalOperator.EQ, true);
            IFilter uncompiledFilter = new RelationalFilter(AudioAlbumAspect.ATTR_COMPILATION, RelationalOperator.EQ, false);
            var     taskEmpty        = cd.CountMediaItemsAsync(necessaryMIATypeIds, emptyFilter, true, showVirtual);
            var     taskCompiled     = cd.CountMediaItemsAsync(necessaryMIATypeIds, compiledFilter, true, showVirtual);
            var     taskUncompiled   = cd.CountMediaItemsAsync(necessaryMIATypeIds, uncompiledFilter, true, showVirtual);

            var counts = await Task.WhenAll(taskEmpty, taskCompiled, taskUncompiled);

            return(new List <FilterValue>(new FilterValue[]
            {
                new FilterValue(Consts.RES_VALUE_EMPTY_TITLE, emptyFilter, null, counts[0], this),
                new FilterValue(Consts.RES_COMPILATION_FILTER_COMPILED, compiledFilter, null, counts[1], this),
                new FilterValue(Consts.RES_COMPILATION_FILTER_UNCOMPILED, uncompiledFilter, null, counts[2], this),
            }.Where(fv => !fv.NumItems.HasValue || fv.NumItems.Value > 0)));
        }
Exemple #2
0
        protected override async Task <MediaItemQuery> CreateQueryAsync()
        {
            Guid?   userProfile = CurrentUserProfile?.ProfileId;
            IFilter filter;

            if (userProfile.HasValue)
            {
                filter = await AppendUserFilterAsync(
                    new RelationalUserDataFilter(userProfile.Value, UserDataKeysKnown.KEY_PLAY_PERCENTAGE, RelationalOperator.EQ, UserDataKeysKnown.GetSortablePlayPercentageString(0), true), _necessaryMias);
            }
            else
            {
                filter = new RelationalFilter(MediaAspect.ATTR_PLAYCOUNT, RelationalOperator.EQ, 0);
            }

            IFilter navigationFilter = GetNavigationFilter(_navigationInitializerType);

            if (navigationFilter != null)
            {
                filter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, filter, navigationFilter);
            }

            return(new MediaItemQuery(_necessaryMias, _optionalMias, filter)
            {
                SortInformation = new List <ISortInformation> {
                    new AttributeSortInformation(ImporterAspect.ATTR_DATEADDED, SortDirection.Ascending)
                }
            });
        }
Exemple #3
0
        internal static async Task <MediaItem> GetAlbumByAlbumNameAsync(Guid?userId, string albumName)
        {
            IFilter           searchFilter = new RelationalFilter(AudioAlbumAspect.ATTR_ALBUM, RelationalOperator.EQ, albumName);
            IList <MediaItem> items        = await GetAlbumsAsync(userId, searchFilter, 1);

            return(items.FirstOrDefault());
        }
        public bool TryGetFanArt(FanArtConstants.FanArtMediaType mediaType, FanArtConstants.FanArtType fanArtType, string name, int maxWidth, int maxHeight, bool singleRandom, out IList <FanArtImage> result)
        {
            result = null;
            if (mediaType != FanArtConstants.FanArtMediaType.Album || fanArtType != FanArtConstants.FanArtType.Poster || string.IsNullOrEmpty(name))
            {
                return(false);
            }

            IMediaLibrary mediaLibrary = ServiceRegistration.Get <IMediaLibrary>(false);

            if (mediaLibrary == null)
            {
                return(false);
            }

            IFilter        filter = new RelationalFilter(AudioAspect.ATTR_ALBUM, RelationalOperator.EQ, name);
            MediaItemQuery query  = new MediaItemQuery(NECESSARY_MIAS, filter);
            var            items  = mediaLibrary.Search(query, false);

            result = new List <FanArtImage>();
            foreach (var mediaItem in items)
            {
                byte[] textureData;
                if (!MediaItemAspect.TryGetAttribute(mediaItem.Aspects, ThumbnailLargeAspect.ATTR_THUMBNAIL, out textureData))
                {
                    continue;
                }

                // Only one record required
                result.Add(new FanArtImage(name, textureData));
                return(true);
            }
            return(true);
        }
Exemple #5
0
        internal static Task <IList <MediaItem> > GetTrackByAlbumTrackAsync(Guid?userId, Guid albumId, int discNo, int trackNo)
        {
            IFilter filter = new RelationalFilter(AudioAspect.ATTR_DISCID, RelationalOperator.EQ, discNo);

            filter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, filter, new RelationalFilter(AudioAspect.ATTR_TRACK, RelationalOperator.EQ, trackNo));
            return(GetTracksAsync(userId, albumId, filter));
        }
Exemple #6
0
        internal static async Task <MediaItem> GetSeriesBySeriesNameAsync(Guid?userId, string seriesName)
        {
            IFilter           searchFilter = new RelationalFilter(SeriesAspect.ATTR_SERIES_NAME, RelationalOperator.EQ, seriesName);
            IList <MediaItem> items        = await GetSeriesAsync(userId, searchFilter, 1);

            return(items.FirstOrDefault());
        }
Exemple #7
0
        internal static async Task <MediaItem> GetRecordingByRecordingNameAsync(Guid?userId, string recordingName)
        {
            IFilter           searchFilter = new RelationalFilter(MediaAspect.ATTR_TITLE, RelationalOperator.EQ, recordingName);
            IList <MediaItem> items        = await GetRecordingsAsync(userId, searchFilter, 1);

            return(items.FirstOrDefault());
        }
Exemple #8
0
        internal static async Task <MediaItem> GetMovieByMovieNameAsync(Guid?userId, string movieName)
        {
            IFilter           searchFilter = new RelationalFilter(MovieAspect.ATTR_MOVIE_NAME, RelationalOperator.EQ, movieName);
            IList <MediaItem> items        = await GetMoviesAsync(userId, searchFilter, 1);

            return(items.FirstOrDefault());
        }
Exemple #9
0
        internal static Task <IList <MediaItem> > GetEpisodesBySeriesSeasonAsync(Guid?userId, Guid seriesId, int seasonNo)
        {
            IFilter filter = new RelationalFilter(EpisodeAspect.ATTR_SEASON, RelationalOperator.EQ, seasonNo);
            List <ISortInformation> sort = new List <ISortInformation>();

            sort.Add(new AttributeSortInformation(EpisodeAspect.ATTR_EPISODE, SortDirection.Ascending));

            return(GetEpisodesAsync(userId, seriesId, filter, sort));
        }
Exemple #10
0
        internal static async Task <MediaItem> GetEpisodeBySeriesEpisodeAsync(Guid?userId, Guid seriesId, int seasonNo, int episodeNo)
        {
            IFilter filter = new RelationalFilter(EpisodeAspect.ATTR_SEASON, RelationalOperator.EQ, seasonNo);

            filter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, filter, new InFilter(EpisodeAspect.ATTR_EPISODE, new object[] { episodeNo }));
            var items = await GetEpisodesAsync(userId, seriesId, filter);

            return(items.FirstOrDefault());
        }
        public static IFilter GetEpisodeSearchFilter(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects)
        {
            SingleMediaItemAspect episodeAspect;

            if (!MediaItemAspect.TryGetAspect(extractedAspects, EpisodeAspect.Metadata, out episodeAspect))
            {
                return(null);
            }

            IFilter episodeFilter = RelationshipExtractorUtils.CreateExternalItemFilter(extractedAspects, ExternalIdentifierAspect.TYPE_EPISODE);
            IFilter seriesFilter  = RelationshipExtractorUtils.CreateExternalItemFilter(extractedAspects, ExternalIdentifierAspect.TYPE_SERIES);

            if (seriesFilter == null)
            {
                return(episodeFilter);
            }

            int?    seasonNumber       = episodeAspect.GetAttributeValue <int?>(EpisodeAspect.ATTR_SEASON);
            IFilter seasonNumberFilter = seasonNumber.HasValue ?
                                         new RelationalFilter(EpisodeAspect.ATTR_SEASON, RelationalOperator.EQ, seasonNumber.Value) : null;

            IEnumerable <int> episodeNumbers      = episodeAspect.GetCollectionAttribute <int>(EpisodeAspect.ATTR_EPISODE);
            IFilter           episodeNumberFilter = null;

            if (episodeNumbers.Count() > 1)
            {
                episodeNumberFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.Or, episodeNumbers.Select(e => new RelationalFilter(EpisodeAspect.ATTR_EPISODE, RelationalOperator.EQ, e)));
            }
            else if (episodeNumbers.Any())
            {
                episodeNumberFilter = new RelationalFilter(EpisodeAspect.ATTR_EPISODE, RelationalOperator.EQ, episodeNumbers.First());
            }

            seriesFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, seriesFilter, seasonNumberFilter, episodeNumberFilter);

            return(BooleanCombinationFilter.CombineFilters(BooleanOperator.Or, episodeFilter, seriesFilter));
        }
Exemple #12
0
        public override ICollection <FilterValue> GetAvailableValues(IEnumerable <Guid> necessaryMIATypeIds, IFilter selectAttributeFilter, IFilter filter)
        {
            IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory;

            if (cd == null)
            {
                throw new NotConnectedException("The MediaLibrary is not connected");
            }

            IFilter unwatchedFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.Or,
                                                                              new EmptyFilter(MediaAspect.ATTR_PLAYCOUNT),
                                                                              new RelationalFilter(MediaAspect.ATTR_PLAYCOUNT, RelationalOperator.EQ, 0));

            IFilter watchedFilter = new RelationalFilter(MediaAspect.ATTR_PLAYCOUNT, RelationalOperator.GT, 0);

            int numUnwatchedItems = cd.CountMediaItems(necessaryMIATypeIds, unwatchedFilter, true);
            int numWatchedItems   = cd.CountMediaItems(necessaryMIATypeIds, watchedFilter, true);

            return(new List <FilterValue>(new FilterValue[]
            {
                new FilterValue(Consts.RES_VALUE_UNWATCHED, unwatchedFilter, null, numUnwatchedItems, this),
                new FilterValue(Consts.RES_VALUE_WATCHED, watchedFilter, null, numWatchedItems, this),
            }.Where(fv => !fv.NumItems.HasValue || fv.NumItems.Value > 0)));
        }
Exemple #13
0
        /// <summary>
        /// Builds the actual filter SQL expression <c>[Attribute-Operand] [Operator] [Comparison-Value]</c> for the given
        /// attribute <paramref name="filter"/>.
        /// </summary>
        /// <param name="filter">Attribute filter instance to create the SQL expression for.</param>
        /// <param name="attributeOperand">Comparison attribute to be used. Depending on the cardinality of the
        /// to-be-filtered attribute, this will be the inline attribute alias or the attribute alias of the collection
        /// attribute table.</param>
        /// <param name="bvNamespace">Namespace used to build bind var names.</param>
        /// <param name="resultParts">Statement parts for the attribute filter.</param>
        /// <param name="resultBindVars">Bind variables for the attribute filter.</param>
        public static void BuildAttributeFilterExpression(IAttributeFilter filter, object attributeOperand, BindVarNamespace bvNamespace,
                                                          IList <object> resultParts, IList <BindVar> resultBindVars)
        {
            Type             attributeType    = filter.AttributeType.AttributeType;
            RelationalFilter relationalFilter = filter as RelationalFilter;

            if (relationalFilter != null)
            {
                resultParts.Add(attributeOperand);
                switch (relationalFilter.Operator)
                {
                case RelationalOperator.EQ:
                    resultParts.Add(" = ");
                    break;

                case RelationalOperator.NEQ:
                    resultParts.Add(" <> ");
                    break;

                case RelationalOperator.LT:
                    resultParts.Add(" < ");
                    break;

                case RelationalOperator.LE:
                    resultParts.Add(" <= ");
                    break;

                case RelationalOperator.GT:
                    resultParts.Add(" > ");
                    break;

                case RelationalOperator.GE:
                    resultParts.Add(" >= ");
                    break;

                default:
                    throw new NotImplementedException(string.Format(
                                                          "Relational filter operator '{0}' isn't supported by the media library", relationalFilter.Operator));
                }
                BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), relationalFilter.FilterValue, attributeType);
                resultParts.Add("@" + bindVar.Name);
                resultBindVars.Add(bindVar);
                return;
            }

            LikeFilter likeFilter = filter as LikeFilter;

            if (likeFilter != null)
            {
                if (!likeFilter.CaseSensitive)
                {
                    resultParts.Add("UPPER(");
                }

                resultParts.Add(attributeOperand);

                if (!likeFilter.CaseSensitive)
                {
                    resultParts.Add(")");
                }

                resultParts.Add(" LIKE ");

                BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), likeFilter.Expression, attributeType);
                if (likeFilter.CaseSensitive)
                {
                    resultParts.Add("@" + bindVar.Name);
                }
                else
                {
                    resultParts.Add("UPPER(@" + bindVar.Name + ")");
                }
                resultBindVars.Add(bindVar);
                if (likeFilter.EscapeChar.HasValue)
                {
                    bindVar = new BindVar(bvNamespace.CreateNewBindVarName("E"), likeFilter.EscapeChar.ToString(), typeof(Char));
                    resultParts.Add(" ESCAPE @" + bindVar.Name);
                    resultBindVars.Add(bindVar);
                }
                return;
            }

            BetweenFilter betweenFilter = filter as BetweenFilter;

            if (betweenFilter != null)
            {
                resultParts.Add(attributeOperand);
                resultParts.Add(" BETWEEN ");
                BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), betweenFilter.Value1, attributeType);
                resultParts.Add("@" + bindVar.Name);
                resultBindVars.Add(bindVar);
                resultParts.Add(" AND ");
                bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), betweenFilter.Value2, attributeType);
                resultParts.Add("@" + bindVar.Name);
                resultBindVars.Add(bindVar);
                return;
            }

            InFilter inFilter = filter as InFilter;

            if (inFilter != null)
            {
                if (inFilter.Values.Count == 0)
                {
                    resultParts.Add("1 = 2"); // No comparison values means filter is always false
                    return;
                }
                int clusterCount = 0;
                foreach (IList <object> valuesCluster in CollectionUtils.Cluster(inFilter.Values, MAX_IN_VALUES_SIZE))
                {
                    if (clusterCount > 0)
                    {
                        resultParts.Add(" OR ");
                    }
                    resultParts.Add(attributeOperand);
                    IList <string> bindVarRefs = new List <string>(MAX_IN_VALUES_SIZE);
                    foreach (object value in valuesCluster)
                    {
                        BindVar bindVar = new BindVar(bvNamespace.CreateNewBindVarName("V"), value, attributeType);
                        bindVarRefs.Add("@" + bindVar.Name);
                        resultBindVars.Add(bindVar);
                    }
                    resultParts.Add(" IN (" + StringUtils.Join(", ", bindVarRefs) + ")");
                    clusterCount++;
                }
                return;
            }
            throw new InvalidDataException("Filter type '{0}' isn't supported by the media library", filter.GetType().Name);
        }
        public override ICollection <FilterValue> GetAvailableValues(IEnumerable <Guid> necessaryMIATypeIds, IFilter selectAttributeFilter, IFilter filter)
        {
            IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory;

            if (cd == null)
            {
                throw new NotConnectedException("The MediaLibrary is not connected");
            }

            if (_necessaryMIATypeIds != null)
            {
                necessaryMIATypeIds = _necessaryMIATypeIds;
            }
            HomogenousMap valueGroups = null;
            HomogenousMap valueKeys   = null;

            if (_keyAttributeType != null)
            {
                Tuple <HomogenousMap, HomogenousMap> values = cd.GetKeyValueGroups(_keyAttributeType, _valueAttributeType, selectAttributeFilter, ProjectionFunction.None, necessaryMIATypeIds, filter, true,
                                                                                   ShowVirtualSetting.ShowVirtualMedia(necessaryMIATypeIds));
                valueGroups = values.Item1;
                valueKeys   = values.Item2;
            }
            else
            {
                valueGroups = cd.GetValueGroups(_valueAttributeType, selectAttributeFilter, ProjectionFunction.None, necessaryMIATypeIds, filter, true,
                                                ShowVirtualSetting.ShowVirtualMedia(necessaryMIATypeIds));
            }
            IList <FilterValue> result = new List <FilterValue>(valueGroups.Count);
            int numEmptyEntries        = 0;

            foreach (KeyValuePair <object, object> group in valueGroups)
            {
                if (_keyAttributeType != null)
                {
                    string name = GetDisplayName(group.Key);
                    if (name == string.Empty)
                    {
                        numEmptyEntries += (int)group.Value;
                    }
                    else
                    {
                        IFilter queryFilter = new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key);
                        if (filter != null)
                        {
                            queryFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, queryFilter, filter);
                        }
                        result.Add(new FilterValue(valueKeys[group.Key], name, new FilteredRelationshipFilter(Guid.Empty, queryFilter), null, (int)group.Value, this));
                    }
                }
                else
                {
                    string name = GetDisplayName(group.Key);
                    if (name == string.Empty)
                    {
                        numEmptyEntries += (int)group.Value;
                    }
                    else
                    {
                        IFilter queryFilter = new RelationalFilter(_valueAttributeType, RelationalOperator.EQ, group.Key);
                        if (filter != null)
                        {
                            queryFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, queryFilter, filter);
                        }
                        result.Add(new FilterValue(name, new FilteredRelationshipFilter(Guid.Empty, queryFilter), null, (int)group.Value, this));
                    }
                }
            }
            if (numEmptyEntries > 0)
            {
                IFilter queryFilter = new EmptyFilter(_valueAttributeType);
                if (filter != null)
                {
                    queryFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And, queryFilter, filter);
                }
                result.Insert(0, new FilterValue(Consts.RES_VALUE_EMPTY_TITLE, new FilteredRelationshipFilter(Guid.Empty, queryFilter), null, numEmptyEntries, this));
            }
            return(result);
        }
        internal static IList <MediaItem> GetMediaItemsByInt(IOwinContext context, int number, ISet <Guid> necessaryMIATypes, ISet <Guid> optionalMIATypes, AttributeSpecification attributeSpecification, uint?limit = null)
        {
            IFilter searchFilter = new RelationalFilter(attributeSpecification, RelationalOperator.EQ, number);

            return(Search(context, necessaryMIATypes, optionalMIATypes, searchFilter, limit));
        }
Exemple #16
0
        public void TestSubqueryQueryBuilder()
        {
            // Use the real RelationshipFilter because CompiledFilter is hard coded to look for it
            MockCore.AddMediaItemAspectStorage(RelationshipAspect.Metadata);

            SingleTestMIA mia1 = TestBackendUtils.CreateSingleMIA("Meta1", Cardinality.Inline, true, true);
            SingleTestMIA mia2 = TestBackendUtils.CreateSingleMIA("Meta2", Cardinality.Inline, true, true);
            SingleTestMIA mia3 = TestBackendUtils.CreateSingleMIA("Meta3", Cardinality.Inline, true, true);
            SingleTestMIA mia4 = TestBackendUtils.CreateSingleMIA("Meta4", Cardinality.Inline, true, true);

            ICollection <MediaItemAspectMetadata> requiredMIATypes = new List <MediaItemAspectMetadata>();

            requiredMIATypes.Add(mia1.Metadata);

            IFilter linkedMovieFilter = new RelationalFilter(mia2.ATTR_INTEGER, RelationalOperator.EQ, 1);

            Guid    movieType               = new Guid("bbbbbbbb-2222-2222-2222-bbbbbbbbbbbb");
            Guid    collectionType          = new Guid("cccccccc-3333-3333-3333-cccccccccccc");
            Guid    actorType               = new Guid("dddddddd-4444-4444-4444-dddddddddddd");
            IFilter movieToCollectionFilter = new FilteredRelationshipFilter(collectionType, movieType, linkedMovieFilter);

            IFilter linkedActorFilter = new RelationalFilter(mia3.ATTR_INTEGER, RelationalOperator.EQ, 1);
            IFilter movieToCollectionToActorFilter = BooleanCombinationFilter.CombineFilters(BooleanOperator.And,
                                                                                             linkedActorFilter, new FilteredRelationshipFilter(actorType, collectionType, movieToCollectionFilter));

            IFilter subQueryFilter = new RelationalFilter(mia4.ATTR_INTEGER, RelationalOperator.EQ, 1);

            MIAQueryBuilder builder = new MIAQueryBuilder(MockCore.Management, new List <QueryAttribute>(), null, requiredMIATypes, new List <MediaItemAspectMetadata>(), movieToCollectionToActorFilter, subQueryFilter, null);

            string mediaItemIdAlias = null;
            IDictionary <MediaItemAspectMetadata, string> miamAliases      = null;
            IDictionary <QueryAttribute, string>          attributeAliases = null;
            string          statementStr = null;
            IList <BindVar> bindVars     = null;

            builder.GenerateSqlStatement(out mediaItemIdAlias, out miamAliases, out attributeAliases, out statementStr, out bindVars);
            Console.WriteLine("mediaItemIdAlias: {0}", mediaItemIdAlias);
            Console.WriteLine("miamAliases: [{0}]", string.Join(",", miamAliases));
            Console.WriteLine("attributeAliases: [{0}]", string.Join(",", attributeAliases));
            Console.WriteLine("statementStr: {0}", statementStr);
            Console.WriteLine("bindVars: [{0}]", string.Join(",", bindVars));

            Assert.AreEqual("A0", mediaItemIdAlias, "Media item ID alias");
            Assert.AreEqual(CreateMIAMAliases(mia1.Metadata, "A1", mia3.Metadata, "A2"), miamAliases, "MIAM aliases");
            Assert.AreEqual(new Dictionary <QueryAttribute, string>(), attributeAliases, "Attribute aliases");
            Assert.AreEqual("SELECT T0.MEDIA_ITEM_ID A0, T0.MEDIA_ITEM_ID A1, T1.MEDIA_ITEM_ID A2 FROM M_META1 T0 LEFT OUTER JOIN M_META3 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID " +
                            " WHERE (T1.ATTR_INTEGER = @V0 AND T0.MEDIA_ITEM_ID" +
                            " IN(SELECT R1.MEDIA_ITEM_ID FROM M_RELATIONSHIP R1 WHERE R1.ROLE=@V1 AND R1.LINKEDROLE=@V2 AND R1.LINKEDID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META4 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID " +
                            " WHERE (T0.MEDIA_ITEM_ID IN(SELECT R1.MEDIA_ITEM_ID FROM M_RELATIONSHIP R1 WHERE R1.ROLE=@V3 AND R1.LINKEDROLE=@V4 AND R1.LINKEDID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1, T2.MEDIA_ITEM_ID A2 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META2 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID LEFT OUTER JOIN M_META4 T2 ON T0.MEDIA_ITEM_ID = T2.MEDIA_ITEM_ID" +
                            "  WHERE (T1.ATTR_INTEGER = @V5 AND T2.ATTR_INTEGER = @V6)) TS)" +
                            " UNION SELECT R1.LINKEDID FROM M_RELATIONSHIP R1 WHERE R1.LINKEDROLE=@V3 AND R1.ROLE=@V4 AND R1.MEDIA_ITEM_ID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1, T2.MEDIA_ITEM_ID A2 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META2 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID LEFT OUTER JOIN M_META4 T2 ON T0.MEDIA_ITEM_ID = T2.MEDIA_ITEM_ID" +
                            "  WHERE (T1.ATTR_INTEGER = @V5 AND T2.ATTR_INTEGER = @V6)) TS)) AND T1.ATTR_INTEGER = @V7)) TS)" +
                            " UNION SELECT R1.LINKEDID FROM M_RELATIONSHIP R1 WHERE R1.LINKEDROLE=@V1 AND R1.ROLE=@V2 AND R1.MEDIA_ITEM_ID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META4 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID" +
                            "  WHERE (T0.MEDIA_ITEM_ID IN(SELECT R1.MEDIA_ITEM_ID FROM M_RELATIONSHIP R1 WHERE R1.ROLE=@V3 AND R1.LINKEDROLE=@V4 AND R1.LINKEDID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1, T2.MEDIA_ITEM_ID A2 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META2 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID LEFT OUTER JOIN M_META4 T2 ON T0.MEDIA_ITEM_ID = T2.MEDIA_ITEM_ID" +
                            "  WHERE (T1.ATTR_INTEGER = @V5 AND T2.ATTR_INTEGER = @V6)) TS)" +
                            " UNION SELECT R1.LINKEDID FROM M_RELATIONSHIP R1 WHERE R1.LINKEDROLE=@V3 AND R1.ROLE=@V4 AND R1.MEDIA_ITEM_ID" +
                            " IN( SELECT TS.A0 FROM (SELECT T0.MEDIA_ITEM_ID A0, T1.MEDIA_ITEM_ID A1, T2.MEDIA_ITEM_ID A2 FROM MEDIA_ITEMS T0 LEFT OUTER JOIN M_META2 T1 ON T0.MEDIA_ITEM_ID = T1.MEDIA_ITEM_ID LEFT OUTER JOIN M_META4 T2 ON T0.MEDIA_ITEM_ID = T2.MEDIA_ITEM_ID" +
                            "  WHERE (T1.ATTR_INTEGER = @V5 AND T2.ATTR_INTEGER = @V6)) TS)) AND T1.ATTR_INTEGER = @V7)) TS)))", statementStr, "Statement");
            Assert.AreEqual(new List <BindVar>
            {
                new BindVar("V0", 1, typeof(int)),
                new BindVar("V1", actorType, typeof(Guid)),
                new BindVar("V2", collectionType, typeof(Guid)),
                new BindVar("V3", collectionType, typeof(Guid)),
                new BindVar("V4", movieType, typeof(Guid)),
                new BindVar("V5", 1, typeof(int)),
                new BindVar("V6", 1, typeof(int)),
                new BindVar("V7", 1, typeof(int))
            }, bindVars, "Bind vars");
        }