Example #1
0
        internal static string GetQuerySource(DocumentConventions conventions, Type type, IndexSourceType sourceType)
        {
            var collectionName = conventions.GetCollectionName(type);

            string source;

            switch (sourceType)
            {
            case IndexSourceType.Documents:
                source = "docs";
                break;

            case IndexSourceType.Counters:
                source = "counters";
                break;

            case IndexSourceType.TimeSeries:
                source = "timeSeries";
                break;

            default:
                throw new NotSupportedException($"Not supported index source type '{sourceType}'.");
            }

            if (StringExtensions.IsIdentifier(collectionName))
            {
                return($"{source}.{collectionName}");
            }

            return($"{source}[@\"{collectionName.Replace("\"", "\"\"")}\"]");
        }
Example #2
0
        internal static string GetQuerySource(DocumentConventions conventions, Type type, IndexSourceType sourceType)
        {
            var collectionName = conventions.GetCollectionName(type);

            string source;

            switch (sourceType)
            {
            case IndexSourceType.Documents:
                source = "docs";
                break;

            case IndexSourceType.Counters:
                source = "counters";
                break;

            case IndexSourceType.TimeSeries:
                source = "timeSeries";
                break;

            default:
                throw new NotSupportedException($"Not supported index source type '{sourceType}'.");
            }

            if (StringExtensions.IsIdentifier(collectionName))
            {
                return($"{source}.{collectionName}");
            }

            var builder = new StringBuilder($"{source}[@\"");

            StringExtensions.EscapeString(builder, collectionName);
            return(builder.Append("\"]").ToString());
        }
        public Task <string> GenerateDocumentIdAsync(object entity)
        {
            var typeTagName = Conventions.GetCollectionName(entity);

            if (string.IsNullOrEmpty(typeTagName)) //ignore empty tags
            {
                return(NullStringCompletedTask);
            }
            var tag = Conventions.TransformTypeCollectionNameToDocumentIdPrefix(typeTagName);

            if (_idGeneratorsByTag.TryGetValue(tag, out var value))
            {
                return(value.GenerateDocumentIdAsync(entity));
            }

            lock (_generatorLock)
            {
                if (_idGeneratorsByTag.TryGetValue(tag, out value))
                {
                    return(value.GenerateDocumentIdAsync(entity));
                }

                value = CreateGeneratorFor(tag);
                _idGeneratorsByTag.TryAdd(tag, value);
            }

            return(value.GenerateDocumentIdAsync(entity));
        }
        public Task <string> GenerateDocumentIdAsync(object entity)
        {
            var typeTagName = _conventions.GetCollectionName(entity);

            if (string.IsNullOrEmpty(typeTagName)) //ignore empty tags
            {
                return(NullStringCompletedTask);
            }
            var tag = _conventions.TransformTypeCollectionNameToDocumentIdPrefix(typeTagName);
            AsyncHiLoIdGenerator value;

            if (_idGeneratorsByTag.TryGetValue(tag, out value))
            {
                return(value.GenerateDocumentIdAsync(entity));
            }

            lock (_generatorLock)
            {
                if (_idGeneratorsByTag.TryGetValue(tag, out value))
                {
                    return(value.GenerateDocumentIdAsync(entity));
                }

                value = new AsyncHiLoIdGenerator(tag, _store, _dbName, _conventions.IdentityPartsSeparator);
                _idGeneratorsByTag.TryAdd(tag, value);
            }

            return(value.GenerateDocumentIdAsync(entity));
        }
Example #5
0
        internal static string GetQuerySource(DocumentConventions conventions, Type type)
        {
            var collectionName = conventions.GetCollectionName(type);

            if (StringExtensions.IsIdentifier(collectionName))
            {
                return("docs." + collectionName);
            }

            return("docs[@\"" + collectionName.Replace("\"", "\"\"") + "\"]");
        }
Example #6
0
        public static string GetPrefixedIncludePath <TInclude>(string basePath, DocumentConventions conventions)
        {
            var idPrefix = conventions.GetCollectionName(typeof(TInclude));

            if (idPrefix != null)
            {
                idPrefix  = conventions.TransformTypeCollectionNameToDocumentIdPrefix(idPrefix);
                idPrefix += conventions.IdentityPartsSeparator;
            }

            return(basePath + "(" + idPrefix + ")");
        }
