lib in views when using couchdb query server - couchdb-2.0

I've built a custom query server for a custom query language.
I've tried to create a design document with views map/reduce.
In those map/reduce functions (most importantly in the map function) I want to be able to reference library code.
I can see there is a lib node that can be added to the design document.
I am expecting the custom query server to receive add_lib message from CouchDB, but I have never seen this yet.
http://docs.couchdb.org/en/stable/query-server/protocol.html#add-lib
add_fun messages fail for code that depends on the library in the query server because the add_lib message has not yet been received in advance.
"The Query Server should parse, compile, and evaluate the function it
receives to make it callable later."
http://docs.couchdb.org/en/stable/query-server/protocol.html#add-fun
Since add_fun fails, this means that I am unable to save the design document.
I have viewed the following pages but I still no success:
How do I add the moment.js library to Cloudant NoSQL Design Doc on Bluemix
How do I DRY up my CouchDB views?
https://www.oreilly.com/library/view/couchdb-the-definitive/9780596158156/ch05.html
I'm doing something wrong or made a mistake it seems, your help is greatly appreciated.

The following website has the correct way to put a lib into a view.
https://caolan.org/posts/commonjs_modules_in_couchdb.html
Here's a new example for a fictitious language which is based on the working one.
{
"_id": "_design/example",
"language": "customlang",
"views": {
"lib": {
"math": "pi = 3.14"
},
"map_everything_to_pi": {
"map": "imports math; pi"
}
}
}
My problem arose because I could not save the design document when I had code in the map function that depended on the library.
By adjusting the map function to not depend on the library, I have now been able to save the document and upon querying the view, I witnessed the add_lib message get sent to the query server.
In CouchhDB 2.2.0 add_lib is sent when the view is queried, but not immediately on saving the design document where add_fun is called. In my view add_lib should be called before for each lib before CouchDB sends the add_fun messages.
This fact makes it impossible for add_fun to evaluate / precompile the code since the library is not yet known. add_lib must succeed in order for the design document to save, so it is impossible to save the design document.
I probably need to raise a bug tracker issue.

Related

Creating API - general question about verbs

I decided to move my application to a new level by creating a RESTful API.
I think I understand the general principles, I have read some tutorials.
My model is pretty simple. I have Projects and Tasks.
So to get the lists of Tasks for a Project you call:
GET /project/:id/tasks
to get a single Task:
GET /task/:id
To create a Task in a Project
CREATE /task
payload: { projectId: :id }
To edit a Task
PATCH /task/:taskId
payload: { data to be changed }
etc...
So far, so good.
But now I want to implement an operation that moves a Task from one Project to another.
My first guess was to do:
PATCH /task/:taskId
payload: { projectId: :projectId }
but I do not feel comfortable with revealing the internal structure of my backend to the frontend.
Of course, it is just a convention and has nothing to do with security, but I would feel better with something like:
PATCH /task/:taskId
payload: { newProject: :projectId }
where there is no direct relation between the 'newProject' and the real column in the database.
But then, the next operation comes.
I want to copy ALL tasks from Project A to Project B with one API call.
PUT /task
payload: { fromProject: :projectA, toProject: :projectB }
Is it a correct RESTful approach? If not - what is the correct one?
What is missing here is "a second verb".
You can see that we are creating a new task(s) hence: 'PUT' but we also 'copy' which is implied by fromProject and toProject.
Is it a correct RESTful approach? If not - what is the correct one?
To begin, think about how you would do it in a web browser: the world wide web is the reference implementation for the REST architectural style.
One of the first things that you will notice: on the web, we are almost always using POST to make changes to the server. You fill in a form in a browser, submit the form, the browser takes information from the input controls of the form to create the HTTP request body, the server figures out how to do the work that is described.
What we have in HTTP is a standardized semantics for messages that manipulate individual documents ("resources"); doing useful work is a side effect of manipulating documents (see Webber 2011).
The trick of POST is that it is the method whose standardized meaning includes the case where "this method isn't worth standardizing" (see Fielding 2009).
POST /2cc3e500-77d5-4d6d-b3ac-e384fca9fb8d
Content-Type: text/plain
Bob,
Please copy all of the tasks from project A to project B
The request line and headers here are metadata in the transfer of documents over a network domain. That is to say, that's the information we are sharing with the general purpose HTTP application.
The actual underlying business semantics of the changes we are making to documents is not something that the HTTP application cares about -- that's the whole point, after all.
That said - if you are really trying to do manipulation of document hierarchies in general purpose and standardized way, then you should maybe see if your problem is a close match to the WebDAV specifications (RFC 2291, RFC 4918, RFC 3253, etc).
If the constraints described by those documents are acceptable to you, then you may find that a lot of the work has already been done.

Xpages: Doc locking error

