/// <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); }
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); } }
/// <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; })); }