diff --git a/lib/app/base-chips/field-types/cached-value.js b/lib/app/base-chips/field-types/cached-value.js --- a/lib/app/base-chips/field-types/cached-value.js +++ b/lib/app/base-chips/field-types/cached-value.js @@ -56,16 +56,20 @@ when, async (context, path, event_params, resource) => { const cache_resource_id = await resource_id_getter( + context, path, event_params, resource ); return app.run_action( - new app.Sealious.SuperContext(), + new app.Sealious.SuperContext(context), ["collections", collection.name, cache_resource_id], "edit", { - [field_name]: await get_value(cache_resource_id), + [field_name]: await get_value( + context, + cache_resource_id + ), } ); } @@ -123,7 +127,7 @@ const cache_value = await this.encode( context, params, - await params.get_value(resource.sealious_id) + await params.get_value(context, resource.sealious_id) ); await app.Datastore.update( collection.name, @@ -143,8 +147,13 @@ ), }; }, - decode: function(context, params, { value }) { - return this._call_base_method("decode", context, params, value); + decode: function(context, params, value_in_db) { + return this._call_base_method( + "decode", + context, + params, + value_in_db ? value_in_db.value : null + ); }, format: function(context, params, decoded_value, format) { const base_field_type = app.FieldType(params.base_field_type.name); diff --git a/lib/app/base-chips/field-types/cached-value.subtest.js b/lib/app/base-chips/field-types/cached-value.subtest.js --- a/lib/app/base-chips/field-types/cached-value.subtest.js +++ b/lib/app/base-chips/field-types/cached-value.subtest.js @@ -34,7 +34,7 @@ min: 0, }, }, - get_value: async resource_id => { + get_value: async (context, resource_id) => { return app.run_action( new app.Sealious.SuperContext(), ["collections", "accounts", resource_id], @@ -90,7 +90,7 @@ values: Object.values(action_to_status), }, }, - get_value: async resource_id => { + get_value: async (context, resource_id) => { const [latest_action] = await app.Datastore.aggregate( "actions", [ @@ -262,10 +262,20 @@ function make_refresh_on() { return { - "post:actions:create": async (path, event_params, resource) => { + "post:actions:create": async ( + context, + path, + event_params, + resource + ) => { return resource.body.account; }, - "post:actions\\..*:edit": async (path, event_params, resource) => { + "post:actions\\..*:edit": async ( + context, + path, + event_params, + resource + ) => { return resource.body.account; }, }; diff --git a/lib/app/base-chips/field-types/single_reference.js b/lib/app/base-chips/field-types/single_reference.js --- a/lib/app/base-chips/field-types/single_reference.js +++ b/lib/app/base-chips/field-types/single_reference.js @@ -161,7 +161,7 @@ field_name ); filter[ - temp_field_name + ".0." + field_value_path + `${temp_field_name}.0.body.${field_name}` ] = field.filter_to_query(context, request_filter[field_name]); } return Promise.props(filter).then(function(_filter) { diff --git a/lib/app/base-chips/field-types/single_reference.subtest.js b/lib/app/base-chips/field-types/single_reference.subtest.js --- a/lib/app/base-chips/field-types/single_reference.subtest.js +++ b/lib/app/base-chips/field-types/single_reference.subtest.js @@ -3,6 +3,10 @@ const axios = require("axios"); const { create_resource_as } = locreq("test_utils"); const { with_running_app } = locreq("test_utils/with-test-app.js"); +const assert_throws_async = locreq("test_utils/assert_throws_async.js"); +const A = "/api/v1/collections/A"; +const B = "/api/v1/collections/B"; +const C = "/api/v1/collections/C"; describe("single_reference", () => { async function create_referencing_collections(app) { @@ -28,66 +32,129 @@ } it("should not allow a value that is not an existing id", async () => - with_running_app(async ({ app, base_url }) => { + with_running_app(async ({ app, base_url, rest_api }) => { await create_referencing_collections(app); - return axios - .post(`${base_url}/api/v1/collections/A`, { - reference_to_b: "non-existing-id", - }) - .then(res => { - throw "This should not succeed"; - }) - .catch(res => + await assert_throws_async( + () => + rest_api.post(A, { + reference_to_b: "non-existing-id", + }), + e => assert.equal( - res.response.data.data.reference_to_b.message, + e.response.data.data.reference_to_b.message, "Nie masz dostępu do danego zasobu z kolekcji B lub on nie istnieje." ) - ); + ); })); it("should allow a value that exists in B", async () => - with_running_app(async ({ app, base_url }) => { - create_referencing_collections(app); - const b_id = (await axios.post(`${base_url}/api/v1/collections/B`, { - number: 1, - })).data.id; - return axios.post(`${base_url}/api/v1/collections/A`, { - reference_to_b: b_id, + with_running_app(async ({ app, base_url, rest_api }) => { + await create_referencing_collections(app); + const { id } = await rest_api.post(B, { number: 1 }); + await rest_api.post(A, { + reference_to_b: id, }); })); it("should not allow a value that exists in B but does not meet the filter criteria", async () => - with_running_app(async ({ app, base_url }) => { - create_referencing_collections(app); - const b_id = (await axios.post(`${base_url}/api/v1/collections/B`, { - number: 0, - })).data.id; - - return axios - .post(`${base_url}/api/v1/collections/A`, { - filtered_reference_to_b: b_id, - }) - .then(response => { - throw "This should fail"; - }) - .catch(error => { + with_running_app(async ({ app, base_url, rest_api }) => { + await create_referencing_collections(app); + const { id } = await rest_api.post(B, { number: 0 }); + await assert_throws_async( + () => + rest_api.post(A, { + filtered_reference_to_b: id, + }), + e => assert.equal( - error.response.data.data.filtered_reference_to_b - .message, + e.response.data.data.filtered_reference_to_b.message, "Nie masz dostępu do danego zasobu z kolekcji B lub on nie istnieje." - ); - }); + ) + ); })); it("should allow a value that exists in B but does not meet the filter criteria", async () => - with_running_app(async ({ app, base_url }) => { - create_referencing_collections(app); - const b_id = (await axios.post(`${base_url}/api/v1/collections/B`, { - number: 1, - })).data.id; + with_running_app(async ({ app, base_url, rest_api }) => { + await create_referencing_collections(app); + const { id } = await rest_api.post(B, { number: 1 }); + await rest_api.post(A, { filtered_reference_to_b: id }); + })); + + it("should be filterable by referenced collection fields", async () => + with_running_app(async ({ app, base_url, rest_api }) => { + await create_referencing_collections(app); - return axios.post(`${base_url}/api/v1/collections/A`, { - filtered_reference_to_b: b_id, + for (let number of [1, 2, 3]) { + const { id } = await rest_api.post(B, { number }); + await rest_api.post(A, { reference_to_b: id }); + } + + const response = await rest_api.get( + `${A}?filter[reference_to_b][number]=3&format[reference_to_b]=expand` + ); + assert.deepEqual(response.length, 1); + assert.deepEqual(response[0].body.reference_to_b.body.number, 3); + })); + + it("should be filterable by referenced collection field of referenced collection field", async () => + with_running_app(async ({ app, base_url, rest_api }) => { + // A => B => C + await app.createChip(app.Sealious.Collection, { + name: "A", + fields: [ + { + name: "reference_to_b", + type: "single_reference", + params: { collection: "B" }, + }, + ], }); + await app.createChip(app.Sealious.Collection, { + name: "B", + fields: [ + { + name: "reference_to_c", + type: "single_reference", + params: { collection: "C" }, + }, + ], + }); + + await app.createChip(app.Sealious.Collection, { + name: "C", + fields: [ + { + name: "number", + type: "int", + }, + ], + }); + let c_ids = []; + let b_ids = []; + for (let number of [1, 2, 3]) { + const { id } = await rest_api.post(C, { number }); + c_ids.push(id); + } + for (let c_id of c_ids) { + const { id } = await rest_api.post(B, { + reference_to_c: c_id, + }); + b_ids.push(id); + } + for (let b_id of b_ids) { + const a = await rest_api.post(A, { reference_to_b: b_id }); + } + + const result = await rest_api + .get( + `${A}?filter[reference_to_b][reference_to_c][number]=3&format[reference_to_b]=deep-expand:2` + ) + .catch(console.error); + + assert.deepEqual(result.length, 1); + assert.deepEqual( + result[0].body.reference_to_b.body.reference_to_c.body.number, + 3 + ); })); }); diff --git a/lib/app/event-manager.js b/lib/app/event-manager.js --- a/lib/app/event-manager.js +++ b/lib/app/event-manager.js @@ -20,7 +20,7 @@ "post", async (context, path, params, intent) => { const token = (await this.app.run_action( - new this.app.Sealious.SuperContext(), + new this.app.Sealious.SuperContext(context), ["collections", collection_name, intent.id], "show" )).body.token; diff --git a/lib/app/run-action-curry.js b/lib/app/run-action-curry.js --- a/lib/app/run-action-curry.js +++ b/lib/app/run-action-curry.js @@ -15,9 +15,7 @@ function run_action_curry(app) { return function run_action(context, subject_path, action_name, params) { - const original_context = context.is_super - ? context.original_context - : context; + const original_context = context.original_context || context; if (!ActionResultCache.has(original_context)) { ActionResultCache.set(original_context, new Map()); diff --git a/lib/super-context.js b/lib/super-context.js --- a/lib/super-context.js +++ b/lib/super-context.js @@ -13,6 +13,10 @@ ret.original_context = regular_context; + while (ret.original_context.original_context) { + ret.original_context = ret.original_context.original_context; + } + return ret; }