2016-05-08 2 views
1

Da ich die folgende JSON-Objekt haben,umgebungsspezifische Konfiguration von einem JSON-Objekt Get mit Lodash

dbConfig = { 
    "db": "default", 
    "default": { 
     "defaultDB": "sqlite", 
     "init": "init", 
     "migrations": { 
      "directory": "migrations", 
      "tableName": "migrations" 
     }, 
     "pool": { 
      "min": "2", 
      "max": "10" 
     }, 
     "sqlite": { 
      "client": "sqlite3", 
      "connection": { 
       "filename": "data/default/sqlitedb/test.db" 
      } 
     }, 
     "oracle": { 
      "client": "oracledb", 
      "config": { 
       "development": { 
        "user": "test", 
        "pass": "test", 
        "db": "test" 
       }, 
       "production": { 
        "user": "test", 
        "pass": "test", 
        "db": "test" 
       }, 
       "test": { 
        "user": "test", 
        "pass": "test", 
        "db": "test" 
       } 
      } 
     } 
    } 
}; 

Knoten Mit & Lodash, gibt es eine Möglichkeit, entweder connection oder config. immer auf das, was dbConfig.default[dbConfig.default.defaultDB] abhängig gesetzt zu.

So zum Beispiel, wenn ich gesetzt dbConfig.default.defaultDB=oracledb und process.env.NODE_ENV=development Ich möchte dbConfig.default[dbConfig.default.defaultDB].config.development

erhalten können Oder wenn ich dbConfig.default.defaultDB=sqlite gesetzt gerade dbConfig.default[dbConfig.default.defaultDB].connection

Mit anderen Worten zu bekommen, wenn die Datenbankumgebung spezifische Konfiguration hat dann Dies wird in "config": {} sein und wenn nicht in "connection": {}

Es muss nicht Lodash sein. Es kann auch einfaches Javascript sein.

Antwort

2

Lösung ohne lodash

var defaultDbName = dbConfig.default[dbConfig.default.defaultDB]; 

var db; 
if (defaultDb === 'sqllite') { 
    db = dbConfig.default[defaultDb].connection; 
} else { 
    var env = process.env.NODE_ENV; 
    db = dbConfig.default[defaultDb].config[env]; 
} 

Lösung mit lodash

Hier bin ich mit lodash get Funktion Objektfeldwert oder null, wenn sie noch nicht existiert. Außerdem verwende ich Template-String-Syntax: ${val}, um Feldpfad zu formatieren.

var defaultDbName = dbConfig.default[dbConfig.default.defaultDB]; 
var defaultDbConf = dbConfig.default[defaultDb]; 
var env = process.env.NODE_ENV; 

var db = defaultDbConf.connection || _.get(defaultDbConf, `config.${env}`); 

Btw, Ihre Konfiguration json ist zu komplex, viel besser Konfiguration pro Umwelt zu haben.

+0

Das ist brilliant. Vielen Dank – nixgadgets

+0

Viele Konfigurationen sind so komplex, es sieht nur schlimmer aus wegen der unnötigen Duplizierung von Nicht-Umgebung-spezifischen Eigenschaften. Das heißt, es ist nicht schlimmer als die übliche Gewohnheit, ganze .properties Dateien pro Umgebung zu duplizieren und dann zu machen Sicher, dass alle Attribute synchron bleiben, wenn neue Funktionen in die endgültige Bereitstellungsumgebung vordringen. Siehe unten für einen Null-/Minimalduplizierungsmechanismus, der Objektattributnamen eine lesbare Notation hinzufügt, die rekursiv durch eine einzige Funktion entweder zur Ausführungs-/Renderzeit oder als Teil des Vorbereitungs-Workflows gefiltert werden kann. – storsoc

1

Lösung ohne [Abhängigkeiten] (ursprünglich here beantwortet, aber nicht AngularJS spezifisch)

Ihre JSON sind komplex, ja, aber es könnte auch kleiner und besser lesbar sein, ohne all die Vervielfältigung, wobei jede Umgebung hat den gleichen Satz von Attributen, die variieren können oder nicht, und würde unnötigerweise dupliziert werden.

Mit einem simple algorithm (jsFiddle) können Sie Ihre JSON-Konfiguration für bestimmte Eigenschaft-Namensuffixe (Eigenschaft @ Suffix) und haben einen Katalog von umwelt unterschiedlichen Eigenschaften neben nicht-variierenden Eigenschaften dynamisch analysieren, ohne die Konfiguration künstlich Strukturierung und ohne Wiederholung, einschließlich tief verschachtelter Konfigurationsobjekte.

Sie können auch Suffixe mischen und zusammenführen und beliebig viele Umgebungsfaktoren oder andere beliebige Faktoren kombinieren, um Ihr Konfigurationsobjekt zu optimieren.

Beispiel, Schnipsel von vorverarbeiteten JSON config:

var config = { 
    'help': { 
     'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.', 
     'PHONE': '808-867-5309', 
     'EMAIL': '[email protected]' 
    }, 
    '[email protected]': { 
     'BLURB': 'Please contact Customer Service Center', 
     '[email protected]': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle', 
     '[email protected]': 'Bitte kontaktieren Sie unseren Kundendienst!!1!', 
     'PHONE': '1-800-CUS-TOMR', 
     'EMAIL': '[email protected]' 
    }, 
} 

... und nachbearbeitet (angesichts location.hostname = 'www.productionwebsite.com' und Navigator.Sprache 'de'):

prefer(config,['www.productionwebsite.com','de']); // prefer(obj,string|Array<string>) 

JSON.stringify(config); // { 
    'help': { 
     'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!', 
     'PHONE': '1-800-CUS-TOMR', 
     'EMAIL': '[email protected]' 
    } 
} 

Natürlich können Sie diese Werte bei Render-Zeit mit location.hostname und window.navigator.language ziehen. Der Algorithmus, um die JSON zu verarbeiten selbst ist nicht sehr komplex (aber immer noch bequemer aus irgendeinem Grund mit einem ganzen Rahmen fühlen kann, anstelle einer einzelnen Funktion):

function prefer(obj,suf) { 
    function pr(o,s) { 
     for (var p in o) { 
      if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1]) continue; // ignore: proto-prop OR not-suffixed OR temp prop score 
      var b = p.split('@')[0]; // base prop name 
      if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder 
      var ps = p.split('@')[1].split('&'); // array of property suffixes 
      var sc = 0; var v = 0; // reset (running)score and value 
      while(ps.length) { 
       // suffix value: index(of found suffix in prefs)^10 
       v = Math.floor(Math.pow(10,s.indexOf(ps.pop()))); 
       if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later) 
       sc += v; 
      } 
      if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop 
      delete o[p]; 
     } 
     for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores 
     for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs 
    } 
    if(typeof obj !== 'object') return; // validate 
    suf = ((suf || suf === 0) && (suf.length || suf === parseFloat(suf)) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings 
    pr(obj,suf.reverse()); 
} 

Der Eigenschaftsname Suffix eine beliebige Anzahl haben können Suffixe nach dem '@', abgegrenzt durch '&' (kaufmännisches Und) und, wo es zwei Eigenschaften mit unterschiedlichen, aber bevorzugten Suffixen gibt, werden in der Reihenfolge bevorzugt, in der sie an die Funktion übergeben werden. Suffixe, die BEIDE bevorzugte Strings enthalten, werden vor allen anderen bevorzugt. In JSON gefundene Suffixe, die nicht als bevorzugt angegeben sind, werden verworfen.

Präferenz/Diskriminierung wird von oben nach unten auf Ihren Objektbaum angewendet, und wenn Objekte auf höherer Ebene überleben, werden sie anschließend auf bevorzugte Suffixe untersucht.

Mit diesem Ansatz Ihre JSON (Ich mache einige Annahmen über welche Attribute variieren zwischen Umgebungen und die nicht) kann wie folgt vereinfacht werden:

dbConfig = { 
    "pool": { 
     "min": "2", 
     "max": "10" 
    }, 
    "init": "init", 
    "migrations": { 
     "directory": "migrations", 
     "tableName": "migrations" 
    }, 
    "db": 
     "client": "sqlite", 
     "filename": "data/default/sqlitedb/development.db" 
     "[email protected]": "data/default/sqlitedb/test.db" 
     "[email protected]": "data/default/sqlitedb/production.db" 
    }, 
    "[email protected]": { 
     "client": "oracle", 
     "user": "devuser", 
     "[email protected]": "testdbuser", 
     "[email protected]": "testdbuser", 
     "pass": "devpass", 
     "[email protected]": "testdbpass", 
     "[email protected]": "testdbpass", 
     "db": "devdb", 
     "[email protected]": "testdbschema", 
     "[email protected]": "testdbschema" 
    } 
}; 

Damit Sie diese ernähren konnte in die es vorziehen() Funktion mit diesen args + Ergebnisse:

für sQLite, Test env:

prefer(dbConfig,'tst'); 
JSON.stringify(dbConfig); // dbConfig: { 
    "pool": { 
     "min": "2", 
     "max": "10" 
    }, 
    "init": "init", 
    "migrations": { 
     "directory": "migrations", 
     "tableName": "migrations" 
    }, 
    "db": { 
     "client": "sqlite", 
     "filename": "data/default/sqlitedb/test.db" 
    } 
}; 

für Oracle, default/Entwicklungsumgebung:

prefer(dbConfig,'oracle'); // oracle, dev(default) env 
JSON.stringify(dbConfig); // dbConfig: { 
    "pool": { 
     "min": "2", 
     "max": "10" 
    }, 
    "init": "init", 
    "migrations": { 
     "directory": "migrations", 
     "tableName": "migrations" 
    }, 
    "db": { 
     "client": "oracle", 
     "user": "devdbuser", 
     "pass": "devdbpass", 
     "db": "devdbschema" 
    } 
}; 

prefer(dbConfig,'oracle,prd'); // oracle, production env 
JSON.stringify(dbConfig); // dbConfig: { 
    "pool": { 
     "min": "2", 
     "max": "10" 
    }, 
    "init": "init", 
    "migrations": { 
     "directory": "migrations", 
     "tableName": "migrations" 
    }, 
    "db": { 
     "client": "oracle", 
     "user": "prddbuser", 
     "pass": "prddbpass", 
     "db": "prddbschema" 
    } 
}; 

Abstrakt Nutzung und Beispiele:

var o = { 'a':'apple', '[email protected]':'apple-dev', '[email protected]':'pomme', 
      'b':'banana', '[email protected]':'banane', '[email protected]&fr':'banane-dev', 
      'c':{ 'o':'c-dot-oh', '[email protected]':'c-point-oh' }, '[email protected]': { 'o':'c-dot-oh-dev', '[email protected]':'c-point-oh-dev' } }; 

/*1*/ prefer(o,'dev');  // { a:'apple-dev', b:'banana',  c:{o:'c-dot-oh-dev'} } 
/*2*/ prefer(o,'fr');   // { a:'pomme',  b:'banane',  c:{o:'c-point-oh'}  } 
/*3*/ prefer(o,'dev,fr');  // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} } 
/*4*/ prefer(o,['fr','dev']); // { a:'pomme',  b:'banane-dev', c:{o:'c-point-oh-dev'} } 
/*5*/ prefer(o);    // { a:'apple',  b:'banana',  c:{o:'c-dot-oh'}  } 

Caveats Verwendung des @ in Eigenschaftsname ist nicht Standard und ist ungültig in Punktnotation, Aber bis jetzt hat es noch keine Browser durchbrochen, in denen wir dies getestet haben. Das UPSIDE-Verfahren verhindert, dass Entwickler erwarten, dass sie auf Ihre vorverarbeiteten Attribute mit Suffix verweisen können. Ein Entwickler müsste sich dessen bewusst sein und ein bisschen unkonventionell sein und auf sein Attribut als String (obj ['key @ suf']) verweisen, um das zu tun, was übrigens der Grund dafür ist, dass diese Funktion möglich ist.

Wenn zukünftige JavaScript-Engines dies ablehnen, ersetzen Sie andere tolerierbare Konventionen, seien Sie einfach konsistent. Dieser Algorithmus wurde nicht auf seine Leistung hin profiliert oder streng auf andere potenzielle Probleme getestet. In seiner aktuellen Form, einmalig beim Start/Laden verwendet, haben wir noch Probleme mit zu bekommen. Wie immer, YMMV.

Verwandte Themen