aiiinotate 0.4.2 → 0.4.3
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/package.json
CHANGED
|
@@ -346,7 +346,8 @@ class Annotations2 extends CollectionAbstract {
|
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
|
-
* implementation of the IIIF Search API 1.0
|
|
349
|
+
* implementation of the IIIF Search API 1.0.
|
|
350
|
+
* function arguments have been validated by JSONSchemas at route-level so they're clean.
|
|
350
351
|
*
|
|
351
352
|
* NOTE:
|
|
352
353
|
* - only `motivation` and `q` search params are implemented
|
|
@@ -354,6 +355,7 @@ class Annotations2 extends CollectionAbstract {
|
|
|
354
355
|
* implemented for `q` and `motivation` (in the IIIF specs, you can supply
|
|
355
356
|
* multiple space-separated values and the server should return all partial
|
|
356
357
|
* matches to any of those strings.)
|
|
358
|
+
* - non-standard `canvasMin` and `canvasMax` parameters are implemented: search by annotation's target canvas position.
|
|
357
359
|
*
|
|
358
360
|
* see:
|
|
359
361
|
* https://iiif.io/api/search/1.0/
|
|
@@ -361,11 +363,13 @@ class Annotations2 extends CollectionAbstract {
|
|
|
361
363
|
*
|
|
362
364
|
* @param {string} queryUrl
|
|
363
365
|
* @param {string} manifestShortId
|
|
364
|
-
* @param {string} q
|
|
365
|
-
* @param {"painting"|"non-painting"|"commenting"|"describing"|"tagging"|"linking"} motivation
|
|
366
|
+
* @param {string?} q
|
|
367
|
+
* @param {"painting"|"non-painting"|"commenting"|"describing"|"tagging"|"linking"?} motivation
|
|
368
|
+
* @param {number?} canvasMin - minimum value of `on.canvasIdx`, inclusive
|
|
369
|
+
* @param {number?} canvasMax - maximum value of `on.canvasIdx`, inclusive
|
|
366
370
|
* @returns {object} annotationList containing results
|
|
367
371
|
*/
|
|
368
|
-
async search(queryUrl, manifestShortId, q, motivation) {
|
|
372
|
+
async search(queryUrl, manifestShortId, q, motivation, canvasMin, canvasMax) {
|
|
369
373
|
const
|
|
370
374
|
queryBase = { "on.manifestShortId": manifestShortId },
|
|
371
375
|
queryFilters = { $and: [] };
|
|
@@ -379,7 +383,7 @@ class Annotations2 extends CollectionAbstract {
|
|
|
379
383
|
{ "resource.chars": q }
|
|
380
384
|
]
|
|
381
385
|
});
|
|
382
|
-
}
|
|
386
|
+
};
|
|
383
387
|
if ( motivation ) {
|
|
384
388
|
queryFilters.$and.push(
|
|
385
389
|
motivation === "non-painting"
|
|
@@ -388,6 +392,23 @@ class Annotations2 extends CollectionAbstract {
|
|
|
388
392
|
? { motivation: "sc:painting" }
|
|
389
393
|
: { motivation: `oa:${motivation}` }
|
|
390
394
|
);
|
|
395
|
+
};
|
|
396
|
+
// TODO test
|
|
397
|
+
if ( canvasMin ) {
|
|
398
|
+
// if canvasMax is undefined, then search for canvasIdx===canvasMin
|
|
399
|
+
if ( !canvasMax ) {
|
|
400
|
+
queryFilters.$and.push({ "on.canvasIdx": canvasMin })
|
|
401
|
+
// if canvasMin and canvasMax, canvasIdx must be in [canvasMin, canvasMax] (inclusive).
|
|
402
|
+
} else {
|
|
403
|
+
queryFilters.$and.push({
|
|
404
|
+
"on.canvasIdx": {
|
|
405
|
+
$and: [
|
|
406
|
+
{ $gte: canvasMin },
|
|
407
|
+
{ $lte: canvasMax },
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
})
|
|
411
|
+
}
|
|
391
412
|
}
|
|
392
413
|
const query =
|
|
393
414
|
queryFilters.$and.length
|
|
@@ -4,12 +4,12 @@ import CollectionAbstract from "#data/collectionAbstract.js";
|
|
|
4
4
|
|
|
5
5
|
/** @typedef {import("#types").FastifyInstanceType} FastifyInstanceType */
|
|
6
6
|
|
|
7
|
-
/** @typedef {
|
|
7
|
+
/** @typedef {Annotations3} Annotations3InstanceType */
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @extends {CollectionAbstract}
|
|
11
11
|
*/
|
|
12
|
-
class
|
|
12
|
+
class Annotations3 extends CollectionAbstract {
|
|
13
13
|
/**
|
|
14
14
|
* @param {FastifyInstanceType} fastify
|
|
15
15
|
*/
|
|
@@ -17,14 +17,10 @@ class Annnotations3 extends CollectionAbstract {
|
|
|
17
17
|
super(fastify, "annotations3");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
notImplementedError() {
|
|
21
|
-
throw this.errorNoAction(`${this.constructor.name}: not implemented`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
export default fastifyPlugin((fastify, options, done) => {
|
|
27
|
-
fastify.decorate("
|
|
23
|
+
fastify.decorate("annotations3", new Annotations3(fastify));
|
|
28
24
|
done();
|
|
29
25
|
}, {
|
|
30
26
|
name: "annotations3",
|
|
@@ -20,8 +20,8 @@ class CollectionAbstractError extends Error {
|
|
|
20
20
|
*/
|
|
21
21
|
constructor(collectionName, operation, message, errInfo) {
|
|
22
22
|
const
|
|
23
|
-
collInfo = collectionName ? `on collection '${collectionName}'
|
|
24
|
-
operationInfo = operation ?
|
|
23
|
+
collInfo = collectionName ? `on collection '${collectionName}'` : "",
|
|
24
|
+
operationInfo = operation ? `, when performing operation '${operation.toLocaleLowerCase()}'`: "";
|
|
25
25
|
super(`CollectionAbstractError: ${collInfo} ${operationInfo}: ${message}`);
|
|
26
26
|
this.info = errInfo;
|
|
27
27
|
}
|
|
@@ -176,6 +176,10 @@ class CollectionAbstract {
|
|
|
176
176
|
throw this.errorConstructor(operation)(err.message, err.errorResponse);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
notImplementedError() {
|
|
180
|
+
throw this.errorNoAction("not implemented");
|
|
181
|
+
}
|
|
182
|
+
|
|
179
183
|
//////////////////////////////////////
|
|
180
184
|
// INSERT/UPDATE
|
|
181
185
|
|
package/src/data/routes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fastifyPlugin from "fastify-plugin"
|
|
2
2
|
|
|
3
|
-
import { pathToUrl, ajvCompile, inspectObj, getFirstNonEmptyPair } from "#utils/utils.js";
|
|
3
|
+
import { pathToUrl, ajvCompile, inspectObj, getFirstNonEmptyPair, visibleLog } from "#utils/utils.js";
|
|
4
4
|
import { returnError, makeResponsePostSchema } from "#utils/routeUtils.js";
|
|
5
5
|
|
|
6
6
|
/** @typedef {import("#types").Manifests2InstanceType} Manifests2InstanceType */
|
|
@@ -53,22 +53,42 @@ function commonRoutes(fastify, options, done) {
|
|
|
53
53
|
motivation: {
|
|
54
54
|
type: "string",
|
|
55
55
|
enum: ["painting", "non-painting", "commenting", "describing", "tagging", "linking"]
|
|
56
|
+
},
|
|
57
|
+
canvasMin: {
|
|
58
|
+
type: "integer",
|
|
59
|
+
minimum: 0
|
|
60
|
+
},
|
|
61
|
+
canvasMax: {
|
|
62
|
+
type: ["integer","null"],
|
|
63
|
+
minimum: 0
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
},
|
|
59
67
|
response: {
|
|
60
68
|
200: iiifAnnotationListSchema
|
|
61
69
|
}
|
|
70
|
+
},
|
|
71
|
+
preValidation: async (request, reply) => {
|
|
72
|
+
const
|
|
73
|
+
{ canvasMin, canvasMax } = request.query,
|
|
74
|
+
error = new Error(`Error validating GET search-api route: 'canvasMin' must be smaller than 'canvasMax'. If 'canvasMax' is defined, 'canvasMin' must be defined as well. Got canvasMin=${canvasMin}, canvasMax=${canvasMax}`);
|
|
75
|
+
if (
|
|
76
|
+
(canvasMin == null && canvasMax != null)
|
|
77
|
+
|| (canvasMin > canvasMax)
|
|
78
|
+
) {
|
|
79
|
+
returnError(request, reply, error, {}, 400);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
62
82
|
}
|
|
63
83
|
},
|
|
64
84
|
async (request, reply) => {
|
|
65
85
|
const
|
|
66
86
|
queryUrl = pathToUrl(request.url),
|
|
67
87
|
{ iiifSearchVersion, manifestShortId } = request.params,
|
|
68
|
-
{ q, motivation } = request.query;
|
|
88
|
+
{ q, motivation, canvasMin, canvasMax } = request.query;
|
|
69
89
|
|
|
70
90
|
if ( iiifSearchVersion===1 ) {
|
|
71
|
-
return await annotations2.search(queryUrl, manifestShortId, q, motivation);
|
|
91
|
+
return await annotations2.search(queryUrl, manifestShortId, q, motivation, canvasMin, canvasMax);
|
|
72
92
|
} else {
|
|
73
93
|
annotations3.notImplementedError();
|
|
74
94
|
}
|
package/src/data/routes.test.js
CHANGED
|
@@ -32,6 +32,19 @@ test("test common routes", async (t) => {
|
|
|
32
32
|
throw err;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
////////////////////////////////////////////////
|
|
36
|
+
// GET routes
|
|
37
|
+
|
|
38
|
+
await t.test("test route /search-api/:iiifSearchVersion/manifests/:manifestShortId/search", async (t) => {
|
|
39
|
+
|
|
40
|
+
// TODO
|
|
41
|
+
// q
|
|
42
|
+
// motivation
|
|
43
|
+
// canvasMin
|
|
44
|
+
// canvasMax
|
|
45
|
+
|
|
46
|
+
})
|
|
47
|
+
|
|
35
48
|
////////////////////////////////////////////////
|
|
36
49
|
// DELETE routes
|
|
37
50
|
|