From 13d967c0e7b80f486990dd66fe3b9ce002d07a28 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 17 Sep 2023 00:57:51 +0500 Subject: [PATCH 1/3] Optimize projection func of kinds.js module. Add tests --- lib/kinds.js | 19 +++++++----- test/kinds.js | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 test/kinds.js diff --git a/lib/kinds.js b/lib/kinds.js index c957f54..cedf58a 100644 --- a/lib/kinds.js +++ b/lib/kinds.js @@ -13,16 +13,19 @@ const STORE = ['persistent', 'memory']; const ALLOW = ['write', 'append', 'read']; const projection = (kind, meta, root) => { - const { scope = 'local', store = 'memory', allow = 'write' } = meta; - const metadata = { ...meta, kind, scope, store, allow }; - const { schema, fields } = meta; - if (!schema && !fields) throw new Error('Invalid Projection'); - metadata.parent = schema; - const parent = root.findReference(schema); + const { schema: schemaName, fields: fieldNames } = meta; + if (!schemaName) throw new Error('Invalid Projection: "schema" expected'); + if (!Array.isArray(fieldNames) || fieldNames.length === 0) + throw new Error('Invalid Projection: non-empty "fields" array expected'); + if (!root || typeof root.findReference !== 'function') + throw new Error('Invalid Projection: "root" should satisfy Schema API'); const defs = {}; - for (const key of fields) { - defs[key] = parent.fields[key]; + const referencedFields = root.findReference(schemaName)?.fields; + if (referencedFields) { + for (const name of fieldNames) defs[name] = referencedFields[name]; } + const { scope = 'local', store = 'memory', allow = 'write', ...rest } = meta; + const metadata = { kind, scope, store, allow, parent: schemaName, ...rest }; return { defs, metadata }; }; diff --git a/test/kinds.js b/test/kinds.js new file mode 100644 index 0000000..b58d2e6 --- /dev/null +++ b/test/kinds.js @@ -0,0 +1,81 @@ +'use strict'; + +const metatests = require('metatests'); +const { getKindMetadata } = require('../lib/kinds.js'); + +metatests.test('Kinds: Projection', (test) => { + const getProjectionMeta = getKindMetadata.bind(null, 'projection'); + { + const meta = { + schema: 'Account', + fields: ['login', 'password'], + etc: ['another', 'field'], + }; + test.throws( + () => getProjectionMeta({}, null), + new Error('Invalid Projection: "schema" expected'), + ); + test.throws( + () => getProjectionMeta({ schema: 'Account' }, null), + new Error('Invalid Projection: non-empty "fields" array expected'), + ); + test.throws( + () => getProjectionMeta(meta, null), + new Error('Invalid Projection: "root" should satisfy Schema API'), + ); + test.doesNotThrow(() => + getProjectionMeta(meta, { findReference: new Function() }), + ); + } + + { + const meta = { + schema: 'Account', + fields: ['login', 'password'], + etc: ['another', 'field'], + }; + const { defs, metadata } = getProjectionMeta(meta, { + findReference: new Function(), + }); + test.strictEqual(metadata.kind, 'projection'); + test.strictEqual(metadata.scope, 'local'); + test.strictEqual(metadata.store, 'memory'); + test.strictEqual(metadata.allow, 'write'); + test.strictEqual(metadata.parent, 'Account'); + test.strictEqual(metadata.fields, ['login', 'password']); + test.strictEqual(Object.keys(defs).length, 0); + } + + { + const meta = { + scope: 'system', + store: 'persistent', + allow: 'append', + schema: 'Account', + fields: ['login', 'password', 'otp'], + }; + const root = { + findReference: (schemaName) => ({ + name: schemaName, + fields: { + login: 'any', + password: 'string', + otpNotMentioned: 'here', + }, + }), + }; + const { defs, metadata } = getProjectionMeta(meta, root); + test.strictEqual(metadata.kind, 'projection'); + test.strictEqual(metadata.scope, 'system'); + test.strictEqual(metadata.store, 'persistent'); + test.strictEqual(metadata.allow, 'append'); + test.strictEqual(metadata.parent, 'Account'); + test.strictEqual(metadata.fields, ['login', 'password', 'otp']); + test.strictEqual(Object.keys(defs).length, 3); + test.strictEqual(defs.login, 'any'); + test.strictEqual(defs.password, 'string'); + test.strictEqual(defs.otp, undefined); + } + + test.end(); +}); From 862b5d6ec47df9f76ca4f5d94ecb5fe393260193 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 20 Sep 2023 21:18:36 +0500 Subject: [PATCH 2/3] Treat projection as a private case of 'kindMemory' --- lib/kinds.js | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/kinds.js b/lib/kinds.js index cedf58a..9590d03 100644 --- a/lib/kinds.js +++ b/lib/kinds.js @@ -12,6 +12,25 @@ const SCOPE = ['application', 'global', 'local']; const STORE = ['persistent', 'memory']; const ALLOW = ['write', 'append', 'read']; +const KIND_STORED_DEFAULT_META = { + scope: 'application', + store: 'persistent', + allow: 'write', +}; +const KIND_MEMORY_DEFAULT_META = { + scope: 'local', + store: 'memory', + allow: 'write', +}; + +const withDefaults = (meta, defaults, extra) => { + const result = { ...meta, ...extra }; + for (const [key, defaultValue] of Object.entries(defaults)) { + if (result[key] === undefined) result[key] = defaultValue; + } + return result; +}; + const projection = (kind, meta, root) => { const { schema: schemaName, fields: fieldNames } = meta; if (!schemaName) throw new Error('Invalid Projection: "schema" expected'); @@ -24,29 +43,30 @@ const projection = (kind, meta, root) => { if (referencedFields) { for (const name of fieldNames) defs[name] = referencedFields[name]; } - const { scope = 'local', store = 'memory', allow = 'write', ...rest } = meta; - const metadata = { kind, scope, store, allow, parent: schemaName, ...rest }; + const metadata = withDefaults(meta, KIND_MEMORY_DEFAULT_META, { + kind, + parent: schemaName, + }); return { defs, metadata }; }; const kindStored = (kind, meta, root) => { - const { scope = 'application', store = 'persistent', allow = 'write' } = meta; - const metadata = { ...meta, kind, scope, store, allow }; + if (!root) throw new Error('"root" schema expected'); const id = root.name ? `${toLowerCamel(root.name)}Id` : 'id'; const defs = { [id]: '?string' }; + const metadata = withDefaults(meta, KIND_STORED_DEFAULT_META, { kind }); return { defs, metadata }; }; -const kindMemory = (kind, meta) => { - const { scope = 'local', store = 'memory', allow = 'write' } = meta; - return { metadata: { ...meta, kind, scope, store, allow }, defs: {} }; +const kindMemory = (kind, meta, root) => { + if (kind === 'projection') return projection(kind, meta, root); + const metadata = withDefaults(meta, KIND_MEMORY_DEFAULT_META, { kind }); + return { defs: {}, metadata }; }; const getKindMetadata = (kind, meta = {}, root) => { - if (kind === 'projection') return projection(kind, meta, root); - if (KIND_MEMORY.includes(kind)) return kindMemory(kind, meta); - if (KIND_STORED.includes(kind)) return kindStored(kind, meta, root); - return kindMemory(kind, meta); + const processKind = KIND_STORED.includes(kind) ? kindStored : kindMemory; + return processKind(kind, meta, root); }; module.exports = { From 82d34b708f800605a324bd5a85cdb914545d1295 Mon Sep 17 00:00:00 2001 From: Timur Shemsedinov Date: Tue, 24 Oct 2023 19:55:14 +0300 Subject: [PATCH 3/3] Apply suggestions from code review --- lib/kinds.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/kinds.js b/lib/kinds.js index 9590d03..f896834 100644 --- a/lib/kinds.js +++ b/lib/kinds.js @@ -17,6 +17,7 @@ const KIND_STORED_DEFAULT_META = { store: 'persistent', allow: 'write', }; + const KIND_MEMORY_DEFAULT_META = { scope: 'local', store: 'memory',