Trying to implement document locking in a small database. We use it in XPiNC. I found Julian Boss's excellent answer in in which he provides a javascript function that seems to have everything I need.
So in a small test database I added the script library and added as a resource. In my edit button I have the following code:
var ntdDoc:NotesDocument = document1.getDocument();
documentLocking.lockDoc(ntdDoc)
But this throws the following error:
Script interpreter error, line=2, col=17: [TypeError] Error calling method 'lockDoc(lotus.domino.local.Document)' on an object of type 'Object [JavaScript Object]'
1: var ntdDoc:NotesDocument = document1.getDocument();
-> 2: documentLocking.lockDoc(ntdDoc)
I have tried passing in the data source and that didn't work either. What do I need to pass?
That answer is a few years old and I'm not sure of the current recommendations around storing SSJS global variables. Storing SSJS functions as objects is no longer recommended.
Domino has in-built document locking, which is equally valid for use in XPages. Mastering XPages Second Edition had a very good and comprehensive walk-through of how to use the document locking. The only (potential) gotcha is that you need to lock the document before deleting it - because to delete it you need to modify it, and to modify it you need to lock it.

noflo-ui: Load and save projects/graphs/components from external database or api

I'm trying to create a custom build of noflo-ui that is effectively only a graph editor. Don't need it to connect to any runtimes.
I'm struggling to find where I can inject this code as it appears part of noflo-ui is written in noflo itself and I cannot find the scripts for those pieces.
For example, in graphs/main.fbp, there is this line:
'user,main,project,github,runtime,context' -> ROUTES Dispatch
Three questions on this:
Where is the source behind the Dispatch component?
If I add my own interface elements to Load data from an external api, where would be the best place to inject that data?
I see a lot of event driven code, so I'm guessing I would add a new polymer element, do my ajax call, the emit or fire something. I believe this is what happens when connecting to a noflo-nodejs runtime; I've traced the connection to line 51312 in a built noflo-ui.js
return port.send({
componentDefinition: definition
});
... but I can't figure out where it goes past here. A port on the main.fbp graph? As per my 1st question, I cannot find the source behind these core graphs.
And this leads to my last question
The code I pasted above from noflo-ui, I cannot find this code anywhere pre-build. I even searched the entire project tree for "componentDefinition: definition". Where is this coming from?
Any pointers on this would be greatly appreciated! Thanks
The FBP runtime protocol is the primary extension point of noflo-ui. You can implement a "runtime" which just provides components and graphs (for instance from a database), without a way to run these.
A network:persist message to let the UI indicate that "this is a good point to save the graphs" has been specced but is currently not implemented. For now you can just autosave latest state.

Is it possible to write a plugin for Glimpse's existing SQL tab?

Is it possible to write a plugin for Glimpse's existing SQL tab?
I'm trying to log my SQL queries and the currently available extensions don't support our in-house SQL libary. I have written a custom plugin which logs what I want, but it has limited functionality and it doesn't integrate with the existing SQL tab.
Currently, I'm logging to my custom plugin using a single helper method inside my DAL's base class. This function looks takes the SqlCommand and Duration in order to show data on my custom tab:
// simplified example:
Stopwatch sw = Stopwatch.StartNew();
sqlCommand.Connection = sqlConnection;
sqlConnection.Open();
object result = sqlCommand.ExecuteScalar();
sqlConnection.Close();
sw.Stop();
long duration = sw.ElapsedMilliseconds;
LogSqlActivity(sqlCommand, null, duration);
This works well on my 'custom' tab but unfortunately means I don't get metrics shown on Glimpse's HUD:
Is there a way I can provide Glimpse directly with the info it needs (in terms of method names, and parameters) so it displays natively on the SQL tab?
The following advise is based on the fact that you can't use DbProviderFactory and you can't use a proxied SqlCommand, etc.
The data that appears in the "out-of-the-box" SQL tab is based on messages of given types been published through our internal Message Broker (see below on information on this). Because of the above limitations in your case, to get things lighting up correctly (i.e. your data showing up in HUD and the SQL tab), you will need to simulate the work that we do under the covers when we publish these messages. This shouldn't be that difficult and once done, should just work moving forward.
If you have a look at the various proxies we have here you will be above to see what messages we publish in what circumstances. Here are some highlights:
DbCommand
Log command start - here
Log command error - here
Log command end - here
DbConnection:
Log connection open - here
Log connection closed - here
DbTransaction
Log Started - here
Log committed - here
Log rollback - here
Other
Command row count here - Glimpses calculates this at the DbDataReader level but you could do it elsewhere as well
Now that you have an idea of what messages we are expecting and how we generate them, as long as you pass in the right data when you publish those messages, everything should just light up - if you are interested here is the code that looks for the messages that you will be publishing.
Message Broker: If you at the GlimpseConfiguration here you will see how to access the Broker. This can be done statically if needed (as we do here). From here you can publish the messages you need.
Helpers: For generating some of the above messages, you can use the helpers inside the Support class here. I would have shifted all the code for publishing the actual messages to this class, but I didn't think there would be too many people doing what you are doing.
Update 1
Starting point: With the above approach you shouldn't need to write your own plugin. You should just be able to access the broker GlimpseConfiguration.GetConfiguredMessageBroker() (make sure you check if its null, which it is if Glimpse is turned off, etc) and publish your messages.
I would imagine that you would put the inspection that leverages the broker and published the messages, where ever you have knowledge of the information that needs to be collected (i.e. inside your custom lib). Normally this would require references inside your lib to glimpse (which you may not want), so to protect against this, from your lib, you would call a proxy (which could be another VS proj) that has the glimpse dependency. Hence your ado lib only has references to your own code.
To get your toes wet, try just publishing a couple of fake connection and command messages. Assuming the broker you get from GlimpseConfiguration.GetConfiguredMessageBroker() isn't null, these should just show up. Then you can work towards getting real data into it from your lib.
Update 2
Obsolete Broker Access
Its marked as obsolete because its going to change in v2. You will still be able to do what you need to do, but the way of accessing the broker has changed. For what you currently need to do this is ok.
Sometimes null
As you have found this is really dependent on where in the page lifecycle you are currently at. To get around this, I would probably change my original recommendation a little.
In the code where you are currently creating messages and pushing them to the message bus, try putting them into HttpContext.Current.Items. If you haven't used it before, this is a store which asp.net provides out of the box which lasts the lifetime of a given request. You could have a list that you put in there, still create the message objects that you are doing, but put them into that list instead of pushing them through the broker.
Then, create a HttpModule (its really simple to do) which taps into the PostLogRequest event. Within this handler, you would pull the list out of the context, iterate through it and push the message into the message broker (accessing the same way you have been).

