Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update/upsert 可能会将不在 raw 参数里的字段从 undefined 设为 null #91

Open
1 task done
chuan6 opened this issue Dec 13, 2018 · 2 comments
Open
1 task done
Assignees
Labels

Comments

@chuan6
Copy link
Contributor

chuan6 commented Dec 13, 2018

实际发生的场景:

  • 受到影响的那个字段是 OBJECT 类型

  • raw 参数只包含主键和一个与受影响字段无关(不存在关联)的字段

  • 手动 upsert { 主键: 'xxx', 受影响字段: undefined },可以将该字段值重置为 undefined

  • 构建一个失败的单元测试以确认问题

在 test/schemas/Post 里,添加 attachments 字段,设置其类型为 RDBType.OBJECT,

it.only("should keep an `undefined` attribute unchanged if the attribute is absent from the upsert body", function*() {
  const mockPost = postGen(1, null).pop()
  const { _id, content, created } = mockPost

  // 需要先有这个条目才能复现原来 undefined 的属性被改为 null 的行为。
  yield database.upsert('Post', { _id, created })

  const post = { _id, content }
  const execRet = yield database.update('Post', post) // upsert 也能重现,insert 不会

  const [ret] = yield database
    .get<PostSchema>('Post', {
      where: {
        _id: post._id,
      },
    })
    .values()

  expect(ret).to.deep.equal({ _id, content, created })
  checkExecutorResult(execRet, 1)
})

得:

AssertionError: expected { Object (_id, content, ...) } to deeply equal { Object (_id, content, ...) }
+ expected - actual

{
    "_id": "47675ecd"
-  "attachments": null
    "content": "posts content:ab8920dd"
    "created": "1969-12-31T16:00:00.000Z"
}
@chuan6 chuan6 added the bug label Dec 13, 2018
@chuan6 chuan6 self-assigned this Dec 13, 2018
@chuan6 chuan6 changed the title upsert 可能会将不在 raw 参数里的字段从 undefined 设为 null update/upsert 可能会将不在 raw 参数里的字段从 undefined 设为 null Mar 10, 2019
@chuan6
Copy link
Contributor Author

chuan6 commented Mar 10, 2019

看了一下,这应该是 lovefield 对 nullable 列的预期行为,而 OBJECT 类型的列被定死为 nullable。

感觉这样的行为对我们的应用而言有些问题;主要在于,它拿掉了原生表达不完整数据的能力。

本来,我们遇到某一单元格的值为 undefined 时,假设这个单元格的值在前端还没有获取到(比如 websocket 推送里没有这个字段),而当值为 null,我们会假设后端数据源对应的值就是 null。

但如果类型为 OBJECT (还有 ARRAY_BUFFER)的列会在更新时把 undefined 变为 null,那上层的代码就不能自然地依赖 undefined 和 null 的不同来分辨(缺值 vs 空值)上述两种情况了。

/cc @Saviio @Brooooooklyn

@chuan6
Copy link
Contributor Author

chuan6 commented Mar 10, 2019

lovefield 代码上,可以追踪到 rowClass 上的 toDbPayload 方法,将其中对 OBJECT 类型的判断由

if (type == lf.Type.OBJECT) {
  obj[key] = goog.isDefAndNotNull(value) ? value : null;
}

改为

if (type == lf.Type.OBJECT) {
  obj[key] = !goog.isNull(value) ? value : null
}

就可以避免这里我们遇到的问题。

由于这个目标与 lovefield 的意图相悖(见上面的评论),我们可能需要 fork 才能用上上边的做法,@Saviio @Brooooooklyn 你们有什么看法吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant