@adobe/acc-js-sdk 1.1.10 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2170
- package/docs/404.html +11 -0
- package/docs/Gemfile +35 -0
- package/docs/Gemfile.lock +270 -0
- package/docs/_config.yml +55 -0
- package/docs/_data/navigation.yml +119 -0
- package/docs/_includes/navigation.html +33 -0
- package/docs/_layouts/default.html +21 -0
- package/docs/_layouts/home.html +4 -0
- package/docs/_layouts/page.html +5 -0
- package/docs/_layouts/post.html +7 -0
- package/docs/_posts/2022-10-14-welcome.html +149 -0
- package/docs/application.html +367 -0
- package/docs/architecture.html +24 -0
- package/docs/assets/css/styles.css +362 -0
- package/docs/assets/images/adobe-campaign-256.png +0 -0
- package/docs/assets/images/architecture.png +0 -0
- package/docs/assets/images/ref.svg +6 -0
- package/docs/badgerFish.html +14 -0
- package/docs/bestPractices.html +189 -0
- package/docs/blog.html +18 -0
- package/docs/buildAndRun.html +96 -0
- package/docs/caches.html +68 -0
- package/docs/changeLog.html +263 -0
- package/docs/checkList.html +168 -0
- package/docs/concepts.html +130 -0
- package/docs/connecting.html +210 -0
- package/docs/connectionParameters.html +109 -0
- package/docs/contribute.html +54 -0
- package/docs/dataTypes.html +124 -0
- package/docs/differences.html +4 -0
- package/docs/documentation.html +21 -0
- package/docs/domHelper.html +88 -0
- package/docs/dynamicInvoke.html +36 -0
- package/docs/entityAccessor.html +22 -0
- package/docs/errors.html +47 -0
- package/docs/escaping.html +76 -0
- package/docs/favicon.png +0 -0
- package/docs/healthCheck.html +66 -0
- package/docs/httpHeaders.html +78 -0
- package/docs/index.html +64 -0
- package/docs/installation.html +34 -0
- package/docs/license.html +208 -0
- package/docs/messageCenter.html +80 -0
- package/docs/methodLevelRepresentation.html +12 -0
- package/docs/midSourcing.html +19 -0
- package/docs/observability.html +169 -0
- package/docs/passwords.html +27 -0
- package/docs/profiles.html +103 -0
- package/docs/pushDown.html +13 -0
- package/docs/quickstart.html +69 -0
- package/docs/release.html +52 -0
- package/docs/samples.html +82 -0
- package/docs/simpleJson.html +88 -0
- package/docs/soapAPIs.html +234 -0
- package/docs/timeouts.html +23 -0
- package/docs/transport.html +45 -0
- package/docs/troubleshooting.html +17 -0
- package/docs/writeDoc.html +208 -0
- package/docs/xml2json.html +96 -0
- package/docs/xtkCaster.html +67 -0
- package/docs/xtkInterface.html +20 -0
- package/docs/xtkOption.html +54 -0
- package/docs/xtkPackage.html +16 -0
- package/docs/xtkPersist.html +213 -0
- package/docs/xtkQueryDef.html +245 -0
- package/docs/xtkSchema.html +39 -0
- package/docs/xtkSession.html +29 -0
- package/docs/xtkWorkflow.html +28 -0
- package/docs/xtkWrite.html +51 -0
- package/package-lock.json +1 -1
- package/package.json +1 -1
- package/src/application.js +15 -5
- package/src/campaign.js +1 -1
- package/src/soap.js +6 -6
- package/test/application.test.js +21 -6
- package/test/soap.test.js +13 -0
- package/CHANGELOG.md +0 -252
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Type conversion (XtkCaster)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
Campaign <a href="{{ site.baseurl }}/dataTypes.html">data types</a> have some specifities. For instance number can
|
|
8
|
+
never be null, and Campaign uses 0 instead. In addition, <a href="{{ site.baseurl }}/xml2json.html">XML to JSON</a> is not always accurate
|
|
9
|
+
and the conversion may return strings instead of booleans, objects instead of arrays, etc.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p>
|
|
13
|
+
The <b>XtkCaster</b> class is here to help and can be used to coerce an value to any type. For instance
|
|
14
|
+
if <i>you know</i> that a value is a boolean, but are not sure if it was actually returned as a boolean,
|
|
15
|
+
you can use the <b>XtkCaster</b> to ensure this. The <b>XtkCaster.asBoolean(value)</b> will ensure this.
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p>You get a static <b>XtkCaster</b> object like this</p>
|
|
19
|
+
<pre class="code">
|
|
20
|
+
const XtkCaster = sdk.XtkCaster;
|
|
21
|
+
</pre>
|
|
22
|
+
|
|
23
|
+
<p>or directly from the client for convenience</p>
|
|
24
|
+
<pre class="code">
|
|
25
|
+
const XtkCaster = client.XtkCaster;
|
|
26
|
+
</pre>
|
|
27
|
+
|
|
28
|
+
<p>To convert a Campaign value into a given type, use one of the following.</p>
|
|
29
|
+
<pre class="code">
|
|
30
|
+
stringValue = XtkCaster.asString(anyValue);
|
|
31
|
+
booleanValue = XtkCaster.asBoolean(anyValue);
|
|
32
|
+
byteValue = XtkCaster.asByte(anyValue);
|
|
33
|
+
shortValue = XtkCaster.asShort(anyValue);
|
|
34
|
+
int32Value = XtkCaster.asLong(anyValue);
|
|
35
|
+
numberValue = XtkCaster.asNumber(anyValue);
|
|
36
|
+
timestampValue = XtkCaster.asTimestamp(anyValue);
|
|
37
|
+
dateValue = XtkCaster.asDate(anyValue);
|
|
38
|
+
</pre>
|
|
39
|
+
|
|
40
|
+
<p>More dynamic conversions can be achieved using the <b>as</b> function. See the types table above for details.</p>
|
|
41
|
+
|
|
42
|
+
<pre class="code">
|
|
43
|
+
stringValue = XtkCaster.as(anyValue, 6);
|
|
44
|
+
</pre>
|
|
45
|
+
|
|
46
|
+
<p>In addition, the following helpers are available</p>
|
|
47
|
+
<ul>
|
|
48
|
+
<li><b>XtkCaster.isTimeType</b> to test if a data type is a date, time or timestamp</li>
|
|
49
|
+
<li><b>XtkCaster.isStringType</b> to test if a data type is a string type (string, memo, etc.)</li>
|
|
50
|
+
<li><b>XtkCaster.isNumericType</b> to test if a data type is a numeric type</li>
|
|
51
|
+
</ul>
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
<h1>Arrays</h1>
|
|
56
|
+
|
|
57
|
+
<p>
|
|
58
|
+
Arrays can be tricky to handle when converted from XML: an empty array will be converted to a null or undefined
|
|
59
|
+
values, an array containing exactly one element may be converted into the element itself. The <b>XtkCaster.asArray</b>
|
|
60
|
+
will ensure that it's parameter will be converted to an array, possibly empty.
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
<pre class="code">
|
|
64
|
+
expect(XtkCaster.asArray(null)).toStrictEqual(<span class="emphasis">[]</span>);
|
|
65
|
+
expect(XtkCaster.asArray("Hello")).toStrictEqual(<span class="emphasis">["Hello"]</span>);
|
|
66
|
+
expect(XtkCaster.asArray(["Hello", "World""])).toStrictEqual(<span class="emphasis">["Hello", "World""]</span>);
|
|
67
|
+
</pre>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: XTK interfaces
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>Campaign schemas are following an object model. An interface is a set of methods. For instance, the "xtk:persist" interface, defined in the "xtk:session" schema, has a NewInstance method.
|
|
7
|
+
Schemas can implement interface, which means they inherit and implement the methods of the interface. Such methods are internally called using a particular SOAP call URN, which is formed of the interface name, followed by a pipe character, followed by the implementation schema id. For instance "xtk:persist|nms:delivery" is used to indicate that we're calling a method of the xtk:persist on a nms:delivery object which implements the xtk:persist interface.</p>
|
|
8
|
+
|
|
9
|
+
<p>The version 1.1.9 of the SDK properly implement this type of calls and will deal with this complexity for you. For instance, you can simply call the NewInstance method as follows:</p>
|
|
10
|
+
|
|
11
|
+
<pre class="code">
|
|
12
|
+
// Create a proxy delivery object
|
|
13
|
+
const delivery = client.NLWS.nmsDelivery.create({ label: "Hello" });
|
|
14
|
+
|
|
15
|
+
// Call the xtk:persist|nms:delivery#NewInstance method to retreive the default
|
|
16
|
+
// values of a delivery object before actually saving the delivery
|
|
17
|
+
await delivery.newInstance();
|
|
18
|
+
</pre>
|
|
19
|
+
|
|
20
|
+
<p>There are 2 common interfaces: <a href="{{ site.baseurl }}/xtkPersist.html">xtk:persist</a> and <a href="">xtk:jobInterface</a> which are documented below.</p>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Managing options
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<h1>Reading options</h1>
|
|
8
|
+
|
|
9
|
+
<p>A convenience function is provided, which returns a typed option value.</p>
|
|
10
|
+
<pre class="code">
|
|
11
|
+
var value = await client.getOption("XtkDatabaseId");
|
|
12
|
+
</pre>
|
|
13
|
+
|
|
14
|
+
Options are cached because they are often used. It's possible to force the reload of an option:
|
|
15
|
+
<pre class="code">
|
|
16
|
+
var value = await client.getOption("XtkDatabaseId", false);
|
|
17
|
+
</pre>
|
|
18
|
+
|
|
19
|
+
<p>It's also possible to call the API directly.</p>
|
|
20
|
+
<p>Use the <b>xtk:session:GetOption</b> method to return an option value and it's type. This call will not use the option cache for returning the option value, but will still cache the result.</p>
|
|
21
|
+
|
|
22
|
+
<pre class="code">
|
|
23
|
+
const optionValueAndType = await NLWS.xtkSession.getOption("XtkDatabaseId");
|
|
24
|
+
console.log("Marketing datbaseId: " + optionValueAndType);
|
|
25
|
+
|
|
26
|
+
Marketing datbaseId: u7F00010100B52BDE,6
|
|
27
|
+
</pre>
|
|
28
|
+
|
|
29
|
+
<p>If the option does not exist, it will return [ "", 0 ]</p>
|
|
30
|
+
|
|
31
|
+
<pre class="code">
|
|
32
|
+
var datbaseId = await client.getOption("XtkDatabaseId");
|
|
33
|
+
console.log(datbaseId);
|
|
34
|
+
</pre>
|
|
35
|
+
|
|
36
|
+
<p>The <a href="{{ site.baseurl }}/caches.html">cache</a> can be cleared.</p>
|
|
37
|
+
<pre class="code">
|
|
38
|
+
client.clearOptionCache();
|
|
39
|
+
</pre>
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
<h1>Setting options</h1>
|
|
43
|
+
|
|
44
|
+
<p>It's also possible to set options with the <b>setOption</b> function.</p>
|
|
45
|
+
<ul>
|
|
46
|
+
<li>It will create the option if necessary</li>
|
|
47
|
+
<li>If the option already exists, it will use the existing value to infer the data type of the option</li>
|
|
48
|
+
</ul>
|
|
49
|
+
|
|
50
|
+
<pre class="code">
|
|
51
|
+
await client.setOption("MyOption", "My value");
|
|
52
|
+
</pre>
|
|
53
|
+
|
|
54
|
+
<p>This is really a convenience function. You can always force an option type by using a writer on the xtk:option table, and using getOption to read back and cache the result.</p>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Packages
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>Test if a package is installed. Expects to be connected to an instance. Available since version 0.1.20</p>
|
|
7
|
+
|
|
8
|
+
<pre class="code">
|
|
9
|
+
var hasAmp = client.hasPackage("nms:amp");
|
|
10
|
+
</pre>
|
|
11
|
+
|
|
12
|
+
<p>or</p>
|
|
13
|
+
|
|
14
|
+
<pre class="code">
|
|
15
|
+
var hasAmp = client.hasPackage("nms", "amp");
|
|
16
|
+
</pre>
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: CRUD operations (xkt:persist)
|
|
4
|
+
---
|
|
5
|
+
<p>There are several possibillities to create objects in Campaign.</p>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<h1>Create from scratch</h1>
|
|
10
|
+
|
|
11
|
+
<p>This first method is to create an object from scratch. It's a multi-step operation which contains the following steps</p>
|
|
12
|
+
|
|
13
|
+
<ul>
|
|
14
|
+
<li>Create an object with the "create" function. This function takes an optional parameter with the attributes you know you're going to set</li>
|
|
15
|
+
<li>Call the <b>xtk:persist#NewInstance</b> API which will generate a unique id, and complete your object with default values (such as default folder, etc.) depending on your role</li>
|
|
16
|
+
<li>Optionally set more attributes to override any defaults</li>
|
|
17
|
+
<li>Call <b>save()</b> or <b>xtk:session#Write</b> to create the object in the database </li>
|
|
18
|
+
</ul>
|
|
19
|
+
|
|
20
|
+
<p></p>
|
|
21
|
+
<pre class="code">
|
|
22
|
+
const delivery = client.NLWS.nmsDelivery.create({
|
|
23
|
+
label: "Test #1",
|
|
24
|
+
messageType: "0"
|
|
25
|
+
});
|
|
26
|
+
await delivery.newInstance();
|
|
27
|
+
delivery.$desc = "My description";
|
|
28
|
+
await client.NLWS.xtkSession.write(delivery); // or await delivery.save();
|
|
29
|
+
</pre>
|
|
30
|
+
|
|
31
|
+
<p>You'll notice that this method does not return anything. You may have expected this method to return the created object or some id of this object,
|
|
32
|
+
but Campaign does not. Campaign works the other way round. You first get call NewInstance which will give the id before the object is actually saved
|
|
33
|
+
in the database.</p>
|
|
34
|
+
|
|
35
|
+
<pre class="code">
|
|
36
|
+
const delivery = client.NLWS.nmsDelivery.create({
|
|
37
|
+
label: "Test #1",
|
|
38
|
+
messageType: "0"
|
|
39
|
+
});
|
|
40
|
+
await delivery.newInstance();
|
|
41
|
+
// delivery.entity.id is the future id of the object in the database
|
|
42
|
+
</pre>
|
|
43
|
+
|
|
44
|
+
<p>If you need to modify the object again after it's been created, you can use <b>xtk:session#Write</b> or save again, but you must tell Campaign to perform an update operation instead of an insert, or the call will probably fail or create a duplicate in the database.
|
|
45
|
+
Make sure to read the section about the <b>xtk:session#Write</b> method below to understand how exactly objects are updated
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<pre class="code">
|
|
49
|
+
delivery._operation = "update";
|
|
50
|
+
delivery.$desc = "My updated description";
|
|
51
|
+
await delivery.save();
|
|
52
|
+
</pre>
|
|
53
|
+
|
|
54
|
+
<p>Finally, to delete the object, use <b>xtk:session#Write</b> or save again, this time passing it the "_operation=delete" attribute</p>
|
|
55
|
+
|
|
56
|
+
<pre class="code">
|
|
57
|
+
delivery._operation = "delete";
|
|
58
|
+
await delivery.save();
|
|
59
|
+
</pre>
|
|
60
|
+
|
|
61
|
+
<h1>Create by duplicating an existing object</h1>
|
|
62
|
+
|
|
63
|
+
<p>Sometimes, you do not want to create objects from scratch. Instead you can copy an existing object. Campaign has a sophisticated mechanism to duplicate object and ensures that only the relevant attributes are actually set. For instance, when you dupliate a delivery which is finished, you probably want the new delivery to be in the edition state rather than in the finished state. Schema attributes having the "defOnDuplicate" property will be reset to their defaults in the duplicated object.</p>
|
|
64
|
+
|
|
65
|
+
<p>Just like the <b>NewInstance</b> API, the <b>xtk:persist#Duplicate</b> will automatically set the primary key for you. And again, it is a multi-step process.</p>
|
|
66
|
+
|
|
67
|
+
<ul>
|
|
68
|
+
<li>Create an object with the "create" function. This time, do no pass any parameters</li>
|
|
69
|
+
<li>Call the duplicate method, passing it the primary key of the entity you want to duplicate</li>
|
|
70
|
+
<li>Optionally set more attributes to override any defaults</li>
|
|
71
|
+
<li>Call save() or xtk:session#Write to create the object in the database </li>
|
|
72
|
+
</ul>
|
|
73
|
+
|
|
74
|
+
<p></p>
|
|
75
|
+
|
|
76
|
+
<pre class="code">
|
|
77
|
+
const operator = client.NLWS.xtkOperator.create();
|
|
78
|
+
await operator.duplicate("xtk:operator|1610");
|
|
79
|
+
operator.name = "Alex";
|
|
80
|
+
await operator.save();
|
|
81
|
+
</pre>
|
|
82
|
+
|
|
83
|
+
<p>The primary key format is described in the data types section of this document.</p>
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
<h1>Updating entities</h1>
|
|
87
|
+
|
|
88
|
+
<p>Entities can be updated using the <b>xtk:session#Write</b> API. This API is very flexible and also can be used to create or delete entities or to modify multiple entites at once.</p>
|
|
89
|
+
|
|
90
|
+
<p>More examples of the <b>xtk:session#Write</b> API <a href="{{ site.baseurl }}/xtkPersist.html">here</a>.</p>
|
|
91
|
+
|
|
92
|
+
<p>This method takes an unique argument which is a patch to apply. A patch has the same structure as an entity, but only contains the attributes or elements that need to be modified, created, or deleted. In addition to the value, the patch can also use the _operation property to indicate if a particular set of data needs to be inserted, updated or deleted.
|
|
93
|
+
The patch object also must have the <b>xtkschema</b> property set to the schema id of the entity to modify.
|
|
94
|
+
</p>
|
|
95
|
+
|
|
96
|
+
<p>For instance, one can update the email of a recipient with the following code which clearly shows the xtkschema property, the id and _operation properties to indicate that it is an update and which entity to update, and finally, the email attribute which is the only modified attribute.</p>
|
|
97
|
+
|
|
98
|
+
<pre class="code">
|
|
99
|
+
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
100
|
+
id: "1234", _operation:"update",
|
|
101
|
+
email: "amorin@adobe.com"
|
|
102
|
+
});
|
|
103
|
+
</pre>
|
|
104
|
+
|
|
105
|
+
<p>It's of course possible to pass the whole entity to an update, but this is strongly discouraged as it can have unwanted side effects in complex scenario when passed nested documents with linked objects. It's also less performant, and may overwrite data.
|
|
106
|
+
Passing a patch (sometimes called a diff) containing only the actually modified attributes is the best practice. It also has the benefit to allow some sort of concurrent modifications as each update will onlly update the attributes actually changed.</p>
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
<h1>Setting foreign keys</h1>
|
|
110
|
+
|
|
111
|
+
<p>It's pretty common to have to set foreign keys. For instance one want to set the folder in which a recipient is stored. The first possibility is to set the folder-id attribute directly. It's also the most efficient, but it assumes you know the foreign key in the first place.</p>
|
|
112
|
+
|
|
113
|
+
<pre class="code">
|
|
114
|
+
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
115
|
+
xtkschema:"nms:recipient",
|
|
116
|
+
id: 2020, _operation:"update",
|
|
117
|
+
"folder-id": 6040
|
|
118
|
+
});
|
|
119
|
+
</pre>
|
|
120
|
+
|
|
121
|
+
<p>If you do not know the primary key of the folder but know its name, you can use the following syntax. It works for all collections, where items can be identified with their keys (as defined in the schemas).</p>
|
|
122
|
+
|
|
123
|
+
<pre class="code">
|
|
124
|
+
client.NLWS.xtkSession.write({ xtkschema: "nms:recipient",
|
|
125
|
+
xtkschema:"nms:recipient",
|
|
126
|
+
id: 1990, _operation:"update",
|
|
127
|
+
folder: {
|
|
128
|
+
_operation: "none",
|
|
129
|
+
name: "test"
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
</pre>
|
|
133
|
+
|
|
134
|
+
<p class="info">Note the <b>operation="none"</b> attribute on the folder element which tells Campaign that we should not actually update the folder object itself, but to set the recipient folder instead. If you omit the _operation: "none" property, Campaign will modify both the recipient, but also the folder. It is useful in some cases, but does not make sense in this scenario.</p>
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
<h1>Identifying entities</h1>
|
|
138
|
+
|
|
139
|
+
<p>We've had a glimpse of it but the xtk:session#Write API has several strategies to identify entities, both the top level entity but also linked entities as we've seen with the recipient folder example above.</p>
|
|
140
|
+
|
|
141
|
+
<ul>
|
|
142
|
+
<li>If the entity is an "autopk" entity, i.e. has autopk=true set defined in its schema, then it will have an internal primary key using the @id attribute. If the corresponding id is set in the patch document, it will be used to identify the object. </li>
|
|
143
|
+
<li>Otherwise, it will use the entity keys, as defined in the schema.</li>
|
|
144
|
+
</ul>
|
|
145
|
+
|
|
146
|
+
<p>For instance, folders are an autopk entity and have the id attribute. They also have 2 keys: name and fullName. All 3 can be used as identifiers to update a folder label as the 3 examples below show</p>
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
<pre class="code">
|
|
150
|
+
// Update folder by id
|
|
151
|
+
await client.NLWS.xtkSession.write({
|
|
152
|
+
xtkschema: "xtk:folder",
|
|
153
|
+
_operation: "update", id: 1234,
|
|
154
|
+
label: "Hello World",
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Update folder by name
|
|
159
|
+
await client.NLWS.xtkSession.write({
|
|
160
|
+
xtkschema: "xtk:folder",
|
|
161
|
+
_operation: "update", name: "test",
|
|
162
|
+
label: "Hello World",
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Update folder by full name
|
|
167
|
+
// This is just for example, do not use this method as the folder full name is the concatenation
|
|
168
|
+
// of the folder label and it's parent folders labels. Changing the label will create an
|
|
169
|
+
// inconsistency between the folder full name and its label. You can update other attributes though.
|
|
170
|
+
await client.NLWS.xtkSession.write({
|
|
171
|
+
xtkschema: "xtk:folder",
|
|
172
|
+
_operation: "update", fullName: "/Profiles and Targets/Recipients/Hello/",
|
|
173
|
+
label: "Hello World",
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
</pre>
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
<h1>Deleting data</h1>
|
|
180
|
+
|
|
181
|
+
<p>The <b>xtkSession#write</b> API can also be used to delete data using the "_operation=delete" attribute. For a delete operation, the patch should contain the xtkschema attribute, the _operation=delete attribute and an identifier of the entity.</p>
|
|
182
|
+
|
|
183
|
+
<p>For insance, a folder can be delete with</p>
|
|
184
|
+
|
|
185
|
+
<pre class="code">
|
|
186
|
+
await client.NLWS.xtkSession.write({
|
|
187
|
+
xtkschema: "xtk:folder",
|
|
188
|
+
_operation: "delete", name: "test",
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
</pre>
|
|
192
|
+
|
|
193
|
+
<p>Owned entities which are also autopk will also be deleted</p>
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
<h1>Setting ids</h1>
|
|
197
|
+
|
|
198
|
+
<p>In the previous examples we showed how to create or update object and let Campaign generate the ids. In some cases, you'll want to explictiely set the ids upfront. To ensure uniqueness of the ids, Campaign provides an API to "reserve" ids in advane that you can use afterwards: xtk:session#GetNewIdsEx.</p>
|
|
199
|
+
|
|
200
|
+
<p>In this example, we're getting an id and creating a recipient. The id can be re-used in subsequent calls as a foreign key</p>
|
|
201
|
+
|
|
202
|
+
<pre class="code">
|
|
203
|
+
const idList = XtkCaster.asArray(await client.NLWS.xtkSession.GetNewIdsEx(1, "XtkNewId"));
|
|
204
|
+
await client.NLWS.xtkSession.write({ xtkschema:"nms:recipient", id: idList[0], email: 'amorin@adobe.com' });
|
|
205
|
+
</pre>
|
|
206
|
+
|
|
207
|
+
<p>Note that</p>
|
|
208
|
+
<ul>
|
|
209
|
+
<li>Calling GetNewIdsEx for individual ids is not efficient. It's usually better to reserve a large range of ids and insert multiple rows using those ids</li>
|
|
210
|
+
<li>Inserting data in unitary fashion with API calls is not efficient. Use data management workflows for large imports</li>
|
|
211
|
+
<li>Make sure that the NLWS.xtkSession.GetNewIdsEx returns an array by using XtkCaster.asArray(...)</li>
|
|
212
|
+
</ul>
|
|
213
|
+
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Query API
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
The <b>xtk:queryDef</b> schema contains generic methods to query the database and retrieve any kind of entites, both
|
|
8
|
+
out-of-the-box and custom.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p class="warning">This API is not meant for high concurrency. It is fit for a reasonble usage without the limits of the capacity you purchased.</p>
|
|
12
|
+
|
|
13
|
+
<p>List all accounts</p>
|
|
14
|
+
|
|
15
|
+
<pre class="code">
|
|
16
|
+
const queryDef = {
|
|
17
|
+
schema: "nms:extAccount",
|
|
18
|
+
operation: "select",
|
|
19
|
+
select: {
|
|
20
|
+
node: [
|
|
21
|
+
{ expr: "@id" },
|
|
22
|
+
{ expr: "@name" }
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
27
|
+
|
|
28
|
+
console.log(query);
|
|
29
|
+
const extAccounts = await query.executeQuery();
|
|
30
|
+
console.log(JSON.stringify(extAccounts));
|
|
31
|
+
</pre>
|
|
32
|
+
|
|
33
|
+
<p>Get a single record</p>
|
|
34
|
+
<pre class="code">
|
|
35
|
+
const queryDef = {
|
|
36
|
+
schema: "nms:extAccount",
|
|
37
|
+
operation: "get",
|
|
38
|
+
select: {
|
|
39
|
+
node: [
|
|
40
|
+
{ expr: "@id" },
|
|
41
|
+
{ expr: "@name" },
|
|
42
|
+
{ expr: "@label" },
|
|
43
|
+
{ expr: "@type" },
|
|
44
|
+
{ expr: "@account" },
|
|
45
|
+
{ expr: "@password" },
|
|
46
|
+
{ expr: "@server" },
|
|
47
|
+
{ expr: "@provider" },
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
where: {
|
|
51
|
+
condition: [
|
|
52
|
+
{ expr: "@name='ffda'" }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
57
|
+
const extAccount = await query.executeQuery();
|
|
58
|
+
</pre>
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
<h1>Query operations</h1>
|
|
63
|
+
|
|
64
|
+
<p>
|
|
65
|
+
The <b>operation</b> attribute of a query indicates what kind of query operation to perform amongst the following. It is defined
|
|
66
|
+
in the <b>xtk:queryDef:operation</b> enumeration.
|
|
67
|
+
</p>
|
|
68
|
+
<ul>
|
|
69
|
+
<li><b>get</b> is used to query one and exactly one record. If the record does not exist, it is considered to be an error. If this happens, the SDK will actually throw a JavaScript error</li>
|
|
70
|
+
<li><b>getIfExist</b> is used to query one record which may not exist</li>
|
|
71
|
+
<li><b>select</b> is used to query multiple records. The result is an array of 0, 1, or more entities</li>
|
|
72
|
+
<li><b>count</b> is used to count records</li>
|
|
73
|
+
</ul>
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
<h1>Escaping</h1>
|
|
77
|
+
<p>It's common to use variables in query conditions. For instance, in the above example, you'll want to query an account by name instead of using the hardcoded <b>ffda</b> name. The <b>expr</b> attribute takes an XTK expression as a parameter, and <b>ffda</b> is a string litteral in an xtk expression.</p>
|
|
78
|
+
|
|
79
|
+
<p>To prevent xtk ingestions vulnerabilities, you should not concatenate strings and write code such as expr: "@name = '" + name + "'": if the value of the name
|
|
80
|
+
parameter contains single quotes, your code will not work, but could also cause vulnerabilities.
|
|
81
|
+
</p>
|
|
82
|
+
|
|
83
|
+
<p></p>
|
|
84
|
+
<p class="ref">Find more details about escaping <a href="{{ site.baseurl }}/escaping.html">here</a>.</p>
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
<h1>Pagination</h1>
|
|
90
|
+
<p>Results can be retrieved in different pages, using the <b>lineCount</b> and <b>startLine</b> attributes. For instance, retrieves profiles 3 and 4 (skip 1 and 2)</p>
|
|
91
|
+
|
|
92
|
+
<pre class="code">
|
|
93
|
+
const queryDef = {
|
|
94
|
+
schema: "nms:recipient",
|
|
95
|
+
operation: "select",
|
|
96
|
+
<span class="emphasis">lineCount: 2</span>,
|
|
97
|
+
<span class="emphasis">startLine: 2</span>,
|
|
98
|
+
select: {
|
|
99
|
+
node: [
|
|
100
|
+
{ expr: "@id" },
|
|
101
|
+
{ expr: "@email" }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
106
|
+
const recipients = await query.executeQuery();
|
|
107
|
+
console.log(JSON.stringify(recipients));
|
|
108
|
+
</pre>
|
|
109
|
+
|
|
110
|
+
<p class="warning">
|
|
111
|
+
Campaign will automatically limit the number of row returned by a query to <b>200</b>. The reason for this limit is that
|
|
112
|
+
all the data returned by a query is stored in memory in the application server, but is also sent over the network to
|
|
113
|
+
the SDK or API client, which also stores the data in memory. Storing more than a few hundred rows is generally not a
|
|
114
|
+
good idea. Using the <b>QueryDef</b> API to handle large amounts of data is not a good idea either, it's better to
|
|
115
|
+
use workflow instead. Worfklows are made to process large amounts of data, up to hundreds of millions of rows, whereas
|
|
116
|
+
queries are not meant to handle more than a few hundred rows.
|
|
117
|
+
</p>
|
|
118
|
+
|
|
119
|
+
<p>
|
|
120
|
+
More advanced pagination also need a <b>orderBy</b> clause to ensure that results are consistent. If not using an orderBy
|
|
121
|
+
clause, the query does not quarantee the ordering of the results, and subsequent calls are not quaranteed to
|
|
122
|
+
return consistent pages. This example uses the name attribute to sort delivery mappings and returns the first 2
|
|
123
|
+
records.
|
|
124
|
+
</p>
|
|
125
|
+
|
|
126
|
+
<pre class="code">
|
|
127
|
+
const queryDef = {
|
|
128
|
+
schema: "nms:deliveryMapping",
|
|
129
|
+
operation: "select",
|
|
130
|
+
<span class="emphasis">lineCount: 2</span>,
|
|
131
|
+
select: {
|
|
132
|
+
node: [
|
|
133
|
+
{ expr: "@id" },
|
|
134
|
+
{ expr: "@name" }
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
<span class="emphasis">
|
|
138
|
+
orderBy: { node: [
|
|
139
|
+
{expr: "@name"}
|
|
140
|
+
]}</span>
|
|
141
|
+
};
|
|
142
|
+
</pre>
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
<h1>Conditionnal queries</h1>
|
|
146
|
+
|
|
147
|
+
<p>
|
|
148
|
+
Some Campaign attributes depend on the installed packages. For instance, the mobile package will add attributes to
|
|
149
|
+
various schemas so that Campaign can handle push notifications. I you need to write generic code that can adapt
|
|
150
|
+
whether the mobile package is installed or not, you can use the <b>hasPackage</b> function to
|
|
151
|
+
conditionally add nodes to the query.
|
|
152
|
+
</p>
|
|
153
|
+
|
|
154
|
+
<pre class="code">
|
|
155
|
+
if (client.application.hasPackage("nms:mobileApp")) {
|
|
156
|
+
queryDef.select.node.push({ expr: "@blackListAndroid" });
|
|
157
|
+
}
|
|
158
|
+
</pre>
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
<h1>Select all fields</h1>
|
|
164
|
+
|
|
165
|
+
<p>
|
|
166
|
+
For some objects, such as deliveries and workflows, it can be painful to have to list all the attributes that we want
|
|
167
|
+
to retreive, as there could be hundreds. The query provides a mechanism to select all attributes, a bit like
|
|
168
|
+
a SELECT * would do in SQL. However, it involves an extra API call <b>xtk:queryDef#SelectAll</b> which means an
|
|
169
|
+
additional round-trip to the server
|
|
170
|
+
</p>
|
|
171
|
+
|
|
172
|
+
<pre class="code">
|
|
173
|
+
const queryDef = {
|
|
174
|
+
schema: "xtk:option",
|
|
175
|
+
operation: "get",
|
|
176
|
+
where: {
|
|
177
|
+
condition: [
|
|
178
|
+
{ expr:`@name='XtkDatabaseId'` }
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
183
|
+
await query.selectAll(false);
|
|
184
|
+
const databaseId = await query.executeQuery();
|
|
185
|
+
</pre>
|
|
186
|
+
<p class="caption">Querying all attributes of the xtk:option schema</p>
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
<h1>Generating the SQL of a query</h1>
|
|
192
|
+
|
|
193
|
+
<p>
|
|
194
|
+
The queryDef API also lets you generate the SQL for a query, using the <b>BuildQuery</b>.
|
|
195
|
+
</p>
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
<pre class="code">
|
|
199
|
+
const sql = await query.buildQuery();
|
|
200
|
+
console.log(">> SQL query: " + sql);
|
|
201
|
+
</pre>
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
<p>
|
|
205
|
+
The <b>BuildQueryEx</b> methods will also return the SQL and also metadata (data type) about each select field.
|
|
206
|
+
</p>
|
|
207
|
+
|
|
208
|
+
<pre class="code">
|
|
209
|
+
const sql = await query.buildQueryEx();
|
|
210
|
+
console.log(`>> SQL queryEx: "${sql[0]}"`);
|
|
211
|
+
console.log(`>> Format string: "${sql[1]}"`);
|
|
212
|
+
</pre>
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
<h1>The analyze option</h1>
|
|
217
|
+
|
|
218
|
+
<p>
|
|
219
|
+
The query uses the <b>analyze</b> option to return user friendly names for enumerations.
|
|
220
|
+
In this example, we use the exclusionType attribute of the target mappings schema. Without the analyze flag, the query will
|
|
221
|
+
return the numeric value of the attribute (for example 2). With the flag, the query will still return the numeric value,
|
|
222
|
+
but will also return the string value of the attribute and its label. It will use addition JSON attributes named
|
|
223
|
+
"exclusionTypeName" and "exclusionTypeLabel", using the "Name" and "Label" suffixes.`,
|
|
224
|
+
</p>
|
|
225
|
+
|
|
226
|
+
<pre class="code">
|
|
227
|
+
const queryDef = {
|
|
228
|
+
schema: "nms:deliveryMapping",
|
|
229
|
+
operation: "get",
|
|
230
|
+
select: {
|
|
231
|
+
node: [
|
|
232
|
+
{ expr: "@id" },
|
|
233
|
+
{ expr: "[storage/@exclusionType]", <span class="emphasis">analyze: true</span> },
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
where: {
|
|
237
|
+
condition: [
|
|
238
|
+
{ expr:`@name='mapRecipient'` }
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
query = NLWS.xtkQueryDef.create(queryDef);
|
|
243
|
+
mapping = await query.executeQuery();
|
|
244
|
+
</pre>
|
|
245
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: The Schema API
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
<p>Reading schemas is a common operation in Campaign. The SDK provides a convenient functions as well as caching for efficient use of schemas.</p>
|
|
9
|
+
<p>In addition, have a look at the <a href="{{ site.baseurl }}/application/html">Application</a> object which contains an object model for accessing and traversing schemas</p>
|
|
10
|
+
|
|
11
|
+
<pre class="code">
|
|
12
|
+
const schema = await client.getSchema("nms:recipient");
|
|
13
|
+
console.log(JSON.stringify(schema));
|
|
14
|
+
</pre>
|
|
15
|
+
|
|
16
|
+
<p>A given representation can be forced</p>
|
|
17
|
+
<pre class="code">
|
|
18
|
+
const xmlSchema = await client.getSchema("nms:recipient", "xml");
|
|
19
|
+
const jsonSchema = await client.getSchema("nms:recipient", "SimpleJson");
|
|
20
|
+
</pre>
|
|
21
|
+
|
|
22
|
+
<p>System enumerations can also be retreived with the fully qualified enumeration name</p>
|
|
23
|
+
<pre class="code">
|
|
24
|
+
const sysEnum = await client.getSysEnum("nms:extAccount:encryptionType");
|
|
25
|
+
</pre>
|
|
26
|
+
|
|
27
|
+
<p>or from a schema</p>
|
|
28
|
+
<pre class="code">
|
|
29
|
+
const schema = await client.getSchema("nms:extAccount");
|
|
30
|
+
const sysEnum = await client.getSysEnum("encryptionType", schema);
|
|
31
|
+
</pre>
|
|
32
|
+
|
|
33
|
+
<p>Get a source schema</p>
|
|
34
|
+
<pre class="code">
|
|
35
|
+
var srcSchema = await NLWS.xtkPersist.getEntityIfMoreRecent("xtk:srcSchema|nms:recipient", "", false);
|
|
36
|
+
console.log(JSON.stringify(srcSchema));
|
|
37
|
+
</pre>
|
|
38
|
+
|
|
39
|
+
|