2

MirageJS 以字符串形式提供所有模型 ID。我们的后端使用整数,方便排序等。在阅读完 MirageJS 不支持开箱即用的整数 ID 之后。从我读过的对话中,最好的解决方案是在序列化程序中转换 Id。

Output:

{
 id: "1",
 title: "Some title",
 otherValue: "Some other value"
}

但我想要的是:

Expected Output:

{
 id: 1,
 title: "Some title",
 otherValue: "Some other value"
}

我真的很想转换所有 id。这将包括嵌套对象和序列化的 Id。

4

3 回答 3

2

我的解决方案是遍历数据并递归转换所有Id。它工作得很好。

我还有许多其他要求,例如删除data密钥以及嵌入或序列化 Id。

const ApplicationSerializer = Serializer.extend({
  root: true,

  serialize(resource, request) {
    // required to serializedIds
    // handle removing root key
    const json = Serializer.prototype.serialize.apply(this, arguments)
    const root = resource.models
      ? this.keyForCollection(resource.modelName)
      : this.keyForModel(resource.modelName)

    const keyedItem = json[root]

    // convert single string id to integer
    const idToInt = id => Number(id)

    // convert array of ids to integers
    const idsToInt = ids => ids.map(id => idToInt(id))

    // check if the data being passed is a collection or model
    const isCollection = data => Array.isArray(data)

    // check if data should be traversed
    const shouldTraverse = entry =>
      Array.isArray(entry) || entry instanceof Object

    // check if the entry is an id
    const isIdKey = key => key === 'id'

    // check for serialized Ids
    // don't be stupid and create an array of values with a key like `arachnIds`
    const isIdArray = (key, value) =>
      key.slice(key.length - 3, key.length) === 'Ids' && Array.isArray(value)

    // traverse the passed model and update Ids where required, keeping other entries as is
    const traverseModel = model =>
      Object.entries(model).reduce(
        (a, c) =>
          isIdKey(c[0])
            ? // convert id to int
              { ...a, [c[0]]: idToInt(c[1]) }
            : // convert id array to int
            isIdArray(c[0], c[1])
            ? { ...a, [c[0]]: idsToInt(c[1]) }
            : // traverse nested entries
            shouldTraverse(c[1])
            ? { ...a, [c[0]]: applyFuncToModels(c[1]) }
            : // keep regular entries
              { ...a, [c[0]]: c[1] },
        {}
      )

    // start traversal of data
    const applyFuncToModels = data =>
      isCollection(data)
        ? data.map(model => 
            // confirm we're working with a model, and not a value
            model instance of Object ? traverseModel(model) : model)
        : traverseModel(data)

    return applyFuncToModels(keyedItem)
  }
})
于 2020-04-17T14:03:26.263 回答
1

认为您应该可以为此使用自定义 IdentityManager。这是一个 REPL 示例。(注意:REPL 是一项正在进行的工作 + 目前仅适用于 Chrome)。

这是代码:

import { Server, Model } from "miragejs";

class IntegerIDManager {
  constructor() {
    this.ids = new Set();
    this.nextId = 1;
  }

  // Returns a new unused unique identifier.
  fetch() {
    let id = this.nextId++;
    this.ids.add(id);

    return id;
  }

  // Registers an identifier as used. Must throw if identifier is already used.
  set(id) {
    if (this.ids.has(id)) {
      throw new Error('ID ' + id + 'has already been used.');
    }

    this.ids.add(id);
  }

  // Resets all used identifiers to unused.
  reset() {
    this.ids.clear();
  }
}

export default new Server({
  identityManagers: {
    application: IntegerIDManager,
  },

  models: {
    user: Model,
  },

  seeds(server) {
    server.createList("user", 3);
  },

  routes() {
    this.resource("user");
  },
});

当我使用此服务器向 /users 发出 GET 请求时,我会返回整数 ID。

于 2020-04-21T03:01:30.803 回答
1

我也必须解决这个问题(手指交叉,被包含在库中),我的用例比第一个答案更简单。

function convertIdsToNumbers(o) {
  Object.keys(o).forEach((k) => {
    const v = o[k]
    if (Array.isArray(v) || v instanceof Object) convertIdsToNumbers(v)
    if (k === 'id' || /.*Id$/.test(k)) {
      o[k] = Number(v)
    }
  })
}

const ApplicationSerializer = RestSerializer.extend({
  root: false,
  embed: true,
  serialize(object, request) {
    let json = Serializer.prototype.serialize.apply(this, arguments)
    convertIdsToNumbers(json)
    return {
      status: request.status,
      payload: json,
    }
  },
})
于 2021-08-07T13:23:40.653 回答