Example #7
0
        internal static string GetQuerySource(DocumentConventions conventions, Type type)
        {
            var collectionName = conventions.GetCollectionName(type);

            if (StringExtensions.IsIdentifier(collectionName))
            {
                return("docs." + collectionName);
            }

            var builder = new StringBuilder("docs[@\"");

            StringExtensions.EscapeString(builder, collectionName);
            return(builder.Append("\"]").ToString());
        }
        public async Task <string> GenerateDocumentIdAsync(object entity)
        {
            var identityPartsSeparator = Conventions.IdentityPartsSeparator;

            if (_identityPartsSeparator != identityPartsSeparator)
            {
                await MaybeRefresh(identityPartsSeparator).ConfigureAwait(false);
            }

            var typeTagName = Conventions.GetCollectionName(entity);

            if (string.IsNullOrEmpty(typeTagName)) //ignore empty tags
            {
                return(null);
            }
            var tag = Conventions.TransformTypeCollectionNameToDocumentIdPrefix(typeTagName);

            if (_idGeneratorsByTag.TryGetValue(tag, out var value))
            {
                return(await value.GenerateDocumentIdAsync(entity).ConfigureAwait(false));
            }

            await _generatorLock.WaitAsync().ConfigureAwait(false);

            try
            {
                if (_idGeneratorsByTag.TryGetValue(tag, out value))
                {
                    return(await value.GenerateDocumentIdAsync(entity).ConfigureAwait(false));
                }

                value = CreateGeneratorFor(tag);
                _idGeneratorsByTag.TryAdd(tag, value);
            }
            finally
            {
                _generatorLock.Release();
            }

            return(await value.GenerateDocumentIdAsync(entity).ConfigureAwait(false));
        }
