コード例 #1
0
        /// <summary>
        /// Async ctor
        /// </summary>
        public static async Task <BufferReaderAsync> CreateAsync(IAsyncEnumerable <BufferSlice> source, bool utcDate = false)
        {
            var instance = new BufferReaderAsync(source, utcDate);
            await instance.InitializeAsync();

            return(instance);
        }
コード例 #2
0
        public virtual async Task <BsonDocument> Load(PageAddress rawId)
        {
            await using (var reader = await BufferReaderAsync.CreateAsync(_data.Read(rawId), _utcDate))
            {
                var doc = await reader.ReadDocument(_fields);

                doc.RawId = rawId;

                return(doc);
            }
        }
コード例 #3
0
        /// <summary>
        /// Create a new index (or do nothing if already exists) to a collection/field
        /// </summary>
        public async Task <bool> EnsureIndexAsync(string collection, string name, BsonExpression expression, bool unique)
        {
            if (collection.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(collection));
            }
            if (name.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (expression.IsIndexable == false)
            {
                throw new ArgumentException("Index expressions must contains at least one document field. Used methods must be immutable. Parameters are not supported.", nameof(expression));
            }

            if (name.Length > INDEX_NAME_MAX_LENGTH)
            {
                throw LiteException.InvalidIndexName(name, collection, "MaxLength = " + INDEX_NAME_MAX_LENGTH);
            }
            if (!name.IsWord())
            {
                throw LiteException.InvalidIndexName(name, collection, "Use only [a-Z$_]");
            }
            if (name.StartsWith("$"))
            {
                throw LiteException.InvalidIndexName(name, collection, "Index name can't starts with `$`");
            }
            if (expression.IsScalar == false && unique)
            {
                throw new LiteException(0, "Multikey index expression do not support unique option");
            }

            if (expression.Source == "$._id")
            {
                return(false);                              // always exists
            }
            return(await this.AutoTransaction(async transaction =>
            {
                var snapshot = await transaction.CreateSnapshot(LockMode.Write, collection, true);
                var collectionPage = snapshot.CollectionPage;
                var indexer = new IndexService(snapshot, _header.Pragmas.Collation);
                var data = new DataService(snapshot);

                // check if index already exists
                var current = collectionPage.GetCollectionIndex(name);

                // if already exists, just exit
                if (current != null)
                {
                    // but if expression are different, throw error
                    if (current.Expression != expression.Source)
                    {
                        throw LiteException.IndexAlreadyExist(name);
                    }

                    return false;
                }

                LOG($"create index `{collection}.{name}`", "COMMAND");

                // create index head
                var index = await indexer.CreateIndex(name, expression.Source, unique);
                var count = 0u;

                // read all objects (read from PK index)
                await foreach (var pkNode in new IndexAll("_id", LiteDB.Query.Ascending).Run(collectionPage, indexer))
                {
                    await using (var reader = await BufferReaderAsync.CreateAsync(data.Read(pkNode.DataBlock)))
                    {
                        var doc = await reader.ReadDocument(expression.Fields);

                        // first/last node in this document that will be added
                        IndexNode last = null;
                        IndexNode first = null;

                        // get values from expression in document
                        var keys = expression.GetIndexKeys(doc, _header.Pragmas.Collation);

                        // adding index node for each value
                        foreach (var key in keys)
                        {
                            // insert new index node
                            var node = await indexer.AddNode(index, key, pkNode.DataBlock, last);

                            if (first == null)
                            {
                                first = node;
                            }

                            last = node;

                            count++;
                        }

                        // fix single linked-list in pkNode
                        if (first != null)
                        {
                            last.SetNextNode(pkNode.NextNode);
                            pkNode.SetNextNode(first.Position);
                        }
                    }

                    await transaction.Safepoint();
                }

                return true;
            }));
        }