From 0735eaa523da5d05900837fc6441b3d3a406f038 Mon Sep 17 00:00:00 2001 From: Michael Shanks Date: Fri, 11 Sep 2020 21:24:52 +0100 Subject: [PATCH] stop coercing values on the server - do on client instead --- .../EventsEditor/actions/CreateRecord.svelte | 9 +++-- .../EventsEditor/actions/SaveFields.svelte | 16 +++++---- .../EventsEditor/actions/UpdateRecord.svelte | 20 +++++------ packages/client/src/api/index.js | 33 +++++++++++++++++-- packages/server/src/api/controllers/record.js | 29 ---------------- 5 files changed, 56 insertions(+), 51 deletions(-) diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte index 945a30c45c..b84dcd58a4 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/CreateRecord.svelte @@ -19,10 +19,13 @@ const modelFields = modelId => { const model = $backendUiStore.models.find(m => m._id === modelId) - return Object.keys(model.schema) + return Object.keys(model.schema).map(k => ({ + name: k, + type: model.schema[k].type, + })) } - $: fieldNames = + $: schemaFields = parameters && parameters.modelId ? modelFields(parameters.modelId) : [] const onFieldsChanged = e => { @@ -42,7 +45,7 @@ {#if parameters.modelId} {/if} diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte index 4da1d4d38c..185964bd51 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/SaveFields.svelte @@ -26,7 +26,7 @@ (parameterFields && runtimeToReadableBinding( bindableProperties, - parameterFields[name] + parameterFields[name].value )) || "", })) @@ -56,10 +56,12 @@ const newParameterFields = {} for (let field of fields) { if (field.name) { - newParameterFields[field.name] = readableToRuntimeBinding( - bindableProperties, - field.value - ) + // value and type is needed by the client, so it can parse + // a string into a correct type + newParameterFields[field.name] = { + type: schemaFields.find(f => f.name === field.name).type, + value: readableToRuntimeBinding(bindableProperties, field.value), + } } } dispatch("fieldschanged", newParameterFields) @@ -74,8 +76,8 @@ diff --git a/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte b/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte index 61368f12ee..6ee3a2aed4 100644 --- a/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte +++ b/packages/builder/src/components/userInterface/EventsEditor/actions/UpdateRecord.svelte @@ -39,15 +39,12 @@ $: parameters._id = `{{ ${recordId} }}` // just wraps binding in {{ ... }} - const toBindingExpression = bindingPath => { - console.log("yeo") - return `{{ ${bindingPath} }}` - } + const toBindingExpression = bindingPath => `{{ ${bindingPath} }}` // finds the selected idBinding, then reads the table/view // from the component instance that it belongs to. // then returns the field names for that schema - const modelInfoFromIdBinding = recordId => { + const schemaFromIdBinding = recordId => { if (!recordId) return [] const idBinding = bindableProperties.find( @@ -66,15 +63,18 @@ const model = $backendUiStore.models.find(m => m._id === modelInfo.modelId) parameters.modelId = modelInfo.modelId - return Object.keys(model.schema) + return Object.keys(model.schema).map(k => ({ + name: k, + type: model.schema[k].type, + })) } - let fieldNames + let schemaFields $: { if (parameters && recordId) { - fieldNames = modelInfoFromIdBinding(recordId) + schemaFields = schemaFromIdBinding(recordId) } else { - fieldNames = [] + schemaFields = [] } } @@ -104,7 +104,7 @@ {#if recordId} {/if} diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index 67092ece54..710b0a40de 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -54,10 +54,13 @@ const apiOpts = { } const createRecord = async params => - await post({ url: `/api/${params.modelId}/records`, body: params.fields }) + await post({ + url: `/api/${params.modelId}/records`, + body: makeRecordRequestBody(params), + }) const updateRecord = async params => { - const record = params.fields + const record = makeRecordRequestBody(params) record._id = params._id await patch({ url: `/api/${params.modelId}/records/${params._id}`, @@ -65,6 +68,32 @@ const updateRecord = async params => { }) } +const makeRecordRequestBody = parameters => { + const body = {} + for (let fieldName in parameters.fields) { + const field = parameters.fields[fieldName] + + // ensure fields sent are of the correct type + if (field.type === "boolean") { + if (field.value === "true") body[fieldName] = true + if (field.value === "false") body[fieldName] = false + } else if (field.type === "number") { + const val = parseFloat(field.value) + if (!isNaN(val)) { + body[fieldName] = val + } + } else if (field.type === "datetime") { + const date = new Date(field.value) + if (!isNaN(date.getTime())) { + body[fieldName] = date.toISOString() + } + } else { + body[fieldName] = field.value + } + } + return body +} + export default { authenticate: authenticate(apiOpts), triggerWorkflow: triggerWorkflow(apiOpts), diff --git a/packages/server/src/api/controllers/record.js b/packages/server/src/api/controllers/record.js index f2a9bea49b..d47a73bfac 100644 --- a/packages/server/src/api/controllers/record.js +++ b/packages/server/src/api/controllers/record.js @@ -22,7 +22,6 @@ exports.patch = async function(ctx) { if (!model.schema[key]) continue record[key] = patchfields[key] } - coerceFieldsToCorrectType(record, model) const validateResult = await validate({ record, @@ -58,8 +57,6 @@ exports.save = async function(ctx) { const model = await db.get(record.modelId) - coerceFieldsToCorrectType(record, model) - const validateResult = await validate({ record, model, @@ -195,32 +192,6 @@ exports.validate = async function(ctx) { ctx.body = errors } -// this function modifies an incoming record, to allow for things like -// "boolField": "true" (instead of mandating "boolField": true) -// this allows us to use mustash templating to send non-string fields in a request -const coerceFieldsToCorrectType = (record, model) => { - for (let fieldName in record) { - const fieldValue = record[fieldName] - if (model.schema[fieldName]) { - if ( - model.schema[fieldName].type === "boolean" && - typeof fieldValue !== "boolean" - ) { - if (fieldValue === "true") record[fieldName] = true - if (fieldValue === "false") record[fieldName] = false - continue - } - - if (model.schema[fieldName].type === "number") { - const val = parseFloat(fieldValue) - if (!isNaN(val)) { - record[fieldName] = val - } - } - } - } -} - async function validate({ instanceId, modelId, record, model }) { if (!model) { const db = new CouchDB(instanceId)