Example #9
0
        public IChangesObservable <DocumentChange> ForDocumentsInCollection <TEntity>()
        {
            var collectionName = _conventions.GetCollectionName(typeof(TEntity));

            return(ForDocumentsInCollection(collectionName));
        }
        internal static SubscriptionCreationOptions CreateSubscriptionOptionsFromGeneric <T>(
            DocumentConventions conventions,
            SubscriptionCreationOptions criteria,
            Expression <Func <T, bool> > predicate,
            Expression <Func <T, object> > project,
            Action <ISubscriptionIncludeBuilder <T> > includes)
        {
            criteria ??= new SubscriptionCreationOptions();
            var collectionName = conventions.GetCollectionName(typeof(T));

            if (criteria.Query == null)
            {
                var tType            = typeof(T);
                var includeRevisions = tType.IsConstructedGenericType && tType.GetGenericTypeDefinition() == typeof(Revision <>);
                if (includeRevisions)
                {
                    collectionName = conventions.GetCollectionName(tType.GenericTypeArguments[0]);
                }

                var builder = new StringBuilder("from '");
                StringExtensions.EscapeString(builder, collectionName);
                builder.Append('\'');
                if (includeRevisions)
                {
                    builder.Append(" (Revisions = true)");
                }

                criteria.Query = builder.Append(" as doc").ToString();
            }

            if (predicate != null)
            {
                var script = predicate.CompileToJavascript(
                    new JavascriptCompilationOptions(
                        JsCompilationFlags.BodyOnly,
                        JavascriptConversionExtensions.MathSupport.Instance,
                        new JavascriptConversionExtensions.DictionarySupport(),
                        JavascriptConversionExtensions.LinqMethodsSupport.Instance,
                        new JavascriptConversionExtensions.SubscriptionsWrappedConstantSupport(conventions),
                        new JavascriptConversionExtensions.ConstSupport(conventions),
                        new JavascriptConversionExtensions.ReplaceParameterWithNewName(predicate.Parameters[0], "this"),
                        JavascriptConversionExtensions.ToStringSupport.Instance,
                        JavascriptConversionExtensions.DateTimeSupport.Instance,
                        JavascriptConversionExtensions.InvokeSupport.Instance,
                        JavascriptConversionExtensions.NullCoalescingSupport.Instance,
                        JavascriptConversionExtensions.NestedConditionalSupport.Instance,
                        JavascriptConversionExtensions.StringSupport.Instance
                        ));

                criteria.Query = $"declare function predicate() {{ return {script} }}{Environment.NewLine}" +
                                 $"{criteria.Query}{Environment.NewLine}" +
                                 "where predicate.call(doc)";
            }

            if (project != null)
            {
                var script = project.CompileToJavascript(
                    new JavascriptCompilationOptions(
                        JsCompilationFlags.BodyOnly,
                        JavascriptConversionExtensions.MathSupport.Instance,
                        new JavascriptConversionExtensions.DictionarySupport(),
                        JavascriptConversionExtensions.LinqMethodsSupport.Instance,
                        new JavascriptConversionExtensions.ConstSupport(conventions),
                        JavascriptConversionExtensions.ToStringSupport.Instance,
                        JavascriptConversionExtensions.DateTimeSupport.Instance,
                        JavascriptConversionExtensions.InvokeSupport.Instance,
                        JavascriptConversionExtensions.NullCoalescingSupport.Instance,
                        JavascriptConversionExtensions.StringSupport.Instance,
                        JavascriptConversionExtensions.NestedConditionalSupport.Instance,
                        new JavascriptConversionExtensions.ReplaceParameterWithNewName(project.Parameters[0], "doc"),
                        JavascriptConversionExtensions.CounterSupport.Instance,
                        JavascriptConversionExtensions.CompareExchangeSupport.Instance
                        ));
                criteria.Query += Environment.NewLine + "select " + script;
            }

            if (includes != null)
            {
                var builder = new IncludeBuilder <T>(conventions);
                includes(builder);

                var numberOfIncludesAdded = 0;

                if (builder.DocumentsToInclude?.Count > 0)
                {
                    criteria.Query += Environment.NewLine + "include ";

                    foreach (var inc in builder.DocumentsToInclude)
                    {
                        var include = "doc." + inc;

                        if (numberOfIncludesAdded > 0)
                        {
                            criteria.Query += ",";
                        }

                        if (IncludesUtil.RequiresQuotes(include, out var escapedInclude))
                        {
                            criteria.Query += $"'{escapedInclude}'";
                        }
                        else
                        {
                            criteria.Query += include;
                        }

                        numberOfIncludesAdded++;
                    }
                }

                if (builder.AllCounters)
                {
                    if (numberOfIncludesAdded == 0)
                    {
                        criteria.Query += Environment.NewLine + "include ";
                    }

                    criteria.Query += $"counters()";

                    numberOfIncludesAdded++;
                }
                else if (builder.CountersToInclude?.Count > 0)
                {
                    if (numberOfIncludesAdded == 0)
                    {
                        criteria.Query += Environment.NewLine + "include ";
                    }

                    foreach (var counterName in builder.CountersToInclude)
                    {
                        if (numberOfIncludesAdded > 0)
                        {
                            criteria.Query += ",";
                        }

                        if (IncludesUtil.RequiresQuotes(counterName, out var escapedCounterName))
                        {
                            criteria.Query += $"counters({escapedCounterName})";
                        }
                        else
                        {
                            criteria.Query += $"counters({counterName})";
                        }

                        numberOfIncludesAdded++;
                    }
                }
            }

            return(criteria);
        }
        /// <summary>
        /// Toes the index definition.
        /// </summary>
        public IndexDefinition ToIndexDefinition(DocumentConventions conventions, bool validateMap = true)
        {
            if (Map == null && validateMap)
            {
                throw new InvalidOperationException(
                          string.Format("Map is required to generate an index, you cannot create an index without a valid Map property (in index {0}).", _indexName));
            }

            try
            {
                if (Reduce != null)
                {
                    IndexDefinitionHelper.ValidateReduce(Reduce);
                }

                string querySource     = (typeof(TDocument) == typeof(object) || ContainsWhereEntityIs()) ? "docs" : "docs." + conventions.GetCollectionName(typeof(TDocument));
                var    indexDefinition = new IndexDefinition
                {
                    Name     = _indexName,
                    Reduce   = IndexDefinitionHelper.PruneToFailureLinqQueryAsStringToWorkableCode <TDocument, TReduceResult>(Reduce, conventions, "results", translateIdentityProperty: false),
                    LockMode = LockMode,
                    Priority = Priority,
                    OutputReduceToCollection = OutputReduceToCollection
                };

                var indexes            = ConvertToStringDictionary(Indexes);
                var stores             = ConvertToStringDictionary(Stores);
                var analyzers          = ConvertToStringDictionary(Analyzers);
                var suggestionsOptions = ConvertToStringSet(SuggestionsOptions).ToDictionary(x => x, x => true);
                var termVectors        = ConvertToStringDictionary(TermVectors);
                var spatialOptions     = ConvertToStringDictionary(SpatialIndexes);

                if (conventions.PrettifyGeneratedLinqExpressions)
                {
                    indexDefinition.Reduce = IndexPrettyPrinter.TryFormat(indexDefinition.Reduce);
                }

                foreach (var indexesString in IndexesStrings)
                {
                    if (indexes.ContainsKey(indexesString.Key))
                    {
                        throw new InvalidOperationException("There is a duplicate key in indexes: " + indexesString.Key);
                    }
                    indexes.Add(indexesString);
                }

                foreach (var storeString in StoresStrings)
                {
                    if (stores.ContainsKey(storeString.Key))
                    {
                        throw new InvalidOperationException("There is a duplicate key in stores: " + storeString.Key);
                    }
                    stores.Add(storeString);
                }

                foreach (var analyzerString in AnalyzersStrings)
                {
                    if (analyzers.ContainsKey(analyzerString.Key))
                    {
                        throw new InvalidOperationException("There is a duplicate key in analyzers: " + analyzerString.Key);
                    }
                    analyzers.Add(analyzerString);
                }

                foreach (var termVectorString in TermVectorsStrings)
                {
                    if (termVectors.ContainsKey(termVectorString.Key))
                    {
                        throw new InvalidOperationException("There is a duplicate key in term vectors: " + termVectorString.Key);
                    }
                    termVectors.Add(termVectorString);
                }

                foreach (var spatialString in SpatialIndexesStrings)
                {
                    if (spatialOptions.ContainsKey(spatialString.Key))
                    {
                        throw new InvalidOperationException("There is a duplicate key in spatial indexes: " + spatialString.Key);
                    }
                    spatialOptions.Add(spatialString);
                }



                ApplyValues(indexDefinition, indexes, (options, value) => options.Indexing               = value);
                ApplyValues(indexDefinition, stores, (options, value) => options.Storage                 = value);
                ApplyValues(indexDefinition, analyzers, (options, value) => options.Analyzer             = value);
                ApplyValues(indexDefinition, termVectors, (options, value) => options.TermVector         = value);
                ApplyValues(indexDefinition, spatialOptions, (options, value) => options.Spatial         = value);
                ApplyValues(indexDefinition, suggestionsOptions, (options, value) => options.Suggestions = value);

                if (Map != null)
                {
                    var map = IndexDefinitionHelper.PruneToFailureLinqQueryAsStringToWorkableCode <TDocument, TReduceResult>(
                        Map,
                        conventions,
                        querySource,
                        translateIdentityProperty: true);

                    indexDefinition.Maps.Add(conventions.PrettifyGeneratedLinqExpressions ? IndexPrettyPrinter.TryFormat(map) : map);
                }

                indexDefinition.AdditionalSources = AdditionalSources;

                return(indexDefinition);
            }
            catch (Exception e)
            {
                throw new IndexCompilationException("Failed to create index " + _indexName, e);
            }
        }
