Filters that allows for comparison of model properties - loopbackjs

Using loopback where filter would be a lot more versatile if you could do queries that relate the model's instance properties to one another:
{
where: {
modelId: id,
someProp: {
neq: {
property: someOtherProp
}
}
}
}
The neq I'm referencing denotes 'not equal' .. eg. someProp != someOtherProp or 'bigger' someProp > someOtherProp .
Right now, If i want to compare 2 properties I need to go to SQL and do a manual query there. Can this be a feature for future release?

Related

How to update local data after mutation?

I want to find a better way to update local component state after executing mutation. I'm using svelte-apollo but my question is about basic principles. I have watchQuery which get list of items and returns ObservableQuery in component.
query GetItems($sort: String, $search: String!) {
items(
sort: $sort
where: { name_contains: $search }
) {
id
name
item_picture{
pictures{
url
previewUrl
}
}
description
created_at
}
}
In component I call it:
<script>
$: query = GetItems({
variables: {
sort: 'created_at:DESC',
search
}
});
</script>
...
{#each $query.data?.items || [] as item, key (item.id)}
<div>
<Item
deleteItem={dropItem}
item={item}
setActiveItem={setActiveItem}
/>
</div>
{/each}
...
And I have addItem mutation.
mutation addItem($name: String!, $description: String) {
createItem(
input: { data: { name: $name, description: $description } }
) {
item {
name
description
}
}
}
I just simply want to update local state and add new item to an observable query result after addItem mutation, without using refetchQueries (because I don't want to get all list by network when I just added one item).
I seen this item in cache but my view is not updated.
P.S. If you have similar problems and some ways to solve it, be glad to see some cases from you.
I believe in this case, you could use the cache.modify function to modify the cache directly if you’re looking to skip the network request from refetchQueries. Would that work for your use case? https://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updates
If you don’t mind the network request, I like using cache.evict to evict the data in the cache that I know changed personally. I prefer that to refetchQueries in most cases because it refetches all queries that used that piece of data, not just the queries I specify.

cfwheels - removing unused composite key pairs

I've got an issue with a nested property that uses a composite key.
When I'm editing a model that has multiple instances of nested properties (with a composite key) and want to update it to have fewer by leaving them blank, cfWheels does not remove the ones that are not used anymore, and maintains the old value. Is there a way of forcing the deletion of these without calling delete on the nested model?
I've been doing by deleting all nested properties, and then update() creates the records that are needed, but the big issue with that is that when I have code in between that fails, It just deletes the items, which as you know can be very very bad.
In your init call to nestedProperties(), try adding the allowDelete option:
nestedProperties(association="comments", allowDelete=true);
Then if a model within that collection has a property called _delete that is set to true, CFWheels will delete that record.
I'm not sure of your model because you don't include any details in your question, but you could probably run a beforeValidationOnUpdate callback that checks criteria on the nested models and sets _delete = true when the record needs to be deleted.
For example:
// Post.cfc
component extends="Model" {
function init() {
hasMany("comments");
nestedProperties(association="comments", allowDelete=true);
beforeValidationOnUpdate("removeBlankComments");
}
private function removeBlankComments() {
if (StructKeyExists(this, "comments") && IsArray(this.comments)) {
for (local.i = 1; local.i < ArrayLen(this.comments); local.i++) {
if (!Len(this.comments[local.i].message)) {
this.comments[local.i]._delete = true;
}
}
}
}
}
Not sure if this will give you any problems with the nested composite key. Sometimes nested properties are a little kludgy with "special" cases.
i think you forgot to mention allowDelete attribute in nestedProperties by defalut allowDelete is set as false in wheels and does not delete the composite key form table. you have to set it true.
for example in model you have to do some thing like this.
<cfset hasMany(name="campaignlanguages",shortcut="languages", dependent="deleteAll") />
<cfsetnestedProperties(associations="campaignlanguages",allowDelete="true")/>
you can find more details here

zf2 acl doctrine 2

Actually using Zend Framework 2, I am looking for a way to implement a performant ACL strategy based on a database.
The whole idea is to directly filter the DQL queries depending on the currently logged in user, and it's permissions.
I found an implementation of this mecanisme in Symfony 2 http://symfony.com/doc/current/cookbook/security/acl_advanced.html, in this case one table seems to store for each user if he has access to a single row, so we can easily dynamically load only allowed rows by joining this table.
To synthesize,I am looking for a way to define access rules to entities based on criterias, but want to be able to get results in a single query to be able to do some ordering, and pagination.
Are there any ZF2 modules to resolve this case ?
It looks like integrating the SF2 security component as standalone is not an option: Security component from Symfony 2.0 as standalone
You have to use doctrine filter for load things for current member
example of my codes adding the filter for member query :
$em = $sm->get('doctrine.entitymanager.orm_default');
$ormconfig = $sm->get('doctrine.configuration.orm_default');
$ormconfig->addFilter("member", "\PatrickCore\Script\ORM\Functional\MemberAccessFilter");
//
$currentUser = $membersService->getCurrentUser();
$uid = $currentUser->getId();
$filter = $em->getFilters()->enable("member");
$filter->setParameter('member', $uid);
and this file \PatrickCore\Script\ORM\Functional\MemberAccessFilter :
<?php
namespace PatrickCore\Script\ORM\Functional;
use Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\Filter\SQLFilter;
class MemberAccessFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
// Check if the entity implements the LocalAware interface
if (!$targetEntity->reflClass->implementsInterface('\PatrickCore\Entity\MemberAccessAware')) {
return "";
}
return $targetTableAlias.'.member_id = ' . $this->getParameter('member'); // getParameter applies quoting automatically
}
}

