Source RapidContext_Storage.js

1/*
2 * RapidContext <https://www.rapidcontext.com/>
3 * Copyright (c) 2007-2023 Per Cederberg. All rights reserved.
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the BSD license.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * See the RapidContext LICENSE for more details.
13 */
14
15/**
16 * Provides functions for accessing the server storage (BETA).
17 * @namespace RapidContext.Storage
18 */
19(function (window) {
20
21    /**
22     * Returns a storage URL for a resource. If the resource is an
23     * object, its 'type' and 'id' properties will be used to form
24     * the path.
25     *
26     * @param {string|Object} pathOrObj the path or object
27     *
28     * @return {string} the URL to the resource
29     *
30     * @throws {Error} if the object didn't have both 'type' and 'id'
31     *     properties
32     *
33     * @private
34     */
35    function storageUrl(pathOrObj) {
36        var ident = (typeof(pathOrObj) === "string") ? pathOrObj : path(pathOrObj);
37        if (!ident) {
38            throw new Error("Invalid object or storage path");
39        }
40        return "rapidcontext/storage/" + ident.replace(/^\//, "");
41    }
42
43    /**
44     * Returns the storage path for an object. The object must have
45     * both the 'type' and 'id' properties set.
46     *
47     * @param {Object} obj the object to store
48     *
49     * @return {string} the storage path, or null if not available
50     *
51     * @memberof RapidContext.Storage
52     */
53    function path(obj) {
54        var type = obj && obj.type && obj.type.split("/")[0];
55        return (type && obj.id) ? type + "/" + obj.id : null;
56    }
57
58    /**
59     * Reads an object on a storage path. Note that this will return
60     * a JSON representation of the object, regardless of the actual
61     * object type.
62     *
63     * @param {string|Object} pathOrObj the path or object to read
64     *
65     * @return {Promise} a `RapidContext.Async` promise that will
66     *         resolve with the object data
67     *
68     * @memberof RapidContext.Storage
69     */
70    function read(pathOrObj) {
71        var url = storageUrl(pathOrObj);
72        url += url.endsWith("/") ? "index.json" : ".json";
73        return RapidContext.App.loadJSON(url, null, null);
74    }
75
76    /**
77     * Writes an object to a storage path. Any previous object on the
78     * specified path will be removed. If a path is specified without
79     * data, only the removal is performed.
80     *
81     * @param {string|Object} pathOrObj the path or object to write
82     * @param {Object} [data] the object to write (if path was string)
83     *
84     * @return {Promise} a `RapidContext.Async` promise that will
85     *         resolve when the object has been written
86     *
87     * @memberof RapidContext.Storage
88     */
89    function write(pathOrObj, data) {
90        var url = storageUrl(pathOrObj);
91        if (typeof(pathOrObj) == "string" && data == null) {
92            return RapidContext.App.loadXHR(url, null, { method: "DELETE" });
93        } else {
94            var headers = { "Content-Type": "application/json" };
95            var opts = { method: "POST", headers: headers };
96            return RapidContext.App.loadXHR(url + ".yaml", data || pathOrObj, opts);
97        }
98    }
99
100    /**
101     * Updates an object with properties from a partial object. The
102     * properties in the partial object will overwrite any previous
103     * properties with the same name in the destination object. No
104     * merging of property values will be performed.
105     *
106     * @param {string|Object} pathOrObj the path or object to write
107     * @param {Object} [data] the partial object (changes) to write
108     *
109     * @return {Promise} a `RapidContext.Async` promise that will
110     *         resolve with the updated data object on success
111     *
112     * @memberof RapidContext.Storage
113     */
114    function update(pathOrObj, data) {
115        var url = storageUrl(pathOrObj);
116        var newPath = path(data);
117        var headers = { "Content-Type": "application/json" };
118        if (newPath && newPath != path(pathOrObj)) {
119            headers["X-Move-To"] = newPath + ".yaml";
120        }
121        var opts = { method: "PATCH", headers: headers };
122        return RapidContext.App.loadJSON(url, data || pathOrObj, opts);
123    }
124
125    // Create namespaces & export symbols
126    var RapidContext = window.RapidContext || (window.RapidContext = {});
127    var Storage = RapidContext.Storage || (RapidContext.Storage = {});
128    Object.assign(Storage, { path, read, write, update });
129
130})(this);
131