Example #12
0
        internal static SubscriptionCreationOptions CreateSubscriptionOptionsFromGeneric <T>(
            DocumentConventions conventions,
            SubscriptionCreationOptions criteria,
            Expression <Func <T, bool> > predicate,
            Expression <Func <T, object> > project,
            Action <ISubscriptionIncludeBuilder <T> > includes)
        {
            criteria ??= new SubscriptionCreationOptions();
            var           collectionName = conventions.GetCollectionName(typeof(T));
            StringBuilder queryBuilder;

            if (criteria.Query != null)
            {
                queryBuilder = new StringBuilder(criteria.Query);
            }
            else
            {
                queryBuilder = new StringBuilder();
                var tType            = typeof(T);
                var includeRevisions = tType.IsConstructedGenericType && tType.GetGenericTypeDefinition() == typeof(Revision <>);
                if (includeRevisions)
                {
                    collectionName = conventions.GetCollectionName(tType.GenericTypeArguments[0]);
                }

                queryBuilder.Append("from '");
                StringExtensions.EscapeString(queryBuilder, collectionName);
                queryBuilder.Append('\'');
                if (includeRevisions)
                {
                    queryBuilder.Append(" (Revisions = true)");
                }

                criteria.Query = queryBuilder.Append(" as doc").ToString();
            }

            if (predicate != null)
            {
                var script = predicate.CompileToJavascript(
                    new JavascriptCompilationOptions(
                        JsCompilationFlags.BodyOnly,
                        JavascriptConversionExtensions.MathSupport.Instance,
                        new JavascriptConversionExtensions.DictionarySupport(),
                        JavascriptConversionExtensions.LinqMethodsSupport.Instance,
                        new JavascriptConversionExtensions.SubscriptionsWrappedConstantSupport(conventions),
                        new JavascriptConversionExtensions.ConstSupport(conventions),
                        new JavascriptConversionExtensions.ReplaceParameterWithNewName(predicate.Parameters[0], "this"),
                        JavascriptConversionExtensions.ToStringSupport.Instance,
                        JavascriptConversionExtensions.DateTimeSupport.Instance,
                        JavascriptConversionExtensions.TimeSpanSupport.Instance,
                        JavascriptConversionExtensions.InvokeSupport.Instance,
                        JavascriptConversionExtensions.NullCoalescingSupport.Instance,
                        JavascriptConversionExtensions.NestedConditionalSupport.Instance,
                        JavascriptConversionExtensions.StringSupport.Instance,
                        new JavascriptConversionExtensions.IdentityPropertySupport(conventions)
                        ));

                queryBuilder
                .Insert(0, $"declare function predicate() {{ return {script} }}{Environment.NewLine}")
                .AppendLine()
                .Append("where predicate.call(doc)");
            }

            if (project != null)
            {
                var script = project.CompileToJavascript(
                    new JavascriptCompilationOptions(
                        JsCompilationFlags.BodyOnly,
                        JavascriptConversionExtensions.MathSupport.Instance,
                        new JavascriptConversionExtensions.DictionarySupport(),
                        JavascriptConversionExtensions.LinqMethodsSupport.Instance,
                        new JavascriptConversionExtensions.ConstSupport(conventions),
                        JavascriptConversionExtensions.ToStringSupport.Instance,
                        JavascriptConversionExtensions.DateTimeSupport.Instance,
                        JavascriptConversionExtensions.TimeSpanSupport.Instance,
                        JavascriptConversionExtensions.InvokeSupport.Instance,
                        JavascriptConversionExtensions.NullCoalescingSupport.Instance,
                        JavascriptConversionExtensions.StringSupport.Instance,
                        JavascriptConversionExtensions.NestedConditionalSupport.Instance,
                        new JavascriptConversionExtensions.ReplaceParameterWithNewName(project.Parameters[0], "doc"),
                        new JavascriptConversionExtensions.IdentityPropertySupport(conventions),
                        JavascriptConversionExtensions.CounterSupport.Instance,
                        JavascriptConversionExtensions.CompareExchangeSupport.Instance,
                        new JavascriptConversionExtensions.LoadSupport(),
                        JavascriptConversionExtensions.MemberInit.Instance
                        ));

                queryBuilder
                .AppendLine()
                .Append("select ")
                .Append(script);
            }

            if (includes != null)
            {
                var builder = new IncludeBuilder <T>(conventions);
                includes(builder);

                var numberOfIncludesAdded = 0;

                if (builder.DocumentsToInclude?.Count > 0)
                {
                    queryBuilder
                    .AppendLine()
                    .Append("include ");

                    foreach (var inc in builder.DocumentsToInclude)
                    {
                        var include = "doc." + inc;

                        if (numberOfIncludesAdded > 0)
                        {
                            queryBuilder.Append(",");
                        }

                        if (IncludesUtil.RequiresQuotes(include, out var escapedInclude))
                        {
                            queryBuilder
                            .Append("'")
                            .Append(escapedInclude)
                            .Append("'");
                        }
                        else
                        {
                            queryBuilder.Append(QueryToken.IsKeyword(include) ? $"'{include}'" : include);
                        }

                        numberOfIncludesAdded++;
                    }
                }

                if (builder.AllCounters)
                {
                    if (numberOfIncludesAdded == 0)
                    {
                        queryBuilder
                        .AppendLine()
                        .Append("include ");
                    }

                    var token = CounterIncludesToken.All(string.Empty);
                    token.WriteTo(queryBuilder);

                    numberOfIncludesAdded++;
                }
                else if (builder.CountersToInclude?.Count > 0)
                {
                    if (numberOfIncludesAdded == 0)
                    {
                        queryBuilder
                        .AppendLine()
                        .Append("include ");
                    }

                    foreach (var counterName in builder.CountersToInclude)
                    {
                        if (numberOfIncludesAdded > 0)
                        {
                            queryBuilder.Append(",");
                        }

                        var token = CounterIncludesToken.Create(string.Empty, counterName);
                        token.WriteTo(queryBuilder);

                        numberOfIncludesAdded++;
                    }
                }

                if (builder.TimeSeriesToInclude != null)
                {
                    foreach (var timeSeriesRange in builder.TimeSeriesToInclude)
                    {
                        if (numberOfIncludesAdded == 0)
                        {
                            queryBuilder
                            .AppendLine()
                            .Append("include ");
                        }

                        if (numberOfIncludesAdded > 0)
                        {
                            queryBuilder.Append(",");
                        }

                        var token = TimeSeriesIncludesToken.Create(string.Empty, timeSeriesRange);
                        token.WriteTo(queryBuilder);

                        numberOfIncludesAdded++;
                    }
                }
            }

            criteria.Query = queryBuilder.ToString();
            return(criteria);
        }
Example #13
0
 internal static string GetTimeSeriesName <TTimeSeriesEntry>(DocumentConventions conventions)
 {
     return(conventions.GetCollectionName(typeof(TTimeSeriesEntry)));
 }