-
Notifications
You must be signed in to change notification settings - Fork 63
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
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