stop coercing values on the server - do on client instead
This commit is contained in:
parent
62db75eafb
commit
f975237417
|
@ -19,10 +19,13 @@
|
||||||
const modelFields = modelId => {
|
const modelFields = modelId => {
|
||||||
const model = $backendUiStore.models.find(m => m._id === 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) : []
|
parameters && parameters.modelId ? modelFields(parameters.modelId) : []
|
||||||
|
|
||||||
const onFieldsChanged = e => {
|
const onFieldsChanged = e => {
|
||||||
|
@ -42,7 +45,7 @@
|
||||||
{#if parameters.modelId}
|
{#if parameters.modelId}
|
||||||
<SaveFields
|
<SaveFields
|
||||||
parameterFields={parameters.fields}
|
parameterFields={parameters.fields}
|
||||||
schemaFields={fieldNames}
|
{schemaFields}
|
||||||
on:fieldschanged={onFieldsChanged} />
|
on:fieldschanged={onFieldsChanged} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
(parameterFields &&
|
(parameterFields &&
|
||||||
runtimeToReadableBinding(
|
runtimeToReadableBinding(
|
||||||
bindableProperties,
|
bindableProperties,
|
||||||
parameterFields[name]
|
parameterFields[name].value
|
||||||
)) ||
|
)) ||
|
||||||
"",
|
"",
|
||||||
}))
|
}))
|
||||||
|
@ -56,10 +56,12 @@
|
||||||
const newParameterFields = {}
|
const newParameterFields = {}
|
||||||
for (let field of fields) {
|
for (let field of fields) {
|
||||||
if (field.name) {
|
if (field.name) {
|
||||||
newParameterFields[field.name] = readableToRuntimeBinding(
|
// value and type is needed by the client, so it can parse
|
||||||
bindableProperties,
|
// a string into a correct type
|
||||||
field.value
|
newParameterFields[field.name] = {
|
||||||
)
|
type: schemaFields.find(f => f.name === field.name).type,
|
||||||
|
value: readableToRuntimeBinding(bindableProperties, field.value),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dispatch("fieldschanged", newParameterFields)
|
dispatch("fieldschanged", newParameterFields)
|
||||||
|
@ -74,8 +76,8 @@
|
||||||
<Label size="m" color="dark">Field</Label>
|
<Label size="m" color="dark">Field</Label>
|
||||||
<Select secondary bind:value={field.name} on:blur={rebuildParameters}>
|
<Select secondary bind:value={field.name} on:blur={rebuildParameters}>
|
||||||
<option value="" />
|
<option value="" />
|
||||||
{#each schemaFields as fieldName}
|
{#each schemaFields as schemaField}
|
||||||
<option value={fieldName}>{fieldName}</option>
|
<option value={schemaField.name}>{schemaField.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</Select>
|
</Select>
|
||||||
<Label size="m" color="dark">Value</Label>
|
<Label size="m" color="dark">Value</Label>
|
||||||
|
|
|
@ -39,15 +39,12 @@
|
||||||
$: parameters._id = `{{ ${recordId} }}`
|
$: parameters._id = `{{ ${recordId} }}`
|
||||||
|
|
||||||
// just wraps binding in {{ ... }}
|
// just wraps binding in {{ ... }}
|
||||||
const toBindingExpression = bindingPath => {
|
const toBindingExpression = bindingPath => `{{ ${bindingPath} }}`
|
||||||
console.log("yeo")
|
|
||||||
return `{{ ${bindingPath} }}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// finds the selected idBinding, then reads the table/view
|
// finds the selected idBinding, then reads the table/view
|
||||||
// from the component instance that it belongs to.
|
// from the component instance that it belongs to.
|
||||||
// then returns the field names for that schema
|
// then returns the field names for that schema
|
||||||
const modelInfoFromIdBinding = recordId => {
|
const schemaFromIdBinding = recordId => {
|
||||||
if (!recordId) return []
|
if (!recordId) return []
|
||||||
|
|
||||||
const idBinding = bindableProperties.find(
|
const idBinding = bindableProperties.find(
|
||||||
|
@ -66,15 +63,18 @@
|
||||||
|
|
||||||
const model = $backendUiStore.models.find(m => m._id === modelInfo.modelId)
|
const model = $backendUiStore.models.find(m => m._id === modelInfo.modelId)
|
||||||
parameters.modelId = 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) {
|
if (parameters && recordId) {
|
||||||
fieldNames = modelInfoFromIdBinding(recordId)
|
schemaFields = schemaFromIdBinding(recordId)
|
||||||
} else {
|
} else {
|
||||||
fieldNames = []
|
schemaFields = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
{#if recordId}
|
{#if recordId}
|
||||||
<SaveFields
|
<SaveFields
|
||||||
parameterFields={parameters.fields}
|
parameterFields={parameters.fields}
|
||||||
schemaFields={fieldNames}
|
{schemaFields}
|
||||||
on:fieldschanged={onFieldsChanged} />
|
on:fieldschanged={onFieldsChanged} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -54,10 +54,13 @@ const apiOpts = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const createRecord = async params =>
|
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 updateRecord = async params => {
|
||||||
const record = params.fields
|
const record = makeRecordRequestBody(params)
|
||||||
record._id = params._id
|
record._id = params._id
|
||||||
await patch({
|
await patch({
|
||||||
url: `/api/${params.modelId}/records/${params._id}`,
|
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 {
|
export default {
|
||||||
authenticate: authenticate(apiOpts),
|
authenticate: authenticate(apiOpts),
|
||||||
triggerWorkflow: triggerWorkflow(apiOpts),
|
triggerWorkflow: triggerWorkflow(apiOpts),
|
||||||
|
|
|
@ -22,7 +22,6 @@ exports.patch = async function(ctx) {
|
||||||
if (!model.schema[key]) continue
|
if (!model.schema[key]) continue
|
||||||
record[key] = patchfields[key]
|
record[key] = patchfields[key]
|
||||||
}
|
}
|
||||||
coerceFieldsToCorrectType(record, model)
|
|
||||||
|
|
||||||
const validateResult = await validate({
|
const validateResult = await validate({
|
||||||
record,
|
record,
|
||||||
|
@ -58,8 +57,6 @@ exports.save = async function(ctx) {
|
||||||
|
|
||||||
const model = await db.get(record.modelId)
|
const model = await db.get(record.modelId)
|
||||||
|
|
||||||
coerceFieldsToCorrectType(record, model)
|
|
||||||
|
|
||||||
const validateResult = await validate({
|
const validateResult = await validate({
|
||||||
record,
|
record,
|
||||||
model,
|
model,
|
||||||
|
@ -195,32 +192,6 @@ exports.validate = async function(ctx) {
|
||||||
ctx.body = errors
|
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 }) {
|
async function validate({ instanceId, modelId, record, model }) {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
const db = new CouchDB(instanceId)
|
const db = new CouchDB(instanceId)
|
||||||
|
|
Loading…
Reference in New Issue