@nozbe/watermelondb
Version:
Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast
84 lines (69 loc) • 2.5 kB
JavaScript
// @flow
import { type Decorator } from '../../utils/common/makeDecorator'
import { type ColumnName } from '../../Schema'
import type Model from '../../Model'
import { ensureDecoratorUsedProperly } from '../common'
// Defines a model property that's (de)serialized to and from JSON using custom sanitizer function.
//
// Pass the database column name as first argument, and sanitizer function as second.
//
// Stored value will be parsed to JSON if possible, and passed to sanitizer as argument, or
// undefined will be passed on parsing error. Field value will be result of sanitizer call.
//
// Value assigned to field will be passed to sanitizer and its results will be stored as stringified
// value.
//
// Examples:
// @json('contact_info', jsonValue => jasonValue || {}) contactInfo: ContactInfo
const parseJSON = (value: any) => {
// fast path
if (value === null || value === undefined || value === '') {
return undefined
}
try {
return JSON.parse(value)
} catch (_) {
return undefined
}
}
const defaultOptions = { memo: false }
export const jsonDecorator: Decorator =
(
rawFieldName: ColumnName,
sanitizer: (json: any, model?: Model) => any,
options?: $Exact<{ memo?: boolean }> = defaultOptions,
) =>
(target: Object, key: string, descriptor: Object) => {
ensureDecoratorUsedProperly(rawFieldName, target, key, descriptor)
return {
configurable: true,
enumerable: true,
get(): any {
// $FlowFixMe
const model = this
const rawValue = model.asModel._getRaw(rawFieldName)
if (options.memo) {
// Use cached value if possible
model._jsonDecoratorCache = model._jsonDecoratorCache || {}
const cachedEntry = model._jsonDecoratorCache[rawFieldName]
if (cachedEntry && cachedEntry[0] === rawValue) {
return cachedEntry[1]
}
}
const parsedValue = parseJSON(rawValue)
const sanitized = sanitizer(parsedValue, model)
if (options.memo) {
model._jsonDecoratorCache[rawFieldName] = [rawValue, sanitized]
}
return sanitized
},
set(json: any): void {
// $FlowFixMe
const model = this
const sanitizedValue = sanitizer(json, model)
const stringifiedValue = sanitizedValue != null ? JSON.stringify(sanitizedValue) : null
model.asModel._setRaw(rawFieldName, stringifiedValue)
},
}
}
export default jsonDecorator