/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Nodeset"/>.</returns> protected override Nodeset DoRetrieveNodeset(IMansionContext context, Query query) { // retrieve the nodeset var nodeset = DecoratedRepository.RetrieveNodeset(context, query); // attach the event handler to each node foreach (var node in nodeset.Nodes) { // get the node listeners var listeners = GetListeners(context, node.Pointer.Type); // attach missing property event var node1 = node; node.MissingProperty += (sender, args) => { foreach (var nodeListener in listeners) { object value; if (!nodeListener.TryResolveMissingProperty(context, node1, args.PropertyName, out value)) continue; args.Value = value; break; } }; } // return the nodeset return nodeset; }
/// <summary> /// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="parameters">The parameters which to process.</param> /// <param name="query">The <see cref="Query"/> in which to set the parameters.</param> protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query) { // check for search string where; if (parameters.TryGetAndRemove(context, "sqlWhere", out where) && !string.IsNullOrEmpty(where)) query.Add(new SqlWhereSpecification(where)); }
/// <summary> /// Performs a search using the specified <paramref name="query"/>. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> on which to search.</param> /// <returns>Returns the resulting <see cref="RecordSet"/>.</returns> /// <exception cref="ArgumentNullException">Thrown if one of the parameters is null.</exception> /// <exception cref="ConnectionException">Thrown if a error occurred while executing the search query.</exception> public RecordSet Search(IMansionContext context, Query query) { // validate arguments if (context == null) throw new ArgumentNullException("context"); if (query == null) throw new ArgumentNullException("query"); // find the root type for this query var rootType = query.TypeHints.FindCommonAncestor(context); // resolve the index definitions of this record var indexDefinitions = indexDefinitionResolver.Resolve(context, rootType); // determine the index which to use to perform the search var indexDefinitionTypeMappingPair = SelectBestIndexForQuery(rootType, query, indexDefinitions); // create a search descriptor var search = new SearchQuery(indexDefinitionTypeMappingPair.Item1, indexDefinitionTypeMappingPair.Item2); // map all the query components to the search descriptor foreach (var component in query.Components) converters.Elect(context, component).Map(context, query, component, search); // execute the query return Search(context, search); }
/// <summary> /// Retrieves a single node from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Node"/>.</returns> protected override Node DoRetrieveSingleNode(IMansionContext context, Query query) { // retrieve the node var node = DecoratedRepository.RetrieveSingleNode(context, query); if (node == null) return null; // get the node listeners var listeners = GetListeners(context, node.Pointer.Type); // attach missing property event node.MissingProperty += (sender, args) => { foreach (var nodeListener in listeners) { object value; if (!nodeListener.TryResolveMissingProperty(context, node, args.PropertyName, out value)) continue; args.Value = value; break; } }; // return the node return node; }
/// <summary> /// Retrieves a <see cref="Dataset"/> from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Dataset"/> containing the results.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> or <paramref name="query"/> is null.</exception> protected override RecordSet DoRetrieve(IMansionContext context, Query query) { // select the engine var searcher = SelectQueryEngine(context, query); // execute the query return searcher.Retrieve(context, query); }
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Nodeset"/>.</returns> protected override Nodeset DoRetrieveNodeset(IMansionContext context, Query query) { // check if this query is not cacheable if (!query.IsCacheable()) return DecoratedRepository.RetrieveNodeset(context, query); // create the cache key for this node var cacheKey = query.CalculateCacheKey("Nodeset_Query_"); // return the node return cachingService.GetOrAdd(context, cacheKey, () => DecoratedRepository.RetrieveNodeset(context, query).AsCacheableObject(query)); }
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns></returns> public Nodeset RetrieveNodeset(IMansionContext context, Query query) { // validate arguments if (context == null) throw new ArgumentNullException("context"); if (query == null) throw new ArgumentNullException("query"); CheckDisposed(); // invoke template method return DoRetrieveNodeset(context, query); }
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns></returns> protected override Nodeset DoRetrieveNodeset(IMansionContext context, Query query) { // create the connection and command using (var connection = CreateConnection()) using (var command = context.Nucleus.CreateInstance<SelectNodeCommand>()) { // init the command with the query command.Prepare(context, connection, query); // execute the command return command.Execute(context); } }
/// <summary> /// Requests this voter to cast a vote. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="subject">The subject.</param> /// <returns>Returns the result of the vote.</returns> protected override VoteResult DoVote(IMansionContext context, Query subject) { // check if ElasticSearch is disabled if (!Configuration.IsEnabled) return VoteResult.Refrain; // find the root type for this query var rootType = subject.TypeHints.FindCommonAncestor(context); // resolve the index definitions of this record var indexDefinitions = indexDefinitionResolver.Resolve(context, rootType); // check if there is an index defined for this query return indexDefinitions.Any() ? VoteResult.MediumInterest : VoteResult.Refrain; }
/// <summary> /// Turns the given <paramref name="obj"/> in a cacheable object. /// </summary> /// <param name="obj">The <see cref="Record"/> for which to create the cacheable object.</param> /// <param name="query">The <see cref="Query"/> which resulted in the given <paramref name="obj"/>.</param> /// <returns>Returns the <see cref="CachedObject{TObject}"/>.</returns> public static CachedObject<Record> AsCacheableObject(this Record obj, Query query) { // validate arguments if (query == null) throw new ArgumentNullException("query"); // create a new cacheable object var cacheable = new CachedObject<Record>(obj); // if the result is found, cache it by it's id ChildOfSpecification childOfSpecification; if (obj != null) { // generate an ID for this specific record var recordIdCacheKey = obj.CalculateIdCacheKey(); // add that cache key as the dependency cacheable.Add((StringCacheKeyDependency) recordIdCacheKey); } else if (query.TryGetSpecification(out childOfSpecification)) { // cache on the parent tree Id var parentTreeIdCacheKey = childOfSpecification.ParentPointer.CalculateTreeIdCacheKey(); // add that cache key as the dependency cacheable.Add((StringCacheKeyDependency) parentTreeIdCacheKey); } else { // add the repository modified cache key cacheable.Add(CachingRepositoryDecorator.RepositoryModifiedDependency); } // return the cacheable object return cacheable; }
/// <summary> /// Turns the given <paramref name="obj"/> in a cacheable object. /// </summary> /// <param name="obj">The <see cref="Nodeset"/> for which to create the cacheable object.</param> /// <param name="query">The <see cref="Query"/> which resulted in the given <paramref name="obj"/>.</param> /// <returns>Returns the <see cref="CachedObject{TObject}"/>.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="obj"/> is null.</exception> public static CachedObject<Nodeset> AsCacheableObject(this Nodeset obj, Query query) { // validate arguments if (obj == null) throw new ArgumentNullException("obj"); if (query == null) throw new ArgumentNullException("query"); // create a new cacheable object var cacheable = new CachedObject<Nodeset>(obj); ChildOfSpecification childOfSpecification; if (query.TryGetSpecification(out childOfSpecification)) { // cache on the parent tree Id var parentTreeIdCacheKey = childOfSpecification.ParentPointer.CalculateTreeIdCacheKey(); // add that cache key as the dependency cacheable.Add((StringCacheKeyDependency) parentTreeIdCacheKey); } else { // add the repository modified cache key cacheable.Add(CachingRepositoryDecorator.RepositoryModifiedDependency); } // return the cacheable object return cacheable; }
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Nodeset"/>.</returns> protected override Nodeset DoRetrieveNodeset(IMansionContext context, Query query) { return searcher.SearchNodes(context, query); }
/// <summary> /// Retrieves a single node from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Node"/>.</returns> protected override Node DoRetrieveSingleNode(IMansionContext context, Query query) { return searcher.SearchNodes(context, query).Nodes.FirstOrDefault(); }
/// <summary> /// Retrieves a <see cref="Dataset"/> from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Dataset"/> containing the results.</returns> protected override RecordSet DoRetrieve(IMansionContext context, Query query) { return searcher.Search(context, query); }
/// <summary> /// Retrieves a single record from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Record"/> or null when no result is found.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> or <paramref name="query"/> is null.</exception> protected override Record DoRetrieveSingle(IMansionContext context, Query query) { return searcher.Search(context, query).Records.FirstOrDefault(); }
/// <summary> /// Copies an existing node in this repository to a new node. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="pointer">The pointer to the node which will be copied.</param> /// <param name="targetParentPointer">The pointer to the parent to which the copied node is added.</param> /// <returns>Returns the copied node.</returns> protected override Node DoCopyNode(IMansionContext context, NodePointer pointer, NodePointer targetParentPointer) { // create a query to retrieve the new node var selectQuery = new Query(); // build the query using (var connection = CreateConnection()) using (var transaction = connection.BeginTransaction()) { // retrieve the nodes // TODO: retrieve the nodes within the same transaction var nodeToCopy = RetrieveSingleNode(context, new Query().Add(new IsPropertyEqualSpecification("id", pointer.Id))); if (nodeToCopy == null) throw new ArgumentNullException(string.Format("Could not find node with pointer '{0}'", pointer)); var targetParentNode = RetrieveSingleNode(context, new Query().Add(new IsPropertyEqualSpecification("id", targetParentPointer.Id))); if (targetParentNode == null) throw new ArgumentNullException(string.Format("Could not find node with pointer '{0}'", targetParentPointer)); // create the copy query using (var command = context.Nucleus.CreateInstance<CopyNodeCommand>()) { // init the command command.Prepare(context, connection, transaction, nodeToCopy, targetParentNode); // execute the command try { // execute the query var copiedNodeId = command.Execute(); selectQuery.Add(new IsPropertyEqualSpecification("id", copiedNodeId)); // woohoo it worked! transaction.Commit(); } catch (Exception) { // something terrible happened, revert everything transaction.Rollback(); throw; } } } // return the created node return RetrieveSingleNode(context, selectQuery); }
/// <summary> /// Retrieves a <see cref="Dataset"/> from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Dataset"/> containing the results.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> or <paramref name="query"/> is null.</exception> protected abstract RecordSet DoRetrieve(IMansionContext context, Query query);
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns></returns> protected abstract Nodeset DoRetrieveNodeset(IMansionContext context, Query query);
/// <summary> /// Select the best <see cref="BaseQueryEngine"/> to execute the <paramref name="query"/> on. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which needs to be executed.</param> /// <returns>Returns the <see cref="BaseQueryEngine"/> which to use to execute <paramref name="query"/>.</returns> private BaseQueryEngine SelectQueryEngine(IMansionContext context, Query query) { return queryEngines.Elect(context, query, engines => engines.OrderByPriority().First()); }
/// <summary> /// Retrieves a <see cref="Dataset"/> from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Dataset"/> containing the results.</returns> protected override RecordSet DoRetrieve(IMansionContext context, Query query) { return repository.Retrieve(context, query); }
/// <summary> /// Retrieves a single node from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Node"/>.</returns> protected override Node DoRetrieveSingleNode(IMansionContext context, Query query) { return repository.RetrieveSingleNode(context, query); }
/// <summary> /// Requests this voter to cast a vote. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="subject">The subject.</param> /// <returns>Returns the result of the vote.</returns> protected override VoteResult DoVote(IMansionContext context, Query subject) { IQueryComponentConverter converter; return subject.Components.All(component => Election<IQueryComponentConverter, QueryComponent>.TryElect(context, converters, component, out converter)) ? VoteResult.LowInterest : VoteResult.Refrain; }
/// <summary> /// Retrieves a single node from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns the node.</returns> protected abstract Node DoRetrieveSingleNode(IMansionContext context, Query query);
/// <summary> /// Retrieves a single record from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Record"/> or null when no result is found.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> or <paramref name="query"/> is null.</exception> protected override Record DoRetrieveSingle(IMansionContext context, Query query) { return DecoratedRepository.RetrieveSingle(context, query); }
/// <summary> /// Retrieves a single record from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a single <see cref="Record"/> or null when no result is found.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> or <paramref name="query"/> is null.</exception> protected abstract Record DoRetrieveSingle(IMansionContext context, Query query);
/// <summary> /// Retrieves multiple nodes from this repository. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="query">The <see cref="Query"/> which to execute.</param> /// <returns>Returns a <see cref="Nodeset"/>.</returns> protected override Nodeset DoRetrieveNodeset(IMansionContext context, Query query) { return DecoratedRepository.RetrieveNodeset(context, query); }
/// <summary> /// Selects the best <see cref="IndexDefinition"/> for the given <paramref name="query"/>. /// </summary> /// <param name="type">The <see cref="ITypeDefinition"/>.</param> /// <param name="query">The <see cref="Query"/>.</param> /// <param name="indexDefinitions">The candidate <see cref="IndexDefinition"/>s.</param> /// <returns>Returns a<see cref="Tuple{IndexDefinition,TypeMapping}"/> containing the <see cref="IndexDefinition"/> and <see cref="TypeMapping"/>.</returns> private static Tuple<IndexDefinition, TypeMapping> SelectBestIndexForQuery(ITypeDefinition type, Query query, IEnumerable<IndexDefinition> indexDefinitions) { // first get the type mapping for the root type var indexDefinitionTypeMappingPairs = indexDefinitions.Select(candidate => new Tuple<IndexDefinition, TypeMapping>(candidate, candidate.FindTypeMapping(type.Name))); // return the type mapping which has to most fields matching the query return indexDefinitionTypeMappingPairs.OrderByDescending(pair => pair.Item2.Properties.Select(prop => prop.Key).Intersect(query.PropertyHints, StringComparer.OrdinalIgnoreCase).Count()).First(); }
/// <summary> /// Moves an existing node in this repository to a new parent node. /// </summary> /// <param name="context">The <see cref="IMansionContext"/>.</param> /// <param name="pointer">The pointer to the node which will be moved.</param> /// <param name="newParentPointer">The pointer to the parent to which the node is moved.</param> /// <returns>Returns the moved node.</returns>m protected override Node DoMoveNode(IMansionContext context, NodePointer pointer, NodePointer newParentPointer) { // build the query using (var connection = CreateConnection()) using (var transaction = connection.BeginTransaction()) using (var command = context.Nucleus.CreateInstance<MoveNodeCommand>()) { // init the command command.Prepare(context, connection, transaction, pointer, newParentPointer); // execute the command try { // execute the query command.Execute(); // woohoo it worked! transaction.Commit(); } catch (Exception) { // something terrible happened, revert everything transaction.Rollback(); throw; } } // return the moved node var selectQuery = new Query().Add(new IsPropertyEqualSpecification("id", pointer.Id)); return RetrieveSingleNode(context, selectQuery); }