-
Notifications
You must be signed in to change notification settings - Fork 66
Adding Custom Build Steps
The Roxy Deployer does a lot of things for you, but sometimes you'll need to do something that the Deployer doesn't handle yet. In that case, you can add a custom step to the deployer, specifying your own XQuery code.
The key is to use the deploy/app_specific.rb file. (You don't need to know Ruby to use this feature.) In this example, a user is counting the documents in the content database:
class ServerConfig
def get_document_count()
r = execute_query %Q{
xdmp:estimate(fn:doc())
}
@logger.info(r.body)
end
end
Custom build steps are implemented using Ruby functions. You can use these steps from the ml script, using the function names:
ml local create_view
Note that these functions are used with an environment.
There are three key pieces you need to know to use this feature.
Before you start editing, the deploy/app_specific.rb file looks like this:
class ServerConfig
def my_custom_method()
@logger.info(@properties["ml.content-db"])
end
end
This is Ruby code. If you don't know Ruby, don't worry, you don't need to. The "class ServerConfig ... end" part of the code is a wrapper that provides some context. We'll focus on defining our custom functions.
This part of the code:
def my_custom_method()
...
end
defines a Ruby function. You can choose what to call the function, but the name should reflect what step is being done. The example above defined create_view and delete_view. Let's define a simple (but not very useful) function that tells us how many documents are in a database. We can replace my_custom_method(), so we'll start with this:
class ServerConfig
def get_document_count()
@logger.info(@properties["ml.content-db"])
end
end
Note that Ruby, by convention, uses underscores to separate words.
Having declared the function, we need to add some XQuery code. The XQuery gets wrapped in %Q{ }. [TODO]
[TODO]
In addition to adding new commands, you can make the existing commands do extra steps. Suppose you want the "deploy content" command to do something extra. Add this to deploy/app_specific.rb:
alias_method :original_deploy_content, :deploy_content
def deploy_content
original_deploy_content
execute_query(%Q{
(: put your xquery here :)
},
:db_name => @properties["ml.app-name"])
end
This “overrides” deploy content. You can call it with:
./ml {env} deploy content
class ServerConfig
def delete_view()
r = execute_query %Q{
xquery version "1.0-ml";
import module namespace view = "http://marklogic.com/xdmp/view"
at "/MarkLogic/views.xqy";
try {
view:remove(
"main",
"Compliance"
)
} catch ($e) { () }
(: Deletes a view, of the 'main' schema that contains columns, with a scope on the element, 'html'. :)
},
{ :db_name => @properties["ml.content-db"] }
end
def create_view()
r = execute_query %Q{
xquery version "1.0-ml";
import module namespace view = "http://marklogic.com/xdmp/view"
at "/MarkLogic/views.xqy";
try {
view:schema-create(
"main",
()
)
} catch ($e) {()},
view:create(
"main",
"Compliance",
view:element-view-scope(fn:QName("http://www.w3.org/1999/xhtml","html")),
( view:column("uri", cts:uri-reference()),
view:column("entityName", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "entityName"]/@content',("collation=http://marklogic.com/collation/"))),
view:column("entityStreetAddress", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "entityStreetAddress"]/@content',("collation=http://marklogic.com/collation/", ("nullable")))),
view:column("entityCityAddress", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "entityCityAddress"]/@content',("collation=http://marklogic.com/collation/", ("nullable")))),
view:column("entityCountryAddress", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "entityCountryAddress"]/@content',("collation=http://marklogic.com/collation//S2", ("nullable")))),
view:column("foreignEntityStatus", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "foreignEntityStatus"]/@content',("collation=http://marklogic.com/collation/", ("nullable")))),
view:column("intermediaryEntityStatus", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "intermediaryEntityStatus"]/@content',("collation=http://marklogic.com/collation/codepoint", ("nullable")))),
view:column("EIN", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "EIN"]/@content',("collation=http://marklogic.com/collation/", ("nullable")))),
view:column("docType", cts:path-reference('/xhtml:html/xhtml:head/xhtml:meta[@name eq "docType"]/@content',("collation=http://marklogic.com/collation//S1", ("nullable"))))
),
()
)
(: Creates a view, of the 'main' schema that contains columns, with a scope on the element, 'html'. :)
},
{ :db_name => @properties["ml.content-db"] }
end
end
def create_alerting_triggers()
r = execute_query %Q{
import module namespace alert = "http://marklogic.com/xdmp/alert" at "/MarkLogic/alert.xqy";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
if (alert:config-get("http://sample.com/audit/alert")) then ()
else
let $config :=
alert:make-config(
"http://sample.com/audit/alert",
"Sample Change Alerting",
"Alerting configuration for Sample",
<alert:options/>)
return
alert:config-insert($config);
import module namespace alert = "http://marklogic.com/xdmp/alert" at "/MarkLogic/alert.xqy";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
if (alert:config-get-trigger-ids(alert:config-get("http://sample.com/audit/alert"))) then ()
else
let $uri := "http://sample.com/audit/alert"
let $trigger-ids :=
alert:create-triggers(
$uri,
trgr:trigger-data-event(
trgr:directory-scope("/ItemInfo/", "1"),
trgr:document-content(("modify")),
trgr:pre-commit()))
let $config := alert:config-set-trigger-ids(alert:config-get($uri), $trigger-ids)
return
alert:config-insert($config);
import module namespace alert = "http://marklogic.com/xdmp/alert" at "/MarkLogic/alert.xqy";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
if (alert:get-actions("http://sample.com/audit/alert", ("*"))) then ()
else
let $uri := "http://sample.com/audit/alert"
let $action-add-mailfile :=
alert:make-action(
"add-to-inbox",
"Add Audit Event to the User Inbox",
xdmp:modules-database(),
xdmp:modules-root(),
"/lib/add-to-inbox.xqy",
<alert:options/>
)
return
alert:action-insert($uri, $action-add-mailfile)
},
{ :app_name => @properties["ml.app-name"] }
end
In this example, the "deploy modules" command gets overridden so that in addition to its default behavior, the command will also deploy some triggers. If you do this, you'd probably want to similarly override "clean modules".
class ServerConfig
alias_method :original_deploy_modules, :deploy_modules
def deploy_modules()
original_deploy_modules
r = execute_query(%Q{
xquery version "1.0-ml";
import module namespace trgr="http://marklogic.com/xdmp/triggers"
at "/MarkLogic/triggers.xqy";
xdmp:log("Installing triggers.."),
try {
trgr:remove-trigger("CreateTrigger"),
trgr:remove-trigger("ModifyTrigger")
} catch ($ignore) {
};
xquery version "1.0-ml";
import module namespace trgr="http://marklogic.com/xdmp/triggers"
at "/MarkLogic/triggers.xqy";
trgr:create-trigger("CreateTrigger", "Trigger to enrich XML ingested via MLCP",
trgr:trigger-data-event(
trgr:directory-scope("/ingest/", "1"),
trgr:document-content("create"),
trgr:pre-commit()
),
trgr:trigger-module(xdmp:modules-database(), "/", "/triggers/enrich-xml.xqy"),
fn:true(),
xdmp:default-permissions(),
fn:false()
),
trgr:create-trigger("ModifyTrigger", "Trigger to enrich XML ingested via MLCP",
trgr:trigger-data-event(
trgr:directory-scope("/ingest/", "1"),
trgr:document-content("modify"),
trgr:pre-commit()
),
trgr:trigger-module(xdmp:modules-database(), "/", "/triggers/enrich-xml.xqy"),
fn:true(),
xdmp:default-permissions(),
fn:false()
)
},
{ :app_name => @properties["ml.app-name"] }
)
end
end
Note that as written, the triggers are deployed to the modules database. To deploy it to your Triggers database, you can add this at the end, near :app-name --
{
:app_name => @properties["ml.app-name"],
:db_name => @properties["ml.triggers-db"]
}