Implement unique constraint support (#4467)

* Allow creating unique fields

* Allow removing unique constriant

* Show unique constraint error as validation error in app
This commit is contained in:
Rijk van Zanten
2021-03-10 17:35:21 -05:00
committed by GitHub
parent 7569168e3e
commit 4248b187bb
7 changed files with 35 additions and 5 deletions

View File

@@ -54,7 +54,7 @@
<small class="note" v-if="field.meta && field.meta.note" v-html="marked(field.meta.note)" />
<small class="validation-error" v-if="validationError">
{{ $t(`validationError.${validationError.type}`, validationError) }}
{{ validationMessage }}
</small>
</div>
</template>
@@ -69,6 +69,7 @@ import FormFieldInterface from './form-field-interface.vue';
import { ValidationError } from './types';
import { getJSType } from '@/utils/get-js-type';
import { isEqual } from 'lodash';
import { i18n } from '@/lang';
export default defineComponent({
components: { FormFieldLabel, FormFieldMenu, FormFieldInterface },
@@ -133,7 +134,15 @@ export default defineComponent({
const { showRaw, rawValue } = useRaw();
return { isDisabled, marked, _value, emitValue, showRaw, rawValue };
const validationMessage = computed(() => {
if (props.validationError.code === 'RECORD_NOT_UNIQUE') {
return i18n.t('validationError.unique');
} else {
return i18n.t(`validationError.${props.validationError.type}`, props.validationError);
}
});
return { isDisabled, marked, _value, emitValue, showRaw, rawValue, validationMessage };
function emitValue(value: any) {
if (

View File

@@ -9,6 +9,7 @@ export type FormField = DeepPartial<Field> & {
};
export type ValidationError = {
code: string;
field: string;
type: FilterOperator;
valid?: number | string | (number | string)[];

View File

@@ -110,14 +110,16 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
return response.data.data;
} catch (err) {
if (err?.response?.data?.errors) {
const validationTypes = ['FAILED_VALIDATION', 'RECORD_NOT_UNIQUE'];
validationErrors.value = err.response.data.errors
.filter((err: APIError) => err?.extensions?.code === 'FAILED_VALIDATION')
.filter((err: APIError) => validationTypes.includes(err?.extensions?.code))
.map((err: APIError) => {
return err.extensions;
});
const otherErrors = err.response.data.errors.filter(
(err: APIError) => err?.extensions?.code !== 'FAILED_VALIDATION'
(err: APIError) => validationTypes.includes(err?.extensions?.code) === false
);
if (otherErrors.length > 0) {

View File

@@ -82,6 +82,7 @@ validationError:
null: Value has to be null
nnull: Value can't be null
required: Value is required
unique: Value has to be unique
all_access: All Access
no_access: No Access
use_custom: Use Custom
@@ -390,6 +391,7 @@ errors:
ITEM_LIMIT_REACHED: Item limit reached
ITEM_NOT_FOUND: Item not found
ROUTE_NOT_FOUND: Not found
RECORD_NOT_UNIQUE: Duplicate value detected
UNKNOWN: Unexpected Error
value_hashed: Value Securely Hashed
bookmark_name: Bookmark name...

View File

@@ -1,6 +1,5 @@
<template>
<div>
<div class="form">
<div class="field">
<div class="label type-label">
@@ -139,6 +138,16 @@
block
/>
</div>
<div class="field half-right" v-if="fieldData.schema">
<div class="label type-label">{{ $t('unique') }}</div>
<v-checkbox
:input-value="fieldData.schema.is_unique"
@change="fieldData.schema.is_unique = $event"
:label="$t('value_unique')"
block
/>
</div>
</div>
</div>
</template>

View File

@@ -43,6 +43,7 @@ function initLocalStore(collection: string, field: string, type: typeof localTyp
default_value: undefined,
max_length: undefined,
is_nullable: true,
is_unique: false,
numeric_precision: null,
numeric_scale: null,
},