【问题标题】:Get list of unique entity keys defined on nested schema获取嵌套模式上定义的唯一实体键列表
【发布时间】:2018-01-31 23:48:12
【问题描述】:

我正在尝试获取在 normalizr 架构上定义的所有键的列表,并编写了一个函数来满足我对简单架构的需求:

export const collectAttributes = target => {

  const schemaKeys = []

  if (target.hasOwnProperty('_key')) {
    schemaKeys.push(target._key)
  }

  const definitions = Object.keys(target).filter(key => key[0] !== '_')

  definitions.forEach(key => {
    collectAttributes(target[key]).forEach(attribute => schemaKeys.push(attribute))
  })

  return schemaKeys
}

但是,这在嵌套架构定义上失败,并出现 Maximum call stack size exceeded 错误,如以下测试用例所示:

describe('collectAttributes', () => {
  it('should collect all unique collections defined on a recursive schema', () => {
    const nodeSchema = new schema.Entity('nodes', {})
    const nodeListSchema = new schema.Array(nodeSchema)
    nodeSchema.define({ children: nodeListSchema })

    expect(collectAttributes(nodeSchema)).toEqual(['nodes'])
  })
})

如果有人对如何收集已访问的模式以使递归函数停止有任何想法,他们将不胜感激。

【问题讨论】:

    标签: javascript normalizr


    【解决方案1】:

    我最终想通了 - 解决方案如下:

    export const isSchema = target => {
      if (Array.isArray(target)) {
        return target.length ? isSchema(target[0]) : false
      } else {
        return target.hasOwnProperty('schema') || target instanceof schema.Entity || target instanceof schema.Array
      }
    }
    
    const recursiveCollect = (target, visited = []) => {
    
      const entities = []
      const visitedSchemas = [...visited]
    
      if (isSchema(target)) {
        entities.push(target.key)
        visitedSchemas.push(target)
      }
    
      if (Array.isArray(target) || target instanceof schema.Array) {
        /* 
         * If the current target is an ArraySchema, call `recursiveCollect` 
         * on the underlying entity schema 
         */
        return recursiveCollect(target.schema, visitedSchemas)
      }
    
      Object.keys(target.schema).filter(x => x[0] !== '_').forEach(definition => {
    
        const childSchema= target.schema[definition]
        const alreadyVisited = visitedSchemas.includes(childSchema)
    
        if (isSchema(childSchema) && !alreadyVisited) {
          /* Only call `recursiveCollect` on the child schema if it hasn't 
           * already been encountered
           */
          const result = recursiveCollect(childSchema, visitedSchemas)
    
          if (result.entities) {
            result.entities.forEach(x => entities.push(x))
          }
          if (result.visitedSchemas) {
            result.visitedSchemas.forEach(x => visitedSchemas.push(x))
          }
        }
      })
    
      return { entities, visitedSchemas }
    }
    
    
    export const collectAttributes = target => {
      const { entities } = recursiveCollect(target)
      return entities
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-07
      • 2016-10-07
      • 2016-12-27
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 2020-11-06
      • 2017-06-13
      相关资源
      最近更新 更多