Adding a search box to filter a list of results in Symfony?

I need to put a search box within a list of objects as a result of a typical indexSuccess action in Symfony. The goal is simple: filter the list according to a criteria.
I've been reading the Zend Lucene approach in Jobeet tutorial, but it seems like using a sledge-hammer to crack a nut (at least for my requirements).
I'm more interested in the auto-generated admin filter forms but I don't know how to implement it in a frontend.
I could simply pass the search box content to the action and build a custom query, but is there any better way to do this?
EDIT
I forgot to mention that I would like to have a single generic input field instead of an input field for each model attribute.
Thanks!
I'm using this solution, instead of integrating Zend Lucene I manage to use the autogenerated Symonfy's filters. This is the way i'm doing it:
//module/actions.class.php
public function executeIndex(sfWebRequest $request)
{
//set the form filter
$this->searchForm = new EmployeeFormFilter();
//bind it empty to fetch all data
$this->searchForm->bind(array());
//fetch all
$this->employees = $this->searchForm->getQuery()->execute();
...
}
I made a search action which does the search
public function executeSearch(sfWebRequest $request)
{
//create filter
$this->searchForm = new EmployeeFormFilter();
//bind parameter
$fields = $request->getParameter($this->searchForm->getName());
//bind
$this->searchForm->bind($fields);
//set paginator
$this->employees = $this->searchForm->getQuery()->execute();
...
//template
$this->setTemplate("index");
}
It's important that the search form goes to mymodule/search action.
Actually, i'm also using the sfDoctrinePager for paginate setting directly the query that the form generate to get results properly paginated.
If you want to add more fields to the search form check this :)
I finally made a custom form using the default MyModuleForm generated by Symfony
public function executeIndex {
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
but displaying only a custom field:
<div id="search_box">
<input type="text" name="criteria" id="search_box_criteria" value="Search..." />
<?php echo link_to('Search', '#my_module_search?criteria=') ?>
</div>
Then I created a route named #my_module_search linked to the index action:
my_module_search:
url: my_module/search/:criteria
param: { module: my_module, action: index }
requirements: { criteria: .* } # Terms are optional, show all by default
With Javascript (jQuery in this case) I append the text entered to the criteria parameter in the href attribute of the link:
$('#search_box a').click(function(){
$(this).attr('href', $(this).attr('href') + $(this).prev().val());
});
And finally, back to the executeIndex action, I detect if text was entered and add custom filters to the DoctrineQuery object:
public function executeIndex {
...
// Deal with search criteria
if ( $text = $request->getParameter('criteria') ) {
$query = $this->pager->getQuery()
->where("MyTable.name LIKE ?", "%$text%")
->orWhere("MyTable.remarks LIKE ?", "%$text%")
...;
}
$this->pager->setQuery($query);
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
Actually, the code is more complex, because I wrote some partials and some methods in parent classes to reuse code. But this is the best I can came up with.

How do I add custom column to existing WSS list template

I need to use feature stapler to add some text columns to Posts list inside OOTB blog site definition. I plan not to use site columns, but only to add those columns to list (I don't use site columns because I have multiple site collections and there will be only one Posts list per site collection, so site columns are not very reusable in this case). My question is: How do I achieve this?
Perhaps you can create a feature that uses the object model from the feature receiver to add (and remove as appropriate) the columns to just the specific list when the feature is activated.
I would use the XML Schema approach for creating the columns in order to ensure the same GUID for each column. See
The best solution is to create a hidden custom action for Posts List. I'm posting a simplified version here
Elements.xml:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="XXXXXXXX"
RegistrationType="List"
RegistrationId="101"
Rights="Open"
Location="ViewToolbar"
Sequence="110"
Title="Hidden Settings Button"
ControlAssembly="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX"
ControlClass="MyLib.MyClass"
/>
<FeatureSiteTemplateAssociation Id="XXXXXXX" TemplateName="YOUR_BLOG_SITE_TEMPLATE_NAME" />
MyClass.cs:
[DefaultProperty("Text")]
[ToolboxData("<{0}:MyClass runat=server></{0}:MyClass>")]
public class MyClass : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
protected override void OnLoad(EventArgs e)
{
SPList list = SPContext.Current.List;
if (list != null)
{
list.Fields.Add(XXX, XXX, XXX);
list.Update();
}
}
}
I cannot see what benefit I have from creating custom action for posts list. Both posts are helpful, but I'll probably create custom feature for that.