Why is Mage_Persistent breaking /api/wsdl?soap

I get the following error within Magento CE 1.6.1.0
Warning: session_start() [<a href='function.session-start'>function.session-start</a>]: Cannot send session cookie - headers already sent by (output started at /home/dev/env/var/www/user/dev/wdcastaging/lib/Zend/Controller/Response/Abstract.php:586) in /home/dev/env/var/www/user/dev/wdcastaging/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 119
when accessing /api/soap/?wsdl
Apparently, a session_start() is being attempted after the entire contents of the WSDL file have already been output, resulting in the error.
Why is magento attempting to start a session after outputting all the datums? I'm glad you asked. So it looks like controller_front_send_response_after is being hooked by Mage_Persistent in order to call synchronizePersistentInfo(), which in turn ends up getting that session_start() to fire.
The interesting thing is that this wasn't always happening, initially the WSDL loaded just fine for me, initially I racked my brains to try and see what customization may have been made to our install to cause this, but the tracing I've done seems to indicate that this is all happening entirely inside of core.
We have also experienced a tiny bit of (completely unrelated) strangeness with Mage_Persistent which makes me a little more willing to throw my hands up at this point and SO it.
I've done a bit of searching on SO and have found some questions related to the whole "headers already sent" thing in general, but not this specific case.
Any thoughts?
Oh, and the temporary workaround I have in place is simply disabling Mage_Persistent via the persistent/options/enable config data. I also did a little bit of digging as to whether it might be possible to observe an event in order to disable this module only for the WSDL controller (since that seems to be the only one having problems), but it looks like that module relies exclusively on this config flag to determine it's enabled status.
UPDATE: Bug has been reported: http://www.magentocommerce.com/bug-tracking/issue?issue=13370
I'd report this is a bug to the Magento team. The Magento API controllers all route through standard Magento action controller objects, and all these objects inherit from the Mage_Api_Controller_Action class. This class has a preDispatch method
class Mage_Api_Controller_Action extends Mage_Core_Controller_Front_Action
{
public function preDispatch()
{
$this->getLayout()->setArea('adminhtml');
Mage::app()->setCurrentStore('admin');
$this->setFlag('', self::FLAG_NO_START_SESSION, 1); // Do not start standart session
parent::preDispatch();
return $this;
}
//...
}
which includes setting a flag to ensure normal session handling doesn't start for API methods.
$this->setFlag('', self::FLAG_NO_START_SESSION, 1);
So, it sounds like there's code in synchronizePersistentInf that assumes the existence of a session object, and when it uses it the session is initialized, resulting in the error you've seen. Normally, this isn't a problem as every other controller has initialized a session at this point, but the API controllers explicitly turns it off.
As far as fixes go, your best bet (and probably the quick answer you'll get from Magento support) will be to disable the persistant cart feature for the default configuration setting, but then enable it for specific stores that need it. This will let carts
Coming up with a fix on your own is going to be uncharted territory, and I can't think of a way to do it that isn't terribly hacky/unstable. The most straight forward way would be a class rewrite on the synchronizePersistentInf that calls it's parent method unless you've detected this is an API request.
This answer is not meant to replace the existing answer. But I wanted to drop some code in here in case someone runs into this issue, and comments don't really allow for code formatting.
I went with a simple local code pool override of Mage_Persistent_Model_Observer_Session to exit out of the function for any URL routes that are within /api/*
Not expecting this fix to need to be very long-lived or upgrade-friendly, b/c I'm expecting them to fix this in the next release or so.
public function synchronizePersistentInfo(Varien_Event_Observer $observer)
{
...
if ($request->getRouteName() == 'api') {
return;
}
...
}