Skip to content

Commit 9ecf413

Browse files
committed
MLE-25617 Added TS for marklogic-level functions
1 parent 750b8ff commit 9ecf413

File tree

4 files changed

+304
-0
lines changed

4 files changed

+304
-0
lines changed

marklogic.d.ts

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,29 @@ declare module 'marklogic' {
128128
systemTime?: string;
129129
}
130130

131+
/**
132+
* A timestamp object representing a point in time on the server.
133+
* Used for point-in-time queries and operations.
134+
* @since 2.1.1
135+
*/
136+
export interface Timestamp {
137+
/** The timestamp value as a string */
138+
value: string | null;
139+
}
140+
141+
/**
142+
* Result value from eval, xqueryEval, or invoke operations.
143+
* Each returned value includes format, datatype, and the actual value.
144+
*/
145+
export interface EvalResult {
146+
/** Format of the value: 'json', 'xml', 'text', or 'binary' */
147+
format: 'json' | 'xml' | 'text' | 'binary';
148+
/** Datatype of the value (e.g., 'node()', 'string', 'boolean', 'integer') */
149+
datatype: string;
150+
/** The actual value (type depends on format and datatype) */
151+
value: any;
152+
}
153+
131154
/**
132155
* Result from a removeAll operation.
133156
*/
@@ -390,6 +413,114 @@ declare module 'marklogic' {
390413
*/
391414
checkConnection(): ResultProvider<ConnectionCheckResult>;
392415

416+
/**
417+
* Creates one or more JSON documents for a collection.
418+
* The server assigns URI identifiers to the documents.
419+
* This is a simplified convenience method - use documents.write() for more control.
420+
* @since 1.0
421+
* @param collection - The collection name for the documents
422+
* @param content - The JSON content object(s) for the documents
423+
* @returns A result provider that resolves to an array of assigned URIs
424+
*/
425+
createCollection(collection: string, ...content: any[]): ResultProvider<string[]>;
426+
427+
/**
428+
* Probes whether a document exists.
429+
* This is a simplified convenience method - use documents.probe() for more information.
430+
* @since 1.0
431+
* @param uri - The URI of the document to check
432+
* @returns A result provider that resolves to a boolean
433+
*/
434+
probe(uri: string): ResultProvider<boolean>;
435+
436+
/**
437+
* Queries documents in a collection.
438+
* This is a simplified convenience method - use documents.query() for more control.
439+
* @since 1.0
440+
* @param collection - The collection name
441+
* @param query - Optional query built by queryBuilder
442+
* @returns A result provider that resolves to an array of document content
443+
*/
444+
queryCollection(collection: string, query?: any): ResultProvider<DocumentContent[]>;
445+
446+
/**
447+
* Reads one or more documents, returning just the content.
448+
* This is a simplified convenience method - use documents.read() for metadata too.
449+
* @since 1.0
450+
* @param uris - One or more document URIs
451+
* @returns A result provider that resolves to an array of document content
452+
*/
453+
read(...uris: string[]): ResultProvider<DocumentContent[]>;
454+
455+
/**
456+
* Removes one or more documents.
457+
* This is a simplified convenience method - use documents.remove() for more control.
458+
* @since 1.0
459+
* @param uris - One or more document URIs to remove
460+
* @returns A result provider that resolves to an array of removed URIs
461+
*/
462+
remove(...uris: string[]): ResultProvider<string[]>;
463+
464+
/**
465+
* Removes all documents in a collection.
466+
* This is a simplified convenience method - use documents.removeAll() for more options.
467+
* @since 1.0
468+
* @param collection - The collection whose documents should be deleted
469+
* @returns A result provider that resolves to the collection name
470+
*/
471+
removeCollection(collection: string): ResultProvider<string>;
472+
473+
/**
474+
* Writes documents to a collection using a URI-to-content mapping.
475+
* This is a simplified convenience method - use documents.write() for more control.
476+
* @since 1.0
477+
* @param collection - The collection name for the documents
478+
* @param documents - An object mapping URIs to document content
479+
* @returns A result provider that resolves to an array of written URIs
480+
*/
481+
writeCollection(collection: string, documents: Record<string, DocumentContent>): ResultProvider<string[]>;
482+
483+
/**
484+
* Creates a timestamp object for point-in-time operations.
485+
* @since 2.1.1
486+
* @param value - Optional timestamp value as a string
487+
* @returns A Timestamp object
488+
*/
489+
createTimestamp(value?: string): Timestamp;
490+
491+
/**
492+
* Evaluates JavaScript code on the server.
493+
* The user must have permission to evaluate code and execute the actions performed.
494+
* @since 1.0
495+
* @param source - The JavaScript source code to evaluate
496+
* @param variables - Optional object with variable name-value pairs
497+
* @param txid - Optional transaction ID or Transaction object
498+
* @returns A result provider that resolves to an array of EvalResult objects
499+
*/
500+
eval(source: string, variables?: Record<string, any>, txid?: string | object): ResultProvider<EvalResult[]>;
501+
502+
/**
503+
* Evaluates XQuery code on the server.
504+
* The user must have permission to evaluate code and execute the actions performed.
505+
* @since 1.0
506+
* @param source - The XQuery source code to evaluate
507+
* @param variables - Optional object with variable name-value pairs (keys may use Clark notation)
508+
* @param txid - Optional transaction ID or Transaction object
509+
* @returns A result provider that resolves to an array of EvalResult objects
510+
*/
511+
xqueryEval(source: string, variables?: Record<string, any>, txid?: string | object): ResultProvider<EvalResult[]>;
512+
513+
/**
514+
* Invokes a JavaScript or XQuery module on the server.
515+
* The module must have been installed previously (typically with config.extlibs.write()).
516+
* @since 1.0
517+
* @param path - The path of the module in the modules database
518+
* @param variables - Optional object with variable name-value pairs
519+
* @param txid - Optional transaction ID or Transaction object
520+
* @returns A result provider that resolves to an array of EvalResult objects
521+
*/
522+
invoke(path: string, variables?: Record<string, any>, txid?: string | object): ResultProvider<EvalResult[]>;
523+
393524
/**
394525
* Releases the client and destroys the agent.
395526
* Call this method when you're done with the client to free up resources.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<hello>world</hello>
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
3+
*/
4+
5+
/// <reference path="../marklogic.d.ts" />
6+
7+
/**
8+
* Runtime validation tests for DatabaseClient convenience methods.
9+
*
10+
* These tests verify that the simplified convenience methods on DatabaseClient
11+
* have correct TypeScript types and work as expected.
12+
*
13+
* Run with: npm run test:compile && npx mocha test-typescript/*.js
14+
*/
15+
16+
const should = require('should');
17+
import type { DatabaseClient } from 'marklogic';
18+
19+
const testConfig = require('../etc/test-config.js');
20+
const marklogic = require('../lib/marklogic.js');
21+
22+
describe('DatabaseClient convenience methods runtime validation', function() {
23+
let client: DatabaseClient;
24+
const testUri = '/test-typescript/convenience-test.json';
25+
const testContent = { message: 'Convenience method test', timestamp: Date.now() };
26+
27+
before(function() {
28+
client = marklogic.createDatabaseClient(testConfig.restWriterConnection);
29+
});
30+
31+
after(function() {
32+
client.release();
33+
});
34+
35+
it('should create collection with createCollection()', async function() {
36+
const uris = await client.createCollection('typescript-convenience-test', testContent).result();
37+
38+
uris.should.be.an.Array();
39+
uris.length.should.equal(1);
40+
uris[0].should.be.a.String();
41+
});
42+
43+
it('should probe document with probe()', async function() {
44+
// Write a test document first
45+
await client.documents.write({
46+
uri: testUri,
47+
content: testContent,
48+
collections: ['typescript-convenience-test']
49+
}).result();
50+
51+
const exists = await client.probe(testUri).result();
52+
53+
exists.should.be.a.Boolean();
54+
exists.should.equal(true);
55+
});
56+
57+
it('should read document with read()', async function() {
58+
const contents = await client.read(testUri).result();
59+
60+
contents.should.be.an.Array();
61+
contents.length.should.equal(1);
62+
contents[0].should.have.property('message');
63+
});
64+
65+
it('should query collection with queryCollection()', async function() {
66+
const results = await client.queryCollection('typescript-convenience-test').result();
67+
68+
results.should.be.an.Array();
69+
results.length.should.be.greaterThan(0);
70+
});
71+
72+
it('should write collection with writeCollection()', async function() {
73+
const uriMap = {
74+
'/test-typescript/conv-1.json': { id: 1, name: 'Test 1' },
75+
'/test-typescript/conv-2.json': { id: 2, name: 'Test 2' }
76+
};
77+
78+
const uris = await client.writeCollection('typescript-convenience-test', uriMap).result();
79+
80+
uris.should.be.an.Array();
81+
uris.length.should.equal(2);
82+
});
83+
84+
it('should remove document with remove()', async function() {
85+
const uris = await client.remove('/test-typescript/conv-1.json', '/test-typescript/conv-2.json').result();
86+
87+
uris.should.be.an.Array();
88+
uris.length.should.equal(2);
89+
});
90+
91+
it('should remove collection with removeCollection()', async function() {
92+
const result = await client.removeCollection('typescript-convenience-test').result();
93+
94+
result.should.be.a.String();
95+
result.should.equal('typescript-convenience-test');
96+
});
97+
98+
it('should create timestamp with createTimestamp()', function() {
99+
const ts1 = client.createTimestamp();
100+
ts1.should.have.property('value');
101+
102+
const ts2 = client.createTimestamp('2025-11-25T12:00:00Z');
103+
ts2.should.have.property('value');
104+
if (ts2.value !== null) {
105+
ts2.value.should.equal('2025-11-25T12:00:00Z');
106+
}
107+
});
108+
109+
it('should evaluate JavaScript with eval()', async function() {
110+
const results = await client.eval('xdmp.toJSON({message: "Hello from eval"})').result();
111+
112+
results.should.be.an.Array();
113+
results.length.should.equal(1);
114+
results[0].should.have.property('format');
115+
results[0].should.have.property('datatype');
116+
results[0].should.have.property('value');
117+
results[0].format.should.equal('json');
118+
results[0].value.should.have.property('message');
119+
results[0].value.message.should.equal('Hello from eval');
120+
});
121+
122+
it('should evaluate JavaScript with variables', async function() {
123+
const results = await client.eval(
124+
'var x; xdmp.toJSON({result: x * 2})',
125+
{ x: 21 }
126+
).result();
127+
128+
results.should.be.an.Array();
129+
results[0].value.result.should.equal(42);
130+
});
131+
132+
it('should evaluate XQuery with xqueryEval()', async function() {
133+
const results = await client.xqueryEval('"Hello from XQuery"').result();
134+
135+
results.should.be.an.Array();
136+
results.length.should.equal(1);
137+
results[0].format.should.equal('text');
138+
results[0].datatype.should.equal('string');
139+
results[0].value.should.equal('Hello from XQuery');
140+
});
141+
142+
it('should evaluate XQuery with variables', async function() {
143+
const results = await client.xqueryEval(
144+
'declare variable $x as xs:integer external; $x * 3',
145+
{ x: 14 }
146+
).result();
147+
148+
results.should.be.an.Array();
149+
results[0].value.should.equal(42);
150+
});
151+
152+
it('should invoke a module with invoke()', async function() {
153+
const results = await client.invoke('/hello.xqy').result();
154+
155+
results.should.be.an.Array();
156+
results.length.should.equal(1);
157+
results[0].should.have.property('format');
158+
results[0].should.have.property('value');
159+
results[0].value.should.be.a.String();
160+
});
161+
});

typescript-test-project/test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ async function run() {
5656

5757
const wipeResult = await client.documents.wipe({uri: temporalUri, temporalCollection: temporalCollection}).result();
5858
console.log('wipe', wipeResult);
59+
60+
// Try out eval / invoke
61+
const evalResult = await client.eval('fn.currentDateTime()').result();
62+
console.log('eval', evalResult);
63+
64+
const xqueryEvalResult = await client.xqueryEval('fn:current-dateTime()').result();
65+
console.log('xqueryEval', xqueryEvalResult);
66+
67+
const invokeResult = await client.invoke('/hello.xqy').result();
68+
console.log('invoke', invokeResult);
69+
5970
} else {
6071
console.error(`❌ Connection failed: ${result.httpStatusCode} - ${result.httpStatusMessage}`);
6172
process.exit(1);

0 commit comments

Comments
 (0)