Repository: node-influx/node-influx
Pull request #406 (2019-06-18 21:02:39)

feat: allow schema to be specified at runtime
Fixes #311 - rebases stale changes from @flafik as per https://github.com/node-influx/node-influx/pull/311#issuecomment-497952278

## Proposed Changes
 - Allow a schema to be added to the `InfluxDB` object at runtime i.e. after the object has been initialised.  This makes field coercion work where the name of the database or measurement is not known prior to writing the points.

## Checklist

- [x] A test has been added if appropriate
- [x] `npm test` completes successfully
- [x] Commit messages are in [semantic format](https://seesparkbox.com/foundry/semantic_commit_messages)

revbingo: Will fix linting errors.  TBH it was difficult to notice because on my machine it threw dozens of linting errors even before making any changes 🤷‍♂ 

Patch:
diff --git a/package-lock.json b/package-lock.json
index 8a108df..cd55bb0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1672,27 +1672,33 @@
       "dev": true
     },
     "cacache": {
-      "version": "11.3.2",
-      "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
-      "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==",
+      "version": "11.3.3",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
+      "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
       "dev": true,
       "requires": {
-        "bluebird": "^3.5.3",
+        "bluebird": "^3.5.5",
         "chownr": "^1.1.1",
         "figgy-pudding": "^3.5.1",
-        "glob": "^7.1.3",
+        "glob": "^7.1.4",
         "graceful-fs": "^4.1.15",
         "lru-cache": "^5.1.1",
         "mississippi": "^3.0.0",
         "mkdirp": "^0.5.1",
         "move-concurrently": "^1.0.1",
         "promise-inflight": "^1.0.1",
-        "rimraf": "^2.6.2",
+        "rimraf": "^2.6.3",
         "ssri": "^6.0.1",
         "unique-filename": "^1.1.1",
         "y18n": "^4.0.0"
       },
       "dependencies": {
+        "bluebird": {
+          "version": "3.5.5",
+          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
+          "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==",
+          "dev": true
+        },
         "glob": {
           "version": "7.1.4",
           "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
@@ -1722,6 +1728,15 @@
             "yallist": "^3.0.2"
           }
         },
+        "rimraf": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        },
         "y18n": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
@@ -14272,9 +14287,9 @@
       "optional": true
     },
     "webpack": {
-      "version": "4.34.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.34.0.tgz",
-      "integrity": "sha512-ry2IQy1wJjOefLe1uJLzn5tG/DdIKzQqNlIAd2L84kcaADqNvQDTBlo8UcCNyDaT5FiaB+16jhAkb63YeG3H8Q==",
+      "version": "4.35.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.35.0.tgz",
+      "integrity": "sha512-M5hL3qpVvtr8d4YaJANbAQBc4uT01G33eDpl/psRTBCfjxFTihdhin1NtAKB1ruDwzeVdcsHHV3NX+QsAgOosw==",
       "dev": true,
       "requires": {
         "@webassemblyjs/ast": "1.8.5",
diff --git a/package.json b/package.json
index c0926aa..edceded 100644
--- a/package.json
+++ b/package.json
@@ -78,7 +78,7 @@
     "stream-http": "github:node-influx/stream-http",
     "ts-node": "8.3.0",
     "typescript": "3.5.2",
-    "webpack": "4.34.0",
+    "webpack": "4.35.0",
     "semantic-release": "15.13.16"
   },
   "eslintConfig": {
diff --git a/src/index.ts b/src/index.ts
index c109142..0c25eb1 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -436,22 +436,17 @@ export class InfluxDB {
 			this._pool.addHost(`${host.protocol}://${host.host}:${host.port}`, host.options);
 		});
 
-		this._options.schema.forEach(schema => {
-			schema.database = schema.database || this._options.database;
-			const db = schema.database;
-			if (!db) {
-				throw new Error(
-					`Schema ${schema.measurement} doesn't have a database specified,` +
-            'and no default database is provided!',
-				);
-			}
-
-			if (!this._schema[db]) {
-				this._schema[db] = Object.create(null);
-			}
+		this._options.schema.forEach(schema => this._createSchema(schema));
+	}
 
-			this._schema[db][schema.measurement] = new Schema(schema);
-		});
+	/**
+   * Adds specified schema for better fields coercing.
+   *
+   * @param {ISchemaOptions} schema
+   * @memberof InfluxDB
+   */
+	public addSchema(schema: ISchemaOptions): void {
+		this._createSchema(schema);
 	}
 
 	/**
@@ -1314,4 +1309,27 @@ export class InfluxDB {
 			}
 		};
 	}
+
+	/**
+   * Creates specified measurement schema
+   *
+   * @private
+   * @param {ISchemaOptions} schema
+   * @memberof InfluxDB
+   */
+	private _createSchema(schema: ISchemaOptions): void {
+		schema.database = schema.database || this._options.database;
+		if (!schema.database) {
+			throw new Error(
+				`Schema ${schema.measurement} doesn't have a database specified,` +
+				'and no default database is provided!',
+			);
+		}
+
+		if (!this._schema[schema.database]) {
+			this._schema[schema.database] = Object.create(null);
+		}
+
+		this._schema[schema.database][schema.measurement] = new Schema(schema);
+	}
 }


Test patch:
diff --git a/test/unit/influx.test.ts b/test/unit/influx.test.ts
index 8aa0ad8..614300c 100644
--- a/test/unit/influx.test.ts
+++ b/test/unit/influx.test.ts
@@ -552,6 +552,37 @@ describe('influxdb', () => {
 				]);
 			});
 
+			it('can accept a schema at runtime', () => {
+				setDefaultDB('my_db');
+				expectWrite('my_runtime_schema_measure,my_tag=1 bool=T,float=43,int=42i', {
+					precision: 'n',
+					rp: undefined,
+					db: 'my_db'
+				});
+
+				influx.addSchema({
+					database: 'my_db',
+					measurement: 'my_runtime_schema_measure',
+					fields: {
+						bool: FieldType.BOOLEAN,
+						float: FieldType.FLOAT,
+						int: FieldType.INTEGER
+					},
+					tags: ['my_tag']
+				});
+				return influx.writePoints([
+					{
+						measurement: 'my_runtime_schema_measure',
+						tags: {my_tag: '1'},
+						fields: {
+							int: 42,
+							float: 43,
+							bool: true
+						}
+					}
+				]);
+			});
+
 			it('throws on schema violations', () => {
 				setDefaultDB('my_db');