diff --git a/package.json b/package.json
index c6b91376..774ff6f9 100644
--- a/package.json
+++ b/package.json
@@ -106,6 +106,7 @@
"loglevel-message-prefix": "^3.0.0",
"moment": "^2.22.2",
"moment-timezone": "^0.5.21",
+ "ngeohash": "^0.6.0",
"node-forge": "^0.7.5",
"node-md6": "^0.1.0",
"notepack.io": "^2.1.3",
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 66663f4a..75bdcb36 100755
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -53,7 +53,9 @@
"To MessagePack",
"From MessagePack",
"To Braille",
- "From Braille"
+ "From Braille",
+ "To Geohash",
+ "From Geohash"
]
},
{
diff --git a/src/core/operations/FromGeohash.mjs b/src/core/operations/FromGeohash.mjs
new file mode 100644
index 00000000..1010da11
--- /dev/null
+++ b/src/core/operations/FromGeohash.mjs
@@ -0,0 +1,43 @@
+/**
+ * @author gchq77703 []
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import geohash from "ngeohash";
+
+/**
+ * From Geohash operation
+ */
+class FromGeohash extends Operation {
+
+ /**
+ * FromGeohash constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "From Geohash";
+ this.module = "Default";
+ this.description = "Converts Geohash strings into Lat / Long coordinates. For example, ww8p1r4t8
becomes 37.8324,112.5584
.";
+ this.infoURL = "https://wikipedia.org/wiki/Geohash";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const coords = geohash.decode(input);
+ return [coords.latitude, coords.longitude].join(",");
+ }
+
+}
+
+export default FromGeohash;
diff --git a/src/core/operations/ToGeohash.mjs b/src/core/operations/ToGeohash.mjs
new file mode 100644
index 00000000..826145ae
--- /dev/null
+++ b/src/core/operations/ToGeohash.mjs
@@ -0,0 +1,51 @@
+/**
+ * @author gchq77703 []
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import geohash from "ngeohash";
+
+/**
+ * To Geohash operation
+ */
+class ToGeohash extends Operation {
+
+ /**
+ * ToGeohash constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "To Geohash";
+ this.module = "Default";
+ this.description = "Converts Lat / Long coordinates into a Geohash string. For example, 37.8324,112.5584
becomes ww8p1r4t8
.";
+ this.infoURL = "https://wikipedia.org/wiki/Geohash";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Precision",
+ type: "number",
+ value: 9
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const [precision] = args;
+
+ input = input.replace(/ /g, "");
+ if (input === "") return "";
+ return geohash.encode(...input.split(",").map(num => parseFloat(num)), precision);
+ }
+
+}
+
+export default ToGeohash;
diff --git a/test/index.mjs b/test/index.mjs
index 8cf69732..5d0ce3ff 100644
--- a/test/index.mjs
+++ b/test/index.mjs
@@ -64,6 +64,8 @@ import "./tests/operations/SetUnion";
import "./tests/operations/SymmetricDifference";
import "./tests/operations/TranslateDateTimeFormat";
import "./tests/operations/Magic";
+import "./tests/operations/ToGeohash.mjs";
+import "./tests/operations/FromGeohash.mjs";
let allTestsPassing = true;
const testStatusCounts = {
diff --git a/test/tests/operations/FromGeohash.mjs b/test/tests/operations/FromGeohash.mjs
new file mode 100644
index 00000000..3dbe85ae
--- /dev/null
+++ b/test/tests/operations/FromGeohash.mjs
@@ -0,0 +1,56 @@
+/**
+ * To Geohash tests
+ *
+ * @author gchq77703
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+TestRegister.addTests([
+ {
+ name: "From Geohash",
+ input: "ww8p1r4t8",
+ expectedOutput: "37.83238649368286,112.55838632583618",
+ recipeConfig: [
+ {
+ op: "From Geohash",
+ args: [],
+ },
+ ],
+ },
+ {
+ name: "From Geohash",
+ input: "ww8p1r",
+ expectedOutput: "37.83416748046875,112.5604248046875",
+ recipeConfig: [
+ {
+ op: "From Geohash",
+ args: [],
+ },
+ ],
+ },
+ {
+ name: "From Geohash",
+ input: "ww8",
+ expectedOutput: "37.265625,113.203125",
+ recipeConfig: [
+ {
+ op: "From Geohash",
+ args: [],
+ },
+ ],
+ },
+ {
+ name: "From Geohash",
+ input: "w",
+ expectedOutput: "22.5,112.5",
+ recipeConfig: [
+ {
+ op: "From Geohash",
+ args: [],
+ },
+ ],
+ },
+]);
diff --git a/test/tests/operations/ToGeohash.mjs b/test/tests/operations/ToGeohash.mjs
new file mode 100644
index 00000000..bf3e9858
--- /dev/null
+++ b/test/tests/operations/ToGeohash.mjs
@@ -0,0 +1,56 @@
+/**
+ * To Geohash tests
+ *
+ * @author gchq77703
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+TestRegister.addTests([
+ {
+ name: "To Geohash",
+ input: "37.8324,112.5584",
+ expectedOutput: "ww8p1r4t8",
+ recipeConfig: [
+ {
+ op: "To Geohash",
+ args: [9],
+ },
+ ],
+ },
+ {
+ name: "To Geohash",
+ input: "37.9324,-112.2584",
+ expectedOutput: "9w8pv3ruj",
+ recipeConfig: [
+ {
+ op: "To Geohash",
+ args: [9],
+ },
+ ],
+ },
+ {
+ name: "To Geohash",
+ input: "37.8324,112.5584",
+ expectedOutput: "ww8",
+ recipeConfig: [
+ {
+ op: "To Geohash",
+ args: [3],
+ },
+ ],
+ },
+ {
+ name: "To Geohash",
+ input: "37.9324,-112.2584",
+ expectedOutput: "9w8pv3rujxy5b99",
+ recipeConfig: [
+ {
+ op: "To Geohash",
+ args: [15],
+ },
+ ],
+ },
+]);