2017-08-23 8 views
0

ネストされたスキーマで定義された一意のエンティティキーのリストを取得し、&は、私はシンプルなスキーマのために必要なものを行う関数を書かれている:私は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']) 
    }) 
}) 

誰もが再帰関数が停止するような、既に訪問したスキーマを収集する方法についてのアイデアを持っている場合は、彼らはとても有難い。

答えて

0

私は最後にそれを考え出した - 以下のソリューション:

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 
} 
関連する問題