CouchDb - Access replication filters in view - view

is it possible to use the replication filter feature of couchdb (http://wiki.apache.org/couchdb/Replication#Filtered_Replication) by requesting a view, f.e.:
.../_view/candidates?filter=hrtool/myfilter
This would be nice to filter the documents based on the usersession or userrole
Thanks in advance
fadh

That is possible with a _list function.
List functions are Javascript code which pre-process the view output before sending it to the client. You can modify the view output in any way, such as by filtering some rows.
function(head, req) {
// lists.filtered: filter view output by using a replication filter.
var ddoc = this; // A common trick to explicitly identify the design document.
function error(reason) {
start({"code":400, "headers":{"content-type":"application/json"}});
send(JSON.stringify({"error":reason}));
}
var filter_name = req.query.filter;
if(!filter_name)
return error("Need filter_name parameter");
var filter_src = ddoc.filters[filter_name];
if(!filter_src)
return error("Invalid filter_name: " + filter_name);
// Not 100% sure on this, you could also use new Function(args, src);
// In the worst-case, the couchapp tool has the !code tool to copy code.
var filter = eval(filter_src); // Not 100% sure on this
var row;
start({"headers":{"content-type":"application/json"}});
send('{"rows":[\r\n');
var first = true;
while(row = getRow()) {
if(filter(row)) { // Or perhaps use include_docs=true and filter(row.doc)
if(! first)
send(",\r\n");
first = false;
send(JSON.stringify(row));
}
}
send("]}\r\n");
}
Use this list "filter" like any filter function:
GET /db/_design/example/_list/filtered/candidates?filter=myfilter&include_docs=true

Related

Determine the list of IR filter's functions/operators in Oracle APEX 19.1

Is there a way to hide some Functions/Operators in the Row Filter of APEX 19.1's Interactive Report? Some end-users get confused with as many functions/operators that they do not used.
Thanks for any considerations.
While APEX doesn't support this out of the box, it is doable with JavaScript. Every time the filter dialog is displayed, content is brought from the server to the client and injected into the DOM. You just need to modify the content before the user can see it. One way to achieve this is by using the MutationObserver interface: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Here are some steps you could follow to do it (tested in APEX 19.2):
Go to the Interactive Report and set the Static ID to my-irr.
Go to the page level attributes and add the following code to the Function and Global Variable Declaration field:
function removeIRFilterOperators() {
var irRegId = 'my-irr';
var filterOperatorsToRemove = ['!=', 'ABS'];
var observer;
function detectFilterDialog(mutationsList) {
for (var mIdx = 0; mIdx < mutationsList.length; mIdx++) {
if (mutationsList[mIdx].addedNodes.length &&
mutationsList[mIdx].addedNodes[0].classList &&
mutationsList[mIdx].addedNodes[0].classList.contains('a-IRR-dialog--filter')) {
removeOperators();
}
}
}
function removeOperators() {
var anchors = document.querySelectorAll('#' + irRegId + '_row_filter_operators a');
for (var aIdx = 0; aIdx < anchors.length; aIdx++) {
if (filterOperatorsToRemove.includes(anchors[aIdx].textContent)) {
anchors[aIdx].parentElement.parentElement.removeChild(anchors[aIdx].parentElement);
}
}
}
observer = new MutationObserver(detectFilterDialog);
observer.observe(
document,
{
attributes: false,
childList: true,
subtree: true
}
);
}
removeIRFilterOperators();
The MutationObverver uses the detectFilterDialog function to detect when the filter dialog is added to the DOM. When that happens, the removeOperators function removes the specified options from the operator's list. All you need to do is update the filterOperatorsToRemove array to include the list of operators you want to remove.
If you're talking about the "Actions" menu, then yes - go to IR's attributes and enable/disable any option you want:

How to get multiple properties from objects in JXA?

Is there a way in JXA to get multiple properties from multiple objects with a single call?
For example, I want to get name and enabled property from menu items which can be done for each individual property as follows:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.name()
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.enabled()
but is it possible to get them with a single function call? Something like:
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.select('name', 'enabled')
I know, that I can iterate through the menuBarItems and collect properties from .properties() method, but this approach is too slow, that's why I'm looking for other options.
UPDATE
I'm looking for better performance, not for nicer syntax, i.e. I want properties to be retrieved in a single call to System Events.
I'd probably do it like this:
sys = Application('com.apple.systemevents');
FinderProc = sys.processes['Finder'];
FinderMenuBarItems = FinderProc.menuBars[0].menuBarItems();
Array.from(FinderMenuBarItems,x=>[x.name(),x.enabled()]);
By first converting the object to an array, this allows one to map each element and retrieve the desired properties for all in one go. The code is split over several lines for ease of reading.
EDIT: added on 2019-07-27
Following on from your comment regarding Objective-C implementation, I had a bit of time today to write a JSObjc script. It does the same thing as the vanilla JXA version above, and, yes, it clearly makes multiple function calls, which is necessary. But it's performing these functions at a lower level than System Events (which isn't involved at all here), so hopefully you'll find it more performant.
ObjC.import('ApplicationServices');
ObjC.import('CoreFoundation');
ObjC.import('Foundation');
ObjC.import('AppKit');
var err = {
'-25211':'APIDisabled',
'-25206':'ActionUnsupported',
'-25205':'AttributeUnsupported',
'-25204':'CannotComplete',
'-25200':'Failure',
'-25201':'IllegalArgument',
'-25202':'InvalidUIElement',
'-25203':'InvalidUIElementObserver',
'-25212':'NoValue',
'-25214':'NotEnoughPrecision',
'-25208':'NotImplemented',
'-25209':'NotificationAlreadyRegistered',
'-25210':'NotificationNotRegistered',
'-25207':'NotificationUnsupported',
'-25213':'ParameterizedAttributeUnsupported',
'0':'Success'
};
var unwrap = ObjC.deepUnwrap.bind(ObjC);
var bind = ObjC.bindFunction.bind(ObjC);
bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
return unwrap($.CFMakeCollectable(this[0]));
}
function getAttrValue(AXUIElement, AXAttrName) {
var e;
var _AXAttrValue = Ref();
e = $.AXUIElementCopyAttributeValue(AXUIElement,
AXAttrName,
_AXAttrValue);
if (err[e]!='Success') return err[e];
return _AXAttrValue.nsObject();
}
function getAttrValues(AXUIElement, AXAttrNames){
var e;
var _AXAttrValues = Ref();
e = $.AXUIElementCopyMultipleAttributeValues(AXUIElement,
AXAttrNames,
0,
_AXAttrValues);
if (err[e]!='Success') return err[e];
return _AXAttrValues.nsObject();
}
function getAttrNames(AXUIElement) {
var e;
var _AXAttrNames = Ref();
e = $.AXUIElementCopyAttributeNames(AXUIElement, _AXAttrNames);
if (err[e]!='Success') return err[e];
return _AXAttrNames.nsObject();
}
(() => {
const pid_1 = $.NSWorkspace.sharedWorkspace
.frontmostApplication
.processIdentifier;
const appElement = $.AXUIElementCreateApplication(pid_1);
const menuBar = getAttrValue(appElement,"AXMenuBar");
const menuBarItems = getAttrValue(menuBar, "AXChildren");
return menuBarItems.map(x => {
return getAttrValues(x, ["AXTitle", "AXEnabled"]);
});
})();

parse.com destroyAll not working

In the code following this description, I am trying to find and remove all these bad ListConfig objects that didn't have a group object set. It is correctly finding them, however it does not remove them. Is there something I am missing in the following code?
var Groups = [];
function queryForGroups(callback) {
var Group = Parse.Object.extend("Group");
var query = new Parse.Query(Group);
query.limit(1000);
query.find().then(function(result) {
Groups = result;
callback();
});
};
function removeConfigs(){
var Config = Parse.Object.extend("ListConfig");
var query = new Parse.Query(Config);
query.limit(10000);
query.notContainedIn("group", Groups);
query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
queryForGroups(function() {
removeConfigs();
});
};
removeBadConfigs();
The code could be a little cleaner with respect to mixing promises, callbacks and an unnecessary global. Beyond that, it looks like it should work as long as your data model supports it. Specifically, your ListConfig object must have a "group" property, and it must have a Parse.Object value set for that property. The most common error I've seen is something like this:
var myGroup = // a parse object of type Group
myListConfig.set("group", myGroup.id); // WRONG
myListConfig.set("group", myGroup); // RIGHT
Assuming you've got that right, then it's mysterious why you're not seeing some deletes, but here's the code cleaned up with promises...
function queryForGroups() {
let query = new Parse.Query("Group")
query.limit(1000);
return query.find();
};
function removeConfigsWithGroups(groups){
let query = new Parse.Query("Config");
query.notContainedIn("group", groups);
return query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
return queryForGroups(function(groups) {
return removeConfigsWithGroups(groups);
});
};
removeBadConfigs();
I figured it out. I removed "useMasterKey: true" because 1) it isn't needed for objects not with elevated privileges and 2) I was not running it in Cloud Code.

Getting lightswitch HTML client to load related entities

I am trying to load an entity based on a Query and allow the user to edit it. The entity loads without issues from the query, however it does not load its related entities, leaving detail pickers unfilled when loading the edit screen.
This is the code that I have:
myapp.BrowseCOAMissingHoldingCompanies.VW_ChartOfAccountsWithMissingHoldingCompanies_ItemTap_execute = function (screen) {
var accountName = screen.VW_ChartOfAccountsWithMissingHoldingCompanies.selectedItem.AccountFullName;
return myapp.activeDataWorkspace.Accounting360Data.FindChartOfAccountsMappingByAccountName(accountName)
.execute().then(function (query) {
var coa = query.results[0];
return myapp.showAddEditChartOfAccountsMapping(coa, {
beforeShown: function (addEditScreen) {
addEditScreen.ChartOfAccountsMapping = coa;
},
afterClosed: function () {
screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
}
});
});
};
Interestingly if I open the browse screen (and nothing else) of that entity type first (which does retrieve the entity), then the related entities load correctly and everything works, but I can't figure out how to make that level of load happen in this code.
One method of tackling this (and to avoid the extra query execution of a follow on refresh) is to use the expand method to include any additional navigation properties as follows:
myapp.BrowseCOAMissingHoldingCompanies.VW_ChartOfAccountsWithMissingHoldingCompanies_ItemTap_execute = function (screen) {
var accountName = screen.VW_ChartOfAccountsWithMissingHoldingCompanies.selectedItem.AccountFullName;
return myapp.activeDataWorkspace.Accounting360Data.FindChartOfAccountsMappingByAccountName(
accountName
).expand(
"RelatedEntity," +
"AnotherRelatedEntity," +
"AnotherRelatedEntity/SubEntity"
).execute().then(function (query) {
var coa = query.results[0];
return myapp.showAddEditChartOfAccountsMapping(coa, {
beforeShown: function (addEditScreen) {
addEditScreen.ChartOfAccountsMapping = coa;
},
afterClosed: function () {
screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
}
});
});
}
As you've not mentioned the name of your entity's navigational properties, I've used coa.RelatedEntity, coa.AnotherRelatedEntity and coa.AnotherRelatedEntity.SubEntity in the above example.
As covered by LightSwitch's intellisense (in msls-?.?.?-vsdoc.js) this method 'Expands results by including additional navigation properties using an expression defined by the OData $expand system query option' and it accepts a single parameter of 'An OData expand expression (a comma-separated list of names of navigation properties)'.
The reason your forced refresh of coa also populates the navigational properties is that LightSwitch's refresh method implicitly expands all navigation properties (provided you don't specify the navigationPropertyNames parameter when calling the refresh). The following shows the internal implementation of the LightSwitch refresh method (with the implicit expand behaviour executing if the navigationPropertyNames parameter is null):
function refresh(navigationPropertyNames) {
var details = this,
properties = details.properties.all(),
i, l = properties.length,
property,
propertyEntry,
query;
if (details.entityState !== _EntityState.unchanged) {
return WinJS.Promise.as();
}
if (!navigationPropertyNames) {
navigationPropertyNames = [];
for (i = 0; i < l; i++) {
property = properties[i];
propertyEntry = property._entry;
if (isReferenceNavigationProperty(propertyEntry) &&
!isVirtualNavigationProperty(propertyEntry)) {
navigationPropertyNames.push(propertyEntry.serviceName);
}
}
}
query = new _DataServiceQuery(
{
_entitySet: details.entitySet
},
details._.__metadata.uri);
if (navigationPropertyNames.length > 0) {
query = query.expand(navigationPropertyNames.join(","));
}
return query.merge(msls.MergeOption.unchangedOnly).execute();
}
However, if you take the refresh approach, you'll be performing an additional unnecessary query operation.
Entity Framework uses lazy loading by default, so related data will be loaded on demand, but in your case that's too late because the entity is already client-side a that point.
Try using the Include method in your query if you want eager loading.
Calling refresh on the details of the entity seems to do it:
return coa.details.refresh().then(function() {
return myapp.showAddEditChartOfAccountsMapping(coa, {
beforeShown: function (addEditScreen) {
addEditScreen.ChartOfAccountsMapping = coa;
},
afterClosed: function () {
screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
}
});
});
You should use load method to fetch related data from Server. At this time we don't have any ways to force msls load related data.

How can I full text search response documents and have the parent show in the view/data table

I'm at a bit of an impasse. I am working in Domino with xPages and I am trying to allow full text searching through a view including response documents but including the parent document for any responses that match the query in the view or data table. Currently I'm just using the search term in a view datasource, and then using that datasource in a view control, but any workable solution would be welcome. There may be additional search criteria on the parent document.
Any ideas?
Richard,
you can't directly use the view as data source, so you won't use the view control. You can use the data table or (probably better, since it gives you full layout control) the repeat control.
Run the search against the view in code:
var v = database.getView("yourView")
//var result = database.FTSearch(...)
var result = v.FTSearchSorted(...) // or FTSearch
var datasource = [];
var parent;
for (var doc in result) {
addResult(doc, datasource);
if (doc.isResponseDoc()) {
parent = doc.getParentDocument();
addResult(parent, datasource);
// Careful here - if the parent is part of the resultset on its own
parent.recycle();
}
doc.recycle();
}
try {
result.recycle();
v.recycle();
} catch (e) {
// We suffer silently
}
return datasource;
function addResult(doc, datasource) {
var oneResult = {};
//Adjust that to your needs
oneResult.subject = doc.getItemValueString("Subject");
oneResult.unid = doc.getUniversalId();
datasource.push(oneResult);
}
See the FTSearchSorted documentation. I typed the code off my head, so there might be little syntax snafus, ut you get the idea Don't return documents or Notes objects to the XPage and use recycle() wisely.

Resources