Skip to content

Commit 4466ba3

Browse files
snejborrrden
authored andcommitted
JS Server: Implemented blobs for /updateDatabase
1 parent ab8de36 commit 4466ba3

File tree

2 files changed

+41
-14
lines changed

2 files changed

+41
-14
lines changed

servers/javascript/src/tdk.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,26 +142,31 @@ export class TDKImpl implements tdk.TDK, AsyncDisposable {
142142
const coll = db.getCollection(normalizeCollectionID(update.collection));
143143
const doc = await coll.getDocument(update.documentID);
144144
if (!doc) throw new HTTPError(404, `No document "${update.documentID}"`);
145+
146+
const updatePath = (pathStr: string, value: cbl.CBLValue | undefined): void => {
147+
if (!KeyPathCache.path(pathStr).write(doc, value))
148+
throw new HTTPError(400, `Invalid path ${pathStr} in doc ${update.documentID}`);
149+
};
150+
145151
switch (update.type) {
146152
case 'UPDATE': {
147153
if (update.updatedProperties) {
148154
for (const props of update.updatedProperties) {
149-
for (const pathStr of Object.getOwnPropertyNames(props)) {
150-
if (!KeyPathCache.path(pathStr).write(doc, props[pathStr]))
151-
throw new HTTPError(400, `Invalid path ${pathStr} in doc ${update.documentID}`);
152-
}
155+
for (const pathStr of Object.getOwnPropertyNames(props))
156+
updatePath(pathStr, props[pathStr]);
153157
}
154158
}
155159
if (update.removedProperties) {
156160
for (const props of update.removedProperties) {
157-
for (const pathStr of props) {
158-
if (!KeyPathCache.path(pathStr).write(doc, undefined))
159-
throw new HTTPError(400, `Invalid path ${pathStr} in doc ${update.documentID}`);
160-
}
161+
for (const pathStr of props)
162+
updatePath(pathStr, undefined);
161163
}
162164
}
163165
if (update.updatedBlobs) {
164-
throw new HTTPError(501, "updatedBlobs is not implemented yet"); //TODO
166+
for (const pathStr of Object.getOwnPropertyNames(update.updatedBlobs)) {
167+
const blob = await this.#downloadBlob(update.updatedBlobs[pathStr]);
168+
updatePath(pathStr, blob);
169+
}
165170
}
166171
break;
167172
}
@@ -190,12 +195,19 @@ export class TDKImpl implements tdk.TDK, AsyncDisposable {
190195
throw new HTTPError(501, "Unimplemented replication feature(s)");
191196
const collCfg: cbl.ReplicatorCollectionConfig = { };
192197
if (rq.config.replicatorType !== 'pull') {
198+
if (colls.pushFilter) throw new HTTPError(501, "Push filter is not supported");
193199
collCfg.push = {
194200
continuous: rq.config.continuous,
195201
//filter: colls.pushFilter //TODO
196202
};
197203
}
198204
if (rq.config.replicatorType !== 'push') {
205+
if (colls.pullFilter)
206+
throw new HTTPError(501, "Pull filter is not supported");
207+
if (colls.documentIDs)
208+
throw new HTTPError(501, "List of docIDs is not supported");
209+
if (colls.conflictResolver)
210+
throw new HTTPError(501, "Conflict resolver is not supported");
199211
collCfg.pull = {
200212
continuous: rq.config.continuous,
201213
channels: colls.channels,
@@ -401,7 +413,7 @@ export class TDKImpl implements tdk.TDK, AsyncDisposable {
401413
obj = obj as cbl.CBLDictionary;
402414
if (obj["@type"] === "blob" && typeof obj.digest === "string") {
403415
++totalBlobs;
404-
return await this.#downloadBlob(obj as unknown as cbl.Bloblike, datasetURL);
416+
return await this.#downloadDataSetBlob(obj as unknown as cbl.Bloblike, datasetURL);
405417
}
406418
for (const key of Object.getOwnPropertyNames(obj)) {
407419
const blob = await _installBlobs(obj[key]); // recurse
@@ -416,16 +428,31 @@ export class TDKImpl implements tdk.TDK, AsyncDisposable {
416428
}
417429

418430

419-
async #downloadBlob(blobMeta: cbl.Bloblike, datasetURL: string): Promise<cbl.NewBlob> {
431+
async #downloadDataSetBlob(blobMeta: cbl.Bloblike, datasetURL: string): Promise<cbl.NewBlob> {
420432
check(blobMeta.digest.startsWith("sha1-"), "Unexpected prefix in blob digest");
421433
const digest = blobMeta.digest.substring(5).replaceAll('/', '_');
422434
const blobURL = `${datasetURL}Attachments/${digest}.blob`;
423435
this.#logger.info ` - downloading blob ${blobMeta.digest}`;
436+
const contents = await this.#downloadBlobContents(blobURL);
437+
return new cbl.NewBlob(contents, blobMeta.content_type);
438+
}
439+
440+
441+
async #downloadBlob(blobURL: string): Promise<cbl.NewBlob> {
442+
if (blobURL.endsWith(".zip"))
443+
throw new HTTPError(501, "Unzipping blobs is not supported");
444+
const contents = await this.#downloadBlobContents(blobURL);
445+
const type = blobURL.endsWith(".jpg") ? "image/jpeg" : "application/octet-stream";
446+
return new cbl.NewBlob(contents, type);
447+
}
448+
449+
450+
async #downloadBlobContents(blobURL: string): Promise<Uint8Array> {
424451
const response = await fetch(blobURL);
425452
if (response.status !== 200)
426453
throw new HTTPError(502, `Unable to load blob from <${blobURL}>: ${response.status} ${response.statusText}`);
427454
const data = await response.arrayBuffer();
428-
return new cbl.NewBlob(new Uint8Array(data), blobMeta.content_type);
455+
return new Uint8Array(data);
429456
}
430457

431458

servers/javascript/src/tdkSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export interface DatabaseUpdateItem {
9191
documentID: cbl.DocID,
9292
updatedProperties?: cbl.JSONObject[],
9393
removedProperties?: string[],
94-
updatedBlobs?: Record<string,string>,
94+
updatedBlobs?: Record<string,string>, // KeyPath -> blob URL
9595
}
9696

9797

@@ -172,7 +172,7 @@ export interface DocumentReplication {
172172
collection: string,
173173
documentID: cbl.DocID,
174174
isPush?: boolean,
175-
flags?: Array<'deleted'>; //TODO: other flags?
175+
flags?: Array<'deleted' | 'accessRemoved'>;
176176
error?: ErrorInfo
177177
}
178178

0 commit comments

Comments
 (0)