Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to specify no-tracking to reduce caching on demand #524

Merged
merged 11 commits into from
Jan 26, 2024
18 changes: 9 additions & 9 deletions src/YesSql.Abstractions/IQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ public interface IQuery<T> where T : class
/// </summary>
/// <typeparam name="TIndex">The index to filter on.</typeparam>
IQuery<T, TIndex> With<TIndex>() where TIndex : class, IIndex;

/// <summary>
/// Filters the documents with a constraint on the specified index.
/// </summary>
/// <typeparam name="TIndex">The index to filter on.</typeparam>
IQuery<T, TIndex> With<TIndex>(Expression<Func<TIndex, bool>> predicate) where TIndex : class, IIndex;

/// <summary>
/// Skips the specified number of document.
/// </summary>
Expand Down Expand Up @@ -128,7 +128,7 @@ public interface IQueryIndex<T> where T : IIndex
/// Joins the document table with an index, and filter it with a predicate.
/// </summary>
IQueryIndex<TIndex> With<TIndex>(Expression<Func<TIndex, bool>> predicate) where TIndex : class, IIndex;

/// <summary>
/// Adds a custom Where clause to the query.
/// </summary>
Expand Down Expand Up @@ -163,7 +163,7 @@ public interface IQueryIndex<T> where T : IIndex
/// Adds an OrderBy clause using a custom lambda expression.
/// </summary>
IQueryIndex<T> ThenBy(Expression<Func<T, object>> keySelector);

/// <summary>
/// Adds a descending OrderBy clause using a custom lambda expression.
/// </summary>
Expand Down Expand Up @@ -221,7 +221,7 @@ public interface IQuery<T, TIndex> : IQuery<T>
/// Adds a custom Where clause to the query using a specific dialect.
/// </summary>
IQuery<T, TIndex> Where(Func<ISqlDialect, string> sql);

/// <summary>
/// Adds a named parameter to the query.
/// </summary>
Expand All @@ -236,19 +236,19 @@ public interface IQuery<T, TIndex> : IQuery<T>
/// Sets an OrderBy clause using a custom lambda expression.
/// </summary>
IQuery<T, TIndex> OrderBy(Expression<Func<TIndex, object>> keySelector);

/// <summary>
/// Sets an OrderBy clause using a custom SQL statement.
/// </summary>
IQuery<T, TIndex> OrderBy(string sql);

IQuery<T, TIndex> OrderByDescending(Expression<Func<TIndex, object>> keySelector);

/// <summary>
/// Sets a descending OrderBy clause using a custom SQL statement.
/// </summary>
IQuery<T, TIndex> OrderByDescending(string sql);

/// <summary>
/// Sets a random OrderBy clause.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/YesSql.Abstractions/ISession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ public interface ISession : IDisposable, IAsyncDisposable
/// </remarks>
void Detach(object item, string collection = null);

/// <summary>
/// Removes multiple items from the identity map.
/// </summary>
/// <remarks>
/// This method can be used to remove multiple items that should not be served again from the cache.
/// For instance when its state as changed and any subsequent query should not return the
/// modified instance but a fresh one.
/// </remarks>
void Detach(IEnumerable<object> entries, string collection = null);

/// <summary>
/// Loads objects by id.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/YesSql.Abstractions/IStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface IStore : IDisposable
/// <summary>
/// Creates a new <see cref="ISession"/> to communicate with the <see cref="IStore"/>.
/// </summary>
ISession CreateSession();
ISession CreateSession(bool withTracking = true);

/// <summary>
/// Registers index providers.
Expand Down
25 changes: 10 additions & 15 deletions src/YesSql.Abstractions/SessionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
Expand All @@ -13,16 +13,17 @@ public static class SessionExtensions
/// Loads an object by its id.
/// </summary>
/// <returns>The object or <c>null</c>.</returns>
public async static Task<T> GetAsync<T>(this ISession session, long id, string collection = null) where T : class
{
return (await session.GetAsync<T>(new[] { id }, collection)).FirstOrDefault();
}
public async static Task<T> GetAsync<T>(this ISession session, long id, string collection = null)
where T : class
=> (await session.GetAsync<T>([id], collection)).FirstOrDefault();

/// <summary>
/// Loads objects by id.
/// </summary>
/// <returns>A collection of objects in the same order they were defined.</returns>
public static Task<IEnumerable<T>> GetAsync<T>(this ISession session, int[] ids, string collection = null) where T : class => session.GetAsync<T>(ids.Select(x => (long)x).ToArray(), collection);
public static Task<IEnumerable<T>> GetAsync<T>(this ISession session, int[] ids, string collection = null)
where T : class
=> session.GetAsync<T>(ids.Select(x => (long)x).ToArray(), collection);

/// <summary>
/// Imports an object in the local identity map.
Expand All @@ -37,9 +38,7 @@ public async static Task<T> GetAsync<T>(this ISession session, long id, string c
/// <c>true</c> if the object was imported, <c>false</c> otherwise.
/// </returns>
public static bool Import(this ISession session, object item, string collection = null)
{
return session.Import(item, 0, 0, collection);
}
=> session.Import(item, 0, 0, collection);

/// <summary>
/// Registers index providers that are used only during the lifetime of this session.
Expand All @@ -48,9 +47,7 @@ public static bool Import(this ISession session, object item, string collection
/// <param name="indexProviders">The index providers to register.</param>
/// <returns>The <see cref="ISession"/> instance.</returns>
public static ISession RegisterIndexes(this ISession session, params IIndexProvider[] indexProviders)
{
return session.RegisterIndexes(indexProviders, null);
}
=> session.RegisterIndexes(indexProviders, null);

/// <summary>
/// Registers index providers that are used only during the lifetime of this session.
Expand All @@ -60,9 +57,7 @@ public static ISession RegisterIndexes(this ISession session, params IIndexProvi
/// <param name="collection">The name of the collection.</param>
/// <returns>The <see cref="ISession"/> instance.</returns>
public static ISession RegisterIndexes(this ISession session, IIndexProvider indexProvider, string collection = null)
{
return session.RegisterIndexes(new[] { indexProvider }, collection);
}
=> session.RegisterIndexes([indexProvider], collection);

/// <summary>
/// Saves a new or existing object to the store, and updates
Expand Down
9 changes: 4 additions & 5 deletions src/YesSql.Core/Services/DefaultQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public QueryState(ISqlBuilder sqlBuilder, IStore store, string collection)
public List<Action<object, ISqlBuilder>> _parameterBindings;
public string _collection;
public IStore _store;
internal CompositeNode _predicate; // the defaut root predicate is an AND expression
internal CompositeNode _predicate; // the default root predicate is an AND expression
internal CompositeNode _currentPredicate; // the current predicate when Any() or All() is called
public bool _processed = false;
public bool _deduplicate = true;
Expand Down Expand Up @@ -131,8 +131,7 @@ public class DefaultQuery : IQuery
private readonly object _compiledQuery = null;
private readonly string _collection;

public static Dictionary<MethodInfo, Action<DefaultQuery, IStringBuilder, ISqlDialect, MethodCallExpression>> MethodMappings =
new();
public static Dictionary<MethodInfo, Action<DefaultQuery, IStringBuilder, ISqlDialect, MethodCallExpression>> MethodMappings = [];

static DefaultQuery()
{
Expand Down Expand Up @@ -564,7 +563,7 @@ private ConstantExpression Evaluate(Expression expression)
obj = null;
}

_queryState._parameterBindings = _queryState._parameterBindings ?? new List<Action<object, ISqlBuilder>>();
_queryState._parameterBindings ??= new List<Action<object, ISqlBuilder>>();

// Create a delegate that will be invoked every time a compiled query is reused,
// which will re-evaluate the current node, for the current parameter.
Expand Down Expand Up @@ -624,7 +623,7 @@ private ConstantExpression Evaluate(Expression expression)
return Expression.Constant(Expression.Lambda(expression).Compile().DynamicInvoke());
}

private string GetBinaryOperator(Expression expression)
private static string GetBinaryOperator(Expression expression)
{
switch (expression.NodeType)
{
Expand Down
60 changes: 36 additions & 24 deletions src/YesSql.Core/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@ public class Session : ISession
protected string _tablePrefix;
private readonly ISqlDialect _dialect;
private readonly ILogger _logger;
private readonly bool _withTracking;

public Session(Store store)
public Session(Store store, bool withTracking = true)
{
_store = store;
_tablePrefix = _store.Configuration.TablePrefix;
_dialect = store.Dialect;
_logger = store.Configuration.Logger;

_withTracking = withTracking;
_defaultState = new SessionState();
_collectionStates = new Dictionary<string, SessionState>()
{
[""] = _defaultState
[string.Empty] = _defaultState
};
}

Expand All @@ -58,7 +59,7 @@ public ISession RegisterIndexes(IIndexProvider[] indexProviders, string collecti
}
}

_indexes ??= new List<IIndexProvider>();
_indexes ??= [];

_indexes.AddRange(indexProviders);

Expand All @@ -81,7 +82,6 @@ private SessionState GetState(string collection)
return state;
}

[Obsolete]
public void Save(object entity, bool checkConcurrency = false, string collection = null)
=> SaveAsync(entity, checkConcurrency, collection).GetAwaiter().GetResult();

Expand Down Expand Up @@ -140,10 +140,7 @@ public async Task SaveAsync(object entity, bool checkConcurrency = false, string
state.IdentityMap.AddEntity(id, entity);

// Then assign a new identifier if it has one
if (accessor != null)
{
accessor.Set(entity, id);
}
accessor?.Set(entity, id);

state.Saved.Add(entity);
}
Expand Down Expand Up @@ -222,6 +219,23 @@ public void Detach(object entity, string collection)

var state = GetState(collection);

DetachInternal(entity, state);
}

public void Detach(IEnumerable<object> entries, string collection)
{
CheckDisposed();

var state = GetState(collection);

foreach (var entry in entries)
{
DetachInternal(entry, state);
}
}

private static void DetachInternal(object entity, SessionState state)
{
state.Saved.Remove(entity);
state.Updated.Remove(entity);
state.Tracked.Remove(entity);
Expand Down Expand Up @@ -277,14 +291,11 @@ private async Task SaveEntityAsync(object entity, string collection)
doc.Version = 1;
}

if (versionAccessor != null)
{
versionAccessor.Set(entity, doc.Version);
}
versionAccessor?.Set(entity, doc.Version);

doc.Content = Store.Configuration.ContentSerializer.Serialize(entity);

_commands ??= new List<IIndexCommand>();
_commands ??= [];

_commands.Add(new CreateDocumentCommand(doc, Store, collection));

Expand All @@ -300,14 +311,12 @@ private async Task UpdateEntityAsync(object entity, bool tracked, string collect
throw new ArgumentNullException(nameof(entity));
}

var index = entity as IIndex;

if (entity is Document)
{
throw new ArgumentException("A document should not be saved explicitly");
}

if (index != null)
if (entity is IIndex index)
{
throw new ArgumentException("An index should not be saved explicitly");
}
Expand Down Expand Up @@ -379,7 +388,7 @@ private async Task UpdateEntityAsync(object entity, bool tracked, string collect

oldDoc.Content = newContent;

_commands ??= new List<IIndexCommand>();
_commands ??= [];

_commands.Add(new UpdateDocumentCommand(oldDoc, Store, version, collection));
}
Expand Down Expand Up @@ -463,7 +472,7 @@ private async Task DeleteEntityAsync(object obj, string collection)
// Update impacted indexes
await MapDeleted(doc, obj, collection);

_commands ??= new List<IIndexCommand>();
_commands ??= [];

// The command needs to come after any index deletion because of the database constraints
_commands.Add(new DeleteDocumentCommand(doc, Store, collection));
Expand Down Expand Up @@ -535,7 +544,7 @@ public IEnumerable<T> Get<T>(IList<Document> documents, string collection) where
// Are all the objects already in cache?
foreach (var d in documents)
{
if (state.IdentityMap.TryGetEntityById(d.Id, out var entity))
if (_withTracking && state.IdentityMap.TryGetEntityById(d.Id, out var entity))
{
result.Add((T)entity);
}
Expand Down Expand Up @@ -568,9 +577,12 @@ public IEnumerable<T> Get<T>(IList<Document> documents, string collection) where

accessor?.Set(item, d.Id);

// track the loaded object
state.IdentityMap.AddEntity(d.Id, item);
state.IdentityMap.AddDocument(d);
if (_withTracking)
{
// track the loaded object.
state.IdentityMap.AddEntity(d.Id, item);
state.IdentityMap.AddDocument(d);
}

result.Add(item);
}
Expand Down Expand Up @@ -657,7 +669,7 @@ public async Task FlushAsync()
}

// prevent recursive calls in FlushAsync,
// when autoflush is triggered from an IndexProvider
// when auto-flush is triggered from an IndexProvider
// for instance.

if (_flushing)
Expand Down
8 changes: 4 additions & 4 deletions src/YesSql.Core/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ static Store()

private Store()
{
Indexes = new List<IIndexProvider>();
ScopedIndexes = new List<Type>();
Indexes = [];
ScopedIndexes = [];
}

/// <summary>
Expand Down Expand Up @@ -204,8 +204,8 @@ private void ValidateConfiguration()
}
}

public ISession CreateSession()
=> new Session(this);
public ISession CreateSession(bool withTracking = true)
=> new Session(this, withTracking);

public void Dispose()
{
Expand Down
Loading