Adobe Campaign JavaScript SDK

Manipulating schemas

08 Dec 2023 - Alexandre Morin

This article will illustrate how to use APIs to create and manipulate schemas

Schemas

There are 3 types of schemas in Campaign

Users normally only create source schemas. Those are then "compiled" into schemas and SQL schemas. The compilation process (called "build schemas") can take several seconds and is performed via an API call. This means that the xtk:builder#BuildSchema (or similar API) must be called after schemas are modified or created, to ensure overall consistency.

Once source schemas are created and compiled, you will usually use schemas and not source schemas because source schemas are just the various elements that build up the final schemas. You will probably never need to use sql schemas directly. They are used internally to map schemas to SQL tables.

Of course you can read and use source schemas as well but this is usually limited to schema authoring use cases.

Attribute/MethodDescription
Create or modifyUse source schemas and BuildSchema API
Delete
UseUse schemas

Reading schemas

Get a schema as a JSON object

The simplest way to read a schema is to use the getSchema SDK APIs which also provide client-side caching.

The client.getSchema() API returns a JSON or XML object representing the (compiled) schema requested. See the Schema API page for more details.

const schema = await client.getSchema("nms:recipient");
console.log(JSON.stringify(schema));

Get a schema as a convenient JavaScript object

The application.getSchema() API is built on top of the previous one and returns a schema object which is more convenient to use that a raw JSON object. See the Application object for more details.

const schema = await client.application.getSchema("nms:recipient");

List schemas using a query

It is also possible to use the QueryDef API to read schemas and source schemas.

Let's first get the list of source schemas in the custom namespace "cus". The following will return then names and labels of 10 source schemas in the cus namespace.


const queryDef = {
  schema: "xtk:srcSchema",
  operation: "select",
  lineCount: 10,
  select: {
      node: [
          { expr: "@name" },
          { expr: "@namespace" },
          { expr: "@label" }
      ]
  },
  where: {
    condition: [
        { expr:`@namespace = 'cus'` }
    ]
  }
};
const query = client.NLWS.xtkQueryDef.create(queryDef);
const srcSchemas = await query.executeQuery();

To return schemas instead of source schemas, use "xtk:schema" instead of "xtk:srcSchema" in the QueryDef.

If you want both schemas and source schemas, you can query the "xtk:entity" schema instead. But this requires an additional condition en the "@entitySchema" attribute. If not, you will also get custom forms, javascript, etc.


  const queryDef = {
    schema: "xtk:entity",
    operation: "select",
    lineCount: 10,
    select: {
        node: [
            { expr: "@name" },
            { expr: "@namespace" },
            { expr: "@label" },
            { expr: "@entitySchema" },
        ]
    },
    where: {
      condition: [
        { expr:`@namespace = 'cus'` },
        { expr:`@entitySchema IN ('xtk:schema', 'xtk:srcSchema')` }
        ]
    }
  };
  const query = client.NLWS.xtkQueryDef.create(queryDef);
  const entities = await query.executeQuery();
  

Use a query to get schema details

Schemas are stored into the xtk:entity table. The main fields (@name, @label, @namespace) are stored directly as SQL columns, but the schema definition is actually stored as XML. Getting the XML requires to query at least one of attibutes which is stored in XML, for example the @library attribute.


    const queryDef = {
      schema: "xtk:schema",
      operation: "get",
      select: {
          node: [
              { expr: "@name" },
              { expr: "@namespace" },
              { expr: "@label" },
              { expr: "@library" },
          ]
      },
      where: {
        condition: [
          { expr:`@namespace = 'nms' and @name='recipient'` },
        ]
      }
    };
    const query = client.NLWS.xtkQueryDef.create(queryDef);
    const schema = await query.executeQuery();
  

Note that querying for schemas (as opposed to srcSchemas) the id is the id of the top most src schema (i.e. "nms:recipient" and not "cus:recipient"). The reason is that all source schemas (nms:recipient, cus:recipient, etc.) are merged into a single schema (nms:recipient) when compiled. You can, however, query individual source schemas even if they are extension schemas

  const queryDef = {
    schema: "xtk:srcSchema",
    operation: "get",
    select: {
        node: [
            { expr: "@name" },
            { expr: "@namespace" },
            { expr: "@label" },
            { expr: "@library" },
        ]
    },
    where: {
      condition: [
        { expr:`@namespace = 'gov' and @name='recipient'` },
      ]
    }
  };
  const query = client.NLWS.xtkQueryDef.create(queryDef);
  const srcSchema = await query.executeQuery();

Use GetEntityIfMoreRecent

Last, but not least, you can use the xtk:persist#GetEntityIfMoreRecent method to return a (compiled) schema. This is the method internally used by the SDK. This method is useful if you already have the schema but you are not sure it's up to date. Calling this method is usefull to save network bandwidth as it will only return the schema if it has changed.

For this, you need to keep both the schema and its md5 hash (@md5 attribute). Then you can call the method as follows:

const schema = await client.NLWS.xtkSession.getEntityIfMoreRecent("xtk:srcSchema|nms:notFound", md5, mustExist);

Creating and updating schemas

The following API calls can be used to either create or update schemas. Note the builtin schemas cannot be updated. The operation is always a two-step process:

  • Create or modify a source schema
  • Call one of the BuildSchema methods
  • Always work with source schemas for creation and update. Tampering with (compiled) schemas can lead to inconsistencies and unpredictable results.

    Create (or modify) a custom schema

    In this example we'll create or update a simple custom schema. This is the simplest scenario, there's no schema extension, etc.

    await client.NLWS.xtkSession.write({ 
      xtkschema: "xtk:srcSchema", 
      namespace: "cus",
      name: "foo",
      label: "Foos",
      labelSingular: "Foo",
      desc: "This is a fooooo", 
      mappingType: "sql",
      element: [
        {
          name: "foo",
          key: [
            {
              name: "id",
              keyfield: [
                {
                  xpath: "@id"
                }
              ]
            }
          ],
          attribute: [
            {
              name: "id", 
              label: "Id",
              type: "string",
              length: 100
            }
          ]
        }
      ]
    });
    

    Now, build the schema. This operation may take a few seconds, adjust the timeout accordingly.

    await client.NLWS.pushDown({ timeout: 60000 }).xtkBuilder.BuildSchemaFromId("cus:foo");
    

    Do not forget to call one of the xtk:builder#BuildSchema

    Deleting a schema

    Before you can delete a source schema you need to get it's @extendedSchema attribute. The following will return the id of the parent schema if cus:foo is an extension schema, or undefined if cus:foo is not an extension schema.

    const queryDef = {
      schema: "xtk:srcSchema",
      operation: "get",
      select: {
          node: [
              { expr: "@extendedSchema" },
          ]
      },
      where: {
        condition: [
          { expr:`@namespace = 'cus' and @name='foo'` },
        ]
      }
    };
    const query = client.NLWS.xtkQueryDef.create(queryDef);
    const srcSchema = await query.executeQuery();
    const extendedSchema = srcSchema.extendedSchema;
    

    To remove a schema, a writer to delete the source schema entities you want to delete. Make sure to pass the extendedSchema if there is one.

    await client.NLWS.xtkSession.writeCollection({ 
      xtkschema: "xtk:srcSchema", 
      srcSchema: [
        {
          _operation: "delete",
          extendedSchema: extendedSchema,
          namespace: "cus",
          name: "foo"
        }
      ]
    });
    

    Now, call the xtk:builder#RemoveSchemaLinkRef method to remove the schema and reverse links. Make sure to pass the extendedSchema if there is one.

    await client.NLWS.xtkBuilder.RemoveSchemaLinkRef("cus:foo", extendedSchema);
    

    If the schema you want to delete has extension schema