WatermelonDB
WatermelonDB copied to clipboard
Unable to push sync TypeError: Cannot read property 'type' of undefined at _setRaw
My pull works great and my push syncs to the server just fine, but my records _status
are never marked as synced and I can't figure out why. The result is every time sync is called the same record is pushed to my server over and over again.
I also can't figure out how to get logging working and there isn't anything in the docs about it.
const logger = new SyncLogger(20)
const log = logger.newLog()
interface WatermelonContextType {
sync: (useTurbo?: boolean) => void
}
export const WatermelonContext = createContext<WatermelonContextType | null>(
null
)
interface WatermelonProviderProps {
children: JSX.Element | JSX.Element[] | null | boolean
}
const WatermelonProvider = ({ children }: WatermelonProviderProps) => {
const [syncing, setSyncing] = useRecoilState(SyncState)
const utils = trpc.useContext()
const push = trpc.push.sync.useMutation()
const isDeviceFirstSync = useMemo(() => {
const result = storage.getString('isDeviceFirstSync')
return !result
}, [])
const sync = useCallback(
async (useTurbo = false) => {
if (syncing) {
return
}
setSyncing(true)
await synchronize({
database,
log: log,
migrationsEnabledAtVersion: 1,
pullChanges: async ({ lastPulledAt, schemaVersion, migration }) => {
if (useTurbo) {
const response = await fetch(
ENDPOINT
{
method: 'POST',
body: JSON.stringify({
lastPulledAt,
schemaVersion,
migration
})
}
)
if (!response.ok) {
throw new Error(await response.text())
}
const json = await response.text()
return { syncJson: json }
} else {
const changes = await utils.pull.sync.fetch({
lastPulledAt,
schemaVersion,
migration
})
return changes
}
},
pushChanges: async ({ changes, lastPulledAt }) => {
console.log('Push Time', lastPulledAt)
const response = await push.mutateAsync({
lastPulledAt,
// @ts-ignore
changes // TODO: We use superstruct to validate this on the server, but the types don't align
})
console.log('Push response', response)
if (response.success) {
return
} else {
throw new Error('Sync Push failed')
}
},
sendCreatedAsUpdated: false,
unsafeTurbo: useTurbo,
onWillApplyRemoteChanges: async ({ remoteChangeCount }) => {
console.log('Applying changes', remoteChangeCount)
setSyncing(false)
}
})
},
[syncing, setSyncing, utils.pull.sync, push]
)
useEffect(() => {
if (Env.APP_ENV !== 'development') {
sync()
if (isDeviceFirstSync) {
storage.set('isDeviceFirstSync', JSON.stringify({ date: new Date() }))
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<WatermelonContext.Provider value={{ sync }}>
{children}
</WatermelonContext.Provider>
)
}
As far as I can tell db.batch(...)
never runs this code
https://github.com/Nozbe/WatermelonDB/blob/44d89925985aca3fa72eef1df78f89356b1d9b6f/src/sync/impl/helpers.js#L97
Please help with debugging suggestions or issues with my implementation. Thanks
The only thing I've read that would cause a pushed object not to marked as synced is if it changed during the sync and that hasn't happened in this case. All records are never marked as synced. Very Frustrating
Ok, so I wrapped my entire sync function in a try catch and get an error inside watermelon
TypeError: Cannot read property 'type' of undefined
Top of stack inside _setRaw.
at _setRaw (http://10.0.0.14:8081/../../node_modules/@nozbe/watermelondb/RawRecord/index.bundle//&platform=ios&hot=false&lazy=true&transform.engine=hermes&transform.routerRoot=app&dev=true&minify=false&modulesOnly=true&runModule=false&shallow=true:20:28)
at setRawSanitized (http://10.0.0.14:8081/../../node_modules/@nozbe/watermelondb/RawRecord/index.bundle//&platform=ios&hot=false&lazy=true&transform.engine=hermes&transform.routerRoot=app&dev=true&minify=false&modulesOnly=true&runModule=false&shallow=true:95:12)
When I debug further I found that the error was here
function _setRaw(raw, key, value, columnSchema) {
console.log(raw, key, value, columnSchema)
var {
type: type,
isOptional: isOptional
} = columnSchema;
...
The result of that console.log is
[object] updated_at 1708213289147 undefined
What is interesting is I don't use updated_at
in my schema. I elected to go with all camel cased fields in my schema and not use the updated_at
or created_at
fields as the docs said they weren't required. So why does this function get called with updated_at
even though the columSchema
is undefined
?
I think this may be a bug in Watermelon.
However, I do have updatedAt
, createdAt
, and deletedAt
fields in my database, so maybe I should just map those fields and take advantage of watermelon db's built in advanced fields handling.
Did you manage to solve this?
Didn't go into detail but there is explicit check for updatedAt. I don't think these fields are mandatory but if defined they should be defined both in model and in schema.
Did you manage to solve this?
Didn't go into detail but there is explicit check for updatedAt. I don't think these fields are mandatory but if defined they should be defined both in model and in schema.
Yes, I added updated_at
and created_at
to my schema's and that solved the issue for me. But that is interesting, I assumed that it would be checking for updated_at
and not updatedAt
. I break from naming conventions in my database and use camelcase instead of snake case, which is why I used updatedAt
Overall I don't like that Watermelon uses naming conventions like this. In my opinion you should be able to configure the columns you want to attach advanced field behaviors to. To my knowledge Sqlite doesn't care if you use snake-case or camelcase naming