profile
viewpoint
David Duarte DeltaEvo @tempow Unicorn

DeltaEvo/dotfiles 5

My dotfiles (Now https://github.com/DeltaEvo/nixos-configs + https://github.com/DeltaEvo/.config)

alexisvisco/garbage-collector 4

Naive garbage collector in C with mark and sweep algorithm

DeltaEvo/Corewar-Arena 4

Corewar Arena

DeltaEvo/JVultr 3

A Java port of Vultr API

DeltaEvo/MaidChan 3

A Discord bot to help developers made with @popcorn.moe/migi

DeltaEvo/.config 2

My .config

DeltaEvo/Blog 2

One more blog in the universe

DeltaEvo/ipp-client 2

A web ipp client (Support CUPS IPP extensions https://www.cups.org/doc/spec-ipp.html)

startedrswier/c4

started time in 2 days

startedazure-rtos/threadx

started time in 8 days

startedwinterheart/broadcom-bt-firmware

started time in 12 days

startedmart1nro/joycontrol

started time in 12 days

startednolanrigo/dotfiles

started time in 13 days

startedgoogle/fuzzing

started time in 14 days

startedlibopencm3/libopencm3

started time in 15 days

push eventHydreIO/graphql-http

Sceat

commit sha 48174bb04345adc77e6300c005f2c18789c5e772

Update koa.js

view details

push time in 19 days

PR merged HydreIO/graphql-http

Reviewers
koa bodyparser doesn't use ctx.body
+2 -2

0 comment

1 changed file

Sceat

pr closed time in 19 days

startedJongy/gcc_assert_introspect

started time in 19 days

startedRalim/ts100

started time in 24 days

issue commentzephyrproject-rtos/zephyr

Bluetooth Isochronous Channels Support

Will the backporting effort include Isochronous Channels ?

DeltaEvo

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import graphql from 'graphql'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const NORMAL_CLOSURE = 1000++export default (PassThrough, WebSocket) =>+  class Client {+    // variables are initialized because they are private+    // awaiting https://github.com/evanw/esbuild/issues/47+    // to use the # notation+    ws+    operation_id = 0+    address++    /**+     * Create a graphql client+     * @param {String} address The ws connection uri.+     */+    constructor(address) {+      if (typeof address !== 'string')+        throw new TypeError(`The address must be a string`)+      this.address = address+    }++    /**+     * Connect the client to his address,+     * a client must be disconnected before connecting again+     * or it will throw an error+     */+    async connect() {+      this.ws = new WebSocket(this.address)+      await new Promise((resolve, reject) => {+        this.ws.addEventListener('open', resolve)+        this.ws.addEventListener('error', reject)+      })+      log('client ready')+    }++    disconnect() {+      if (!this.ws)+        throw new Error('You must connect before disconnecting u genius..')+      this.ws.close(NORMAL_CLOSURE, 'closed by client')+      log('disconnected')+    }++    async query(query, variables = {}) {+      if (typeof query !== 'string')+        throw new Error('The query is not a String')++      // fail fast+      parse(query)+      log('querying')++      const operation_id = this.operation_id+++      const pass_through = new PassThrough({+        objectMode: true,+      })+      const serialized_query = JSON.stringify({+        id      : operation_id,+        document: stripIgnoredCharacters(query),+        variables,+      })+      const {+        ws,+      } = this+      const message_handler = ({+        data,+      }) => {+        const operation_response = JSON.parse(data.toString())+        const {+          id, end,+        } = operation_response+        if (id !== operation_id) return+        if (end) pass_through.end()+        else pass_through.write(operation_response)+      }

Pushing a lot of message_handle that do all the json parsing seems to not be a good idea I think you should create an EventTarget that dispatch event based on the operation_id

Sceat

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

 <h1 align=center>@hydre/graphql-websocket</h1> <p align=center>-  <img src="https://img.shields.io/github/license/hydreio/graphql-executor.svg?style=for-the-badge" />-  <a href="https://www.npmjs.com/package/@hydreio/graphql-executor">-    <img src="https://img.shields.io/npm/v/@hydreio/graphql-executor.svg?logo=npm&style=for-the-badge" />+  <img src="https://img.shields.io/github/license/hydreio/graphql-websocket.svg?style=for-the-badge" />+  <a href="https://www.npmjs.com/package/@hydre/graphql-websocket">+    <img src="https://img.shields.io/npm/v/@hydre/graphql-websocket.svg?logo=npm&style=for-the-badge" />   </a>-  <img src="https://img.shields.io/npm/dw/@hydreio/graphql-executor?logo=npm&style=for-the-badge" />-  <img src="https://img.shields.io/github/workflow/status/hydreio/graphql-executor/CI?logo=Github&style=for-the-badge" />+  <img src="https://img.shields.io/npm/dw/@hydre/graphql-websocket?logo=npm&style=for-the-badge" />+  <img src="https://img.shields.io/github/workflow/status/hydreio/graphql-websocket/CI?logo=Github&style=for-the-badge" /> </p>  <h3 align=center>A blazing fast graphql websocket server and client</h3> -> WIP UNDER DEVELOPMENT- - Node <kbd>14</kbd> - Concurrent batched operations leveraging async generators - Loadbalanced batched subscriptions - Koa-like Middlewares - Use with any http framework, or none+- Web & Node client included  ## Table of content <!-- omit in toc -->  - [Installation](#installation) - [Quick start](#quick-start)+  - [Server](#server)+  - [Client](#client) - [Documentation](#documentation)+- [Client browsers support](#client-browsers-support)  ## Installation +```sh+npm install @hydre/graphql-websocket+```+ ## Quick start -## Documentation\ No newline at end of file+### Server+```js+import Server from '@hydre/graphql-websocket/server'+// coming soon

?

Sceat

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import graphql from 'graphql'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const NORMAL_CLOSURE = 1000++export default (PassThrough, WebSocket) =>+  class Client {+    // variables are initialized because they are private+    // awaiting https://github.com/evanw/esbuild/issues/47+    // to use the # notation+    ws+    operation_id = 0+    address++    /**+     * Create a graphql client+     * @param {String} address The ws connection uri.+     */+    constructor(address) {+      if (typeof address !== 'string')+        throw new TypeError(`The address must be a string`)+      this.address = address+    }++    /**+     * Connect the client to his address,+     * a client must be disconnected before connecting again+     * or it will throw an error+     */+    async connect() {+      this.ws = new WebSocket(this.address)+      await new Promise((resolve, reject) => {+        this.ws.addEventListener('open', resolve)+        this.ws.addEventListener('error', reject)+      })+      log('client ready')+    }++    disconnect() {+      if (!this.ws)+        throw new Error('You must connect before disconnecting u genius..')+      this.ws.close(NORMAL_CLOSURE, 'closed by client')+      log('disconnected')+    }++    async query(query, variables = {}) {+      if (typeof query !== 'string')+        throw new Error('The query is not a String')++      // fail fast+      parse(query)+      log('querying')++      const operation_id = this.operation_id+++      const pass_through = new PassThrough({+        objectMode: true,+      })+      const serialized_query = JSON.stringify({+        id      : operation_id,+        document: stripIgnoredCharacters(query),+        variables,+      })+      const {+        ws,+      } = this+      const message_handler = ({+        data,+      }) => {+        const operation_response = JSON.parse(data.toString())+        const {+          id, end,+        } = operation_response+        if (id !== operation_id) return+        if (end) pass_through.end()+        else pass_through.write(operation_response)+      }+      const cleanup = () => {+        ws.removeEventListener('message', message_handler)+      }++      ws.addEventListener('message', message_handler)+      pass_through.on('end', cleanup)+      pass_through.on('finish', cleanup)+      ws.send(serialized_query)++      return {+        /**+         * @return the first response then end the operation+         */+        async json() {+          for await (const result of pass_through) {+            // we force the server to not send anymore stuff+            this.end()+            return result+          }++          return undefined+        },+        /**+         * Tell the server we want to stop receiving+         * updates from this operation+         */+        end() {+          // by sending again the operation id+          // the server will end it+          ws.send(JSON.stringify({+            id: operation_id,+          }))+          pass_through.end()+          log('operation %O terminated', operation_id)+        },+        /**+         * allows for...of+         */+        async *[Symbol.asyncIterator]() {+          yield* pass_through

I think you can avoid the pass_trough by with something like this https://github.com/rolftimmermans/event-iterator

Sceat

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

+(()=>{let e$=Object.defineProperty,f$=Object.hasOwnProperty,h$={},j$,k$=a$=>{let b$=h$[a$];return b$||(b$=h$[a$]={exports:{}},j$[a$](b$.exports,b$)),b$.exports},l$=a$=>{if(a$&&a$.__esModule)return a$;let b$={};for(let c$ in a$)f$.call(a$,c$)&&(b$[c$]=a$[c$]);return b$.default=a$,b$},p$=a$=>l$(k$(a$)),q$=(a$,b$)=>{e$(a$,"__esModule",{value:!0});for(let c$ in b$)e$(a$,c$,{get:b$[c$],enumerable:!0})};j$={126(q,j){var e=1000,f=e*60,g=f*60,d=g*24,k=d*7,l=d*365.25;j.exports=function(a,b){b=b||{};var c=typeof a;if(c==="string"&&a.length>0)return m(a);if(c==="number"&&isFinite(a))return b.long?o(a):n(a);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(a))};function m(a){a=String(a);if(a.length>100)return;var b=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(a);if(!b)return;var c=parseFloat(b[1]),i=(b[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return c*l;case"weeks":case"week":case"w":return c*k;case"days":case"day":case"d":return c*d;case"hours":case"hour":case"hrs":case"hr":case"h":return c*g;case"minutes":case"minute":case"mins":case"min":case"m":return c*f;case"seconds":case"second":case"secs":case"sec":case"s":return c*e;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}function n(a){var b=Math.abs(a);return b>=d?Math.round(a/d)+"d":b>=g?Math.round(a/g)+"h":b>=f?Math.round(a/f)+"m":b>=e?Math.round(a/e)+"s":a+"ms"}function o(a){var b=Math.abs(a);return b>=d?h(a,b,d,"day"):b>=g?h(a,b,g,"hour"):b>=f?h(a,b,f,"minute"):b>=e?h(a,b,e,"second"):a+" ms"}function h(a,b,c,i){var p=b>=c*1.5;return Math.round(a/c)+" "+i+(p?"s":"")}},1(A,o){function p(j){a.debug=a,a.default=a,a.coerce=v,a.disable=t,a.enable=s,a.enabled=u,a.humanize=k$(126),Object.keys(j).forEach(b=>{a[b]=j[b]}),a.instances=[],a.names=[],a.skips=[],a.formatters={};function k(b){let c=0;for(let d=0;d<b.length;d++)c=(c<<5)-c+b.charCodeAt(d),c|=0;return a.colors[Math.abs(c)%a.colors.length]}a.selectColor=k;function a(b){let c;function d(...e){if(!d.enabled)return;const f=d,g=Number(new Date()),w=g-(c||g);f.diff=w,f.prev=c,f.curr=g,c=g,e[0]=a.coerce(e[0]),typeof e[0]!=="string"&&e.unshift("%O");let h=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(i,y)=>{if(i==="%%")return i;h++;const m=a.formatters[y];if(typeof m==="function"){const z=e[h];i=m.call(f,z),e.splice(h,1),h--}return i}),a.formatArgs.call(f,e);const x=f.log||a.log;x.apply(f,e)}return d.namespace=b,d.enabled=a.enabled(b),d.useColors=a.useColors(),d.color=k(b),d.destroy=q,d.extend=r,typeof a.init==="function"&&a.init(d),a.instances.push(d),d}function q(){const b=a.instances.indexOf(this);return b!==-1?(a.instances.splice(b,1),!0):!1}function r(b,c){const d=a(this.namespace+(typeof c==="undefined"?":":c)+b);return d.log=this.log,d}function s(b){a.save(b),a.names=[],a.skips=[];let c;const d=(typeof b==="string"?b:"").split(/[\s,]+/),e=d.length;for(c=0;c<e;c++){if(!d[c])continue;b=d[c].replace(/\*/g,".*?"),b[0]==="-"?a.skips.push(new RegExp("^"+b.substr(1)+"$")):a.names.push(new RegExp("^"+b+"$"))}for(c=0;c<a.instances.length;c++){const f=a.instances[c];f.enabled=a.enabled(f.namespace)}}function t(){const b=[...a.names.map(l),...a.skips.map(l).map(c=>"-"+c)].join(",");return a.enable(""),b}function u(b){if(b[b.length-1]==="*")return!0;let c,d;for(c=0,d=a.skips.length;c<d;c++)if(a.skips[c].test(b))return!1;for(c=0,d=a.names.length;c<d;c++)if(a.names[c].test(b))return!0;return!1}function l(b){return b.toString().substring(2,b.toString().length-2).replace(/\.\*\?$/,"*")}function v(b){return b instanceof Error?b.stack||b.message:b}return a.enable(a.load()),a}o.exports=p},0(b,d){b.log=k,b.formatArgs=j,b.save=l,b.load=m,b.useColors=i,b.storage=n(),b.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function i(){return typeof window!=="undefined"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)?!0:typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:typeof document!=="undefined"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window!=="undefined"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function j(a){a[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+a[0]+(this.useColors?"%c ":" ")+"+"+d.exports.humanize(this.diff);if(!this.useColors)return;const c="color: "+this.color;a.splice(1,0,c,"color: inherit");let e=0,f=0;a[0].replace(/%[a-zA-Z%]/g,g=>{if(g==="%%")return;e++,g==="%c"&&(f=e)}),a.splice(f,0,c)}function k(...a){return typeof console==="object"&&console.log&&console.log(...a)}function l(a){try{a?b.storage.setItem("debug",a):b.storage.removeItem("debug")}catch(c){}}function m(){let a;try{a=b.storage.getItem("debug")}catch(c){}return!a&&typeof process!=="undefined"&&"env"in process&&(a=process.env.DEBUG),a}function n(){try{return localStorage}catch(a){}}d.exports=k$(1)(b);const{formatters:o}=d.exports;o.j=function(a){try{return JSON.stringify(a)}catch(c){return"[UnexpectedJSONParseError]: "+c.message}}},125(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.versionInfo=a.version=void 0;var b="15.0.0";a.version=b;var c=Object.freeze({major:15,minor:0,patch:0,preReleaseTag:null});a.versionInfo=c},22(b){"use strict";Object.defineProperty(b,"__esModule",{value:!0}),b.default=c;function c(a){return typeof(a===null||a===void 0?void 0:a.then)==="function"}},27(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=void 0;var b=typeof Symbol==="function"&&typeof Symbol.for==="function"?Symbol.for("nodejs.util.inspect.custom"):void 0,c=b;a.default=c},17(i){"use strict";Object.defineProperty(i,"__esModule",{value:!0}),i.default=o;var l=m(k$(27));function m(a){return a&&a.__esModule?a:{default:a}}function g(a){return typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?g=function c(b){return typeof b}:g=function c(b){return b&&typeof Symbol==="function"&&b.constructor===Symbol&&b!==Symbol.prototype?"symbol":typeof b},g(a)}var n=10,j=2;function o(a){return h(a,[])}function h(a,c){switch(g(a)){case"string":return JSON.stringify(a);case"function":return a.name?"[function ".concat(a.name,"]"):"[function]";case"object":return a===null?"null":p(a,c);default:return String(a)}}function p(a,c){if(c.indexOf(a)!==-1)return"[Circular]";var b=[].concat(c,[a]),e=s(a);if(e!==void 0){var d=e.call(a);if(d!==a)return typeof d==="string"?d:h(d,b)}else if(Array.isArray(a))return r(a,b);return q(a,b)}function q(a,c){var b=Object.keys(a);if(b.length===0)return"{}";if(c.length>j)return"["+t(a)+"]";var e=b.map(function(d){var f=h(a[d],c);return d+": "+f});return"{ "+e.join(", ")+" }"}function r(a,c){if(a.length===0)return"[]";if(c.length>j)return"[Array]";for(var b=Math.min(n,a.length),e=a.length-b,d=[],f=0;f<b;++f)d.push(h(a[f],c));return e===1?d.push("... 1 more item"):e>1&&d.push("... ".concat(e," more items")),"["+d.join(", ")+"]"}function s(a){var c=a[String(l.default)];if(typeof c==="function")return c;if(typeof a.inspect==="function")return a.inspect}function t(a){var c=Object.prototype.toString.call(a).replace(/^\[object /,"").replace(/]$/,"");if(c==="Object"&&typeof a.constructor==="function"){var b=a.constructor.name;if(typeof b==="string"&&b!=="")return b}return c}},14(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.default=b;function b(c,d){var e=Boolean(c);if(!e)throw new Error(d)}},21(d){"use strict";Object.defineProperty(d,"__esModule",{value:!0}),d.default=e;function b(c){return typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?b=function f(a){return typeof a}:b=function f(a){return a&&typeof Symbol==="function"&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},b(c)}function e(c){return b(c)=="object"&&c!==null}},54(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0}),a.SYMBOL_TO_STRING_TAG=a.SYMBOL_ASYNC_ITERATOR=a.SYMBOL_ITERATOR=void 0;var b=typeof Symbol==="function"?Symbol.iterator:"@@iterator";a.SYMBOL_ITERATOR=b;var c=typeof Symbol==="function"?Symbol.asyncIterator:"@@asyncIterator";a.SYMBOL_ASYNC_ITERATOR=c;var d=typeof Symbol==="function"?Symbol.toStringTag:"@@toStringTag";a.SYMBOL_TO_STRING_TAG=d},39(c){"use strict";Object.defineProperty(c,"__esModule",{value:!0}),c.getLocation=f;function f(g,b){for(var h=/\r\n|[\n\r]/g,d=1,e=b+1,a;(a=h.exec(g.body))&&a.index<b;)d+=1,e=b+1-(a.index+a[0].length);return{line:d,column:e}}},42(m){"use strict";Object.defineProperty(m,"__esModule",{value:!0}),m.printLocation=u,m.printSourceLocation=o;var t=k$(39);function u(a){return o(a.source,(0,t.getLocation)(a.source,a.start))}function o(a,b){var h=a.locationOffset.column-1,c=g(h)+a.body,d=b.line-1,e=a.locationOffset.line-1,f=b.line+e,w=b.line===1?h:0,i=b.column+w,q="".concat(a.name,":").concat(f,":").concat(i,`

This file should not be here

Sceat

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import graphql from 'graphql'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const NORMAL_CLOSURE = 1000++export default (PassThrough, WebSocket) =>+  class Client {+    // variables are initialized because they are private+    // awaiting https://github.com/evanw/esbuild/issues/47+    // to use the # notation+    ws+    operation_id = 0+    address++    /**+     * Create a graphql client+     * @param {String} address The ws connection uri.+     */+    constructor(address) {+      if (typeof address !== 'string')+        throw new TypeError(`The address must be a string`)+      this.address = address+    }++    /**+     * Connect the client to his address,+     * a client must be disconnected before connecting again+     * or it will throw an error+     */+    async connect() {+      this.ws = new WebSocket(this.address)+      await new Promise((resolve, reject) => {+        this.ws.addEventListener('open', resolve)+        this.ws.addEventListener('error', reject)+      })+      log('client ready')+    }++    disconnect() {+      if (!this.ws)+        throw new Error('You must connect before disconnecting u genius..')+      this.ws.close(NORMAL_CLOSURE, 'closed by client')+      log('disconnected')+    }++    async query(query, variables = {}) {+      if (typeof query !== 'string')+        throw new Error('The query is not a String')++      // fail fast+      parse(query)

You really need to import the whole graphql parser just for this ?

Sceat

comment created time in 25 days

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import graphql from 'graphql'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const NORMAL_CLOSURE = 1000++export default (PassThrough, WebSocket) =>

Nice

Sceat

comment created time in 25 days

issue openedzephyrproject-rtos/zephyr

Bluetooth Isochronous Channels Support

Describe the solution you'd like Support Bluetooth LE 5.2 Isochronous Channel in zephyr controller subsystem

Additional context Isochronous Channel is a new addition in Bluetooth 5.2 specification it the fondation for LE Audio

Is there any support planned ?

created time in 25 days

push eventDeltaEvo/test_doc

David Duarte

commit sha 452b9fba700695bfd280191459b7565dabe4661a

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 607cc19bb973f84840b5c1a9faefd9a780ba8ab0

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 0ed630ae612c3328632484abc12629d94bb085bc

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 6d521733498ff4bee415c54767d197e93631811f

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 5f7e743cf1e7aa82dfa811a96332d1ff71a77c0a

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 8c7059dda09e094463c0b913a4e90b7facb9a821

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 6a846f2a7b3af9712a8f6d0665d3e99ea70aea19

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 57a41e21c1b5f234118761f40de0f76ca7a878cc

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha b386e8e2b86685428b5db3b00be49188c2102346

lol

view details

push time in a month

push eventDeltaEvo/test_doc

David Duarte

commit sha 9a4b267dd8e351b1d759fe3613df784544799b24

lol

view details

push time in a month

create barnchDeltaEvo/test_doc

branch : master

created branch time in a month

created repositoryDeltaEvo/test_doc

created time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import {+  on,+} from 'events'+import graphql from 'graphql'+import which_stream from './stream.js'+import {+  promisify,+} from 'util'+import WebSocket from 'ws'+import invariant from 'invariant'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const DEFAULT_TIMEOUT = 31_000+const util_promisify =

Webpack will polyfill it

Sceat

comment created time in a month

startedHydreIO/graphql-batch-executor

started time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import {+  on,+} from 'events'+import graphql from 'graphql'+import which_stream from './stream.js'+import {+  promisify,+} from 'util'+import WebSocket from 'ws'+import invariant from 'invariant'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const DEFAULT_TIMEOUT = 31_000+const util_promisify =

Why when you have promisify from util ?

Sceat

comment created time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import {+  on,+} from 'events'+import graphql from 'graphql'+import which_stream from './stream.js'+import {+  promisify,+} from 'util'+import WebSocket from 'ws'+import invariant from 'invariant'++const log = debug('gql-ws').extend('client')+const {+  stripIgnoredCharacters, parse,+} = graphql+const DEFAULT_TIMEOUT = 31_000+const util_promisify =+  fn =>+    (...parameters) =>+      new Promise(callback => {+        Reflect.apply(+            fn, fn, [...parameters, callback],+        )+      })++// Hate doing that but as i don't want to write 2 clients file+// for either node and the browser i kinda hack my way into it+// by using a runtime resolved instance of stream+// which will be node streams in node+// and the readable-stream package in the browser+// eslint-disable-next-line no-unused-vars+// eslint-disable-next-line init-declarations+let stream++export default class Client {+  #ws+  #streams+  #timeout+  #options+  #protocols+  #operation_id = 0++  /**+   * Create a graphql websocket client+   * @param {Object} payload+   * @param {String|Array} payload.protocols The list of subprotocols.+   * @param {Object} payload.ws_options see https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketaddress-protocols-options+   * @param {Number} payload.timeout the server timeout+   * + a latency prevision, ex: 30000 + 1000+   */+  constructor({+    protocols, ws_options, timeout = DEFAULT_TIMEOUT,+  }) {+    log('initializing client..')+    this.#streams = new Map()+    this.#timeout = timeout+    this.#protocols = protocols+    this.#options = ws_options+  }++  async pipe_streams() {+    // let's get our streams gentlemens+    stream = await which_stream()+    // === end hack /shrug+    const async_pipeline = util_promisify(stream.pipeline)++    await async_pipeline(on(this.#ws, 'message'), async source => {+      try {+        for await (const chunk of source) {+          const operation_response = JSON.parse(chunk.toString())+          log('incomming operation %O', operation_response)+          const {+            id,+          } = operation_response+          const through = this.#streams.get(id)+          if (!through.write(operation_response))+            await promisify(through.once.bind(through))('drain')+        }+      } catch (error) {+        console.error(error)+      }+    })+    log('disconnected')+  }++  heartbeat() {+    clearTimeout(this.#ws.timeout)+    this.#ws.timeout = setTimeout(() => {+      this.#ws.terminate()

terminate ?

Sceat

comment created time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import WebSocket from 'ws'+import http from 'http'+import compose from 'koa-compose'+import Executor from '@hydre/graphql-batch-executor'++import {+  on,+} from 'events'++import {+  pipeline,+} from 'stream'++const log = debug('gql-ws').extend('server')+const DEFAULT_TIMEOUT = 30_000++export default class {+  #ws_options+  #schema+  #rootValue+  #context+  #web_server++  #middleware = []+  #context_is_static+  #timeout++  /**+   * Initialize a graphql websocket server with a configuration object+   * @param {Object} options - server options+   * @param {Number} [options.timeout=30000] - in millisecond,+   *  try to deconnect non reachable clients+   * @param {Object} [options.ws_options] - see https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback+   * @param {graphql.SchemaDefinitionNode} options.schema - a graphql schema+   * @param {Object} options.rootValue - a graphql resolver object+   * @param {(Object|Function)} [options.context={}] - the context object+   * or as a function/async function to dynamically+   * build it on every upgrade request+   */+  constructor({+    ws_options = {+      path             : '/',+      perMessageDeflate: false,+      maxPayload       : 500,+    },+    schema = (() => {+      throw new Error('Missing or invalid schema')+    })(),+    rootValue = {},+    context = {},+    web_server = http.createServer(),+    timeout = DEFAULT_TIMEOUT,+  }) {+    this.#ws_options = ws_options+    this.#schema = schema+    this.#rootValue = rootValue+    this.#web_server = web_server+    this.#context = context+    this.#timeout = timeout++    this.#context_is_static = typeof context === 'object'+  }++  /**+   * Resolve the context to allow usage of dynamic context building+   * @param {(Object | Function | AsyncFunction)} context+   */+  context(...parameters) {+    if (this.#context_is_static) return this.#context+    return this.#context(...parameters)+  }++  use(middleware) {+    this.#middleware.push(middleware)+  }++  listen(...parameters) {+    const middleware = compose(this.#middleware)+    const http_server = this.#web_server.listen(...parameters)+    // we prevent usage of those as it's up to the http server to decide+    // @see https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback+    const {+      // throwing off both vars+      // eslint-disable-next-line no-unused-vars+      host,+      // eslint-disable-next-line no-unused-vars+      port,+      ...options+    } = this.#ws_options+    const wss = new WebSocket.Server({+      ...options,+      noServer: true,+    })++    wss.on('connection', (+        ws, {+          headers,+        }, contextValue,+    ) => {+      const client_id = headers['sec-websocket-key']+      const log_peer = log.extend(client_id)++      log_peer('connected!')++      const executor = new Executor({+        id             : client_id,+        schema         : this.#schema,+        rootValue      : this.#rootValue,+        contextValue,+        high_water_mark: 40,+      })+      const user_streams = new Map()++      ws.alive = true+      ws.force_terminate = () => {+        for (const stream of user_streams.values()) stream.end()+        ws.terminate()+        log_peer('terminated')+      }++      ws.on('pong', () => {+        ws.alive = true+      })+      ws.on('error', error => {+        log_peer(error)+        ws.force_terminate()+      })+      ws.on('close', () => {+        ws.force_terminate()+      })++      pipeline(+          on(ws, 'message'),+          async function *(source) {+            for await (const chunk of source) {+              const {+                id: operation_id, document, variables, unsub,+              } = JSON.parse(chunk.toString())++              if (unsub) {+                const stream = user_streams.get(operation_id)+                if (stream) {+                  log_peer('stream %s was terminated', operation_id)+                  stream.end()+                }++                continue+              }++              yield {+                id: operation_id,+                document,+                variables,+              }+            }+          },+          executor.generate.bind(executor),+          async source => {+            for await (const {+              id: stream_id, stream,+            } of source) {+              const existing_stream = user_streams.get(stream_id)+              if (existing_stream) existing_stream.end()+              user_streams.set(stream_id, stream)++              pipeline(+                  stream,+                  async stream_source => {+                    for await (const chunk of stream_source) {+                      if (!ws.alive) {+                        ws.force_terminate()+                        return+                      }++                      const {+                        id: query_id,+                        operation_type,+                        operation_name,+                        data,+                        errors,+                      } = chunk+                      log_peer(+                          'sending %O[%O]: %O',+                          operation_type,+                          operation_name,+                    errors?.length ? errors : data,+                      )+                      ws.send(JSON.stringify({+                        id: query_id,+                        operation_type,+                        operation_name,+                        data,+                        errors,+                      }))+                    }+                  },+                  error => {+                    if (error) console.error(error)+                    else log_peer('operation terminated')+                  },+              )+            }+          },+          () => {+            log_peer('disconnected')+          },+      )+    })++    const interval = setInterval(() => {+      wss.clients.forEach(ws => {+        if (!ws.alive) {+          ws.force_terminate()+          return+        }++        ws.alive = false

You realy need to handle this yourself ?

Sceat

comment created time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+export default async () => {+  // eslint-disable-next-line no-undef+  const stream = await globalThis.process?.release?.name ?+    import('stream') : import('readable-stream')

Do you really need this, webpack don't do this job already ?

Sceat

comment created time in a month

Pull request review commentHydreIO/graphql-websocket

Release/stable

+import debug from 'debug'+import WebSocket from 'ws'+import http from 'http'+import compose from 'koa-compose'+import Executor from '@hydre/graphql-batch-executor'++import {+  on,+} from 'events'++import {+  pipeline,+} from 'stream'++const log = debug('gql-ws').extend('server')+const DEFAULT_TIMEOUT = 30_000++export default class {+  #ws_options+  #schema+  #rootValue+  #context+  #web_server++  #middleware = []+  #context_is_static+  #timeout++  /**+   * Initialize a graphql websocket server with a configuration object+   * @param {Object} options - server options+   * @param {Number} [options.timeout=30000] - in millisecond,+   *  try to deconnect non reachable clients+   * @param {Object} [options.ws_options] - see https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback+   * @param {graphql.SchemaDefinitionNode} options.schema - a graphql schema+   * @param {Object} options.rootValue - a graphql resolver object+   * @param {(Object|Function)} [options.context={}] - the context object+   * or as a function/async function to dynamically+   * build it on every upgrade request+   */+  constructor({+    ws_options = {+      path             : '/',+      perMessageDeflate: false,+      maxPayload       : 500,+    },+    schema = (() => {+      throw new Error('Missing or invalid schema')+    })(),+    rootValue = {},+    context = {},+    web_server = http.createServer(),+    timeout = DEFAULT_TIMEOUT,+  }) {+    this.#ws_options = ws_options+    this.#schema = schema+    this.#rootValue = rootValue+    this.#web_server = web_server+    this.#context = context+    this.#timeout = timeout++    this.#context_is_static = typeof context === 'object'+  }++  /**+   * Resolve the context to allow usage of dynamic context building+   * @param {(Object | Function | AsyncFunction)} context+   */+  context(...parameters) {+    if (this.#context_is_static) return this.#context+    return this.#context(...parameters)+  }++  use(middleware) {+    this.#middleware.push(middleware)+  }++  listen(...parameters) {+    const middleware = compose(this.#middleware)+    const http_server = this.#web_server.listen(...parameters)+    // we prevent usage of those as it's up to the http server to decide+    // @see https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback+    const {+      // throwing off both vars+      // eslint-disable-next-line no-unused-vars+      host,+      // eslint-disable-next-line no-unused-vars+      port,

I think i migth be better to add a varsIgnorePattern for the eslint rule like if you variable start with _

Sceat

comment created time in a month

startedstreetsidesoftware/cspell

started time in a month

startedintel/tinycrypt

started time in a month

starteddocumentationjs/documentation

started time in a month

startedCONNECT-platform/codedoc

started time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};

If it's only this

:upside_down_face:

const index_check = (aValues, object) => {
  const TOKENIZER_ARRAY = aValues.flatMap(value => {
    if (value.includes('@index')) {
      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {
        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');
      }
      const FIELDS = value.slice(7, -1).split(',');
      return FIELDS.map(field =>field.trim());
    }
    return [];
  });
  if (TOKENIZER_ARRAY.length) {
    object.index = true;
    object.tokenizer = TOKENIZER_ARRAY;
  }
};
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};

Why this won't work ?

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());

eslint complain that you are shadowin a variable, so if someone read your code it could be tricked or doesn't know easily form where the variable came from: the global scope or the argument So you just need another name, or remove you global SCHEMA & TYPES :smile: (This option is better, global state is bad)

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);

It's because you have something that keep you event loop alive, like the client that you never destroyed :smile:

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);+});++program.command('get_diff').action(async () => {+  const CLIENT = helper.create_client();+  const DIFFERENCES = await get_diff(CLIENT);+  print_diff(DIFFERENCES);+  process.exit(0);+});++program.command('alter_schema').action(async () => {+  const FORCE_FLAG = !!program.force;+  const CLIENT = helper.create_client();+  await alter_schema(CLIENT, FORCE_FLAG);+  process.exit(0);+});++program.parse(process.argv);

parse is not an async function so if the async function inside your action reject the rejection will be lost, so to get back this rejection you should use parseAsync as explained in the README of commander :)

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());

You should take DB_URL as parameter :smile:

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);+});++program.command('get_diff').action(async () => {+  const CLIENT = helper.create_client();+  const DIFFERENCES = await get_diff(CLIENT);+  print_diff(DIFFERENCES);+  process.exit(0);+});++program.command('alter_schema').action(async () => {+  const FORCE_FLAG = !!program.force;+  const CLIENT = helper.create_client();+  await alter_schema(CLIENT, FORCE_FLAG);+  process.exit(0);

Why do you need to exit the event loop by hand It will stop automatically when there is no work left

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });

Use filter and map here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);+});++program.command('get_diff').action(async () => {+  const CLIENT = helper.create_client();+  const DIFFERENCES = await get_diff(CLIENT);+  print_diff(DIFFERENCES);+  process.exit(0);+});++program.command('alter_schema').action(async () => {+  const FORCE_FLAG = !!program.force;+  const CLIENT = helper.create_client();+  await alter_schema(CLIENT, FORCE_FLAG);+  process.exit(0);+});++program.parse(process.argv);

You are using action action handler you should use parseAsync https://www.npmjs.com/package/commander#action-handler-subcommands

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {

6 and 7 are magic values prefer using

value.slice('@index'.length)[0]
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });+        } else if (typeof NEW_OBJECT !== 'undefined' && typeof NEW_OBJECT.index !== 'undefined' && NEW_OBJECT.index === true && difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Tokenizer of this objects was edited.',+            category: 'schema',+            object: { ...CURRENT_OBJECT },+          });+        }+      });+    }+  });+  MISSING_PREDICATES.forEach(predicate => {+    const DELETED_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    CONFLICTS.push({+      message: 'This object was deleted.',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const raw_schema = () => {+  let raw_predicates = '';+  Object.entries(SCHEMA).forEach(([key, value]) => {+    raw_predicates += `${key}: ${value}\n`;+  });

You don't event want to reduce it What you want is

  Object.entries(SCHEMA).map(([key, value]) => `${key}: ${value}`).join('\n')
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });

Use map here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });+        } else if (typeof NEW_OBJECT !== 'undefined' && typeof NEW_OBJECT.index !== 'undefined' && NEW_OBJECT.index === true && difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Tokenizer of this objects was edited.',+            category: 'schema',+            object: { ...CURRENT_OBJECT },+          });+        }+      });+    }+  });+  MISSING_PREDICATES.forEach(predicate => {+    const DELETED_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    CONFLICTS.push({+      message: 'This object was deleted.',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const raw_schema = () => {+  let raw_predicates = '';+  Object.entries(SCHEMA).forEach(([key, value]) => {

Take SCHEMA as parameter

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];

Prefer returning an object here it's more explicit for it's content

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });+        } else if (typeof NEW_OBJECT !== 'undefined' && typeof NEW_OBJECT.index !== 'undefined' && NEW_OBJECT.index === true && difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Tokenizer of this objects was edited.',+            category: 'schema',+            object: { ...CURRENT_OBJECT },+          });+        }+      });+    }+  });+  MISSING_PREDICATES.forEach(predicate => {+    const DELETED_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    CONFLICTS.push({+      message: 'This object was deleted.',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];

Use an object here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });

Use multiple filter here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });+        } else if (typeof NEW_OBJECT !== 'undefined' && typeof NEW_OBJECT.index !== 'undefined' && NEW_OBJECT.index === true && difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Tokenizer of this objects was edited.',+            category: 'schema',+            object: { ...CURRENT_OBJECT },

Mmh why do you copy the object ?

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });

Use map here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}

And u sure using for loops with index in JS is legal :upside_down_face: ?

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });

Use mutiple filter call here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}++const diff_types_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const TYPES_TO_CHECK = [];+  const MISSING_TYPES = [];++  new_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    TYPES_TO_CHECK.push(type.name);+  });++  current_schema.types.forEach(type => {+    type.fields.sort(compare_types_fields);+    if (!TYPES_TO_CHECK.includes(type.name)) {+      MISSING_TYPES.push(type.name);+    }+  });++  TYPES_TO_CHECK.forEach(type => {+    const NEW_OBJECT = new_schema.types.find(object => object.name === type);+    const CURRENT_OBJECT = current_schema.types.find(object => object.name === type);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT);+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path: ${difference.path[0]}`,+            category: 'types',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected ${difference.lhs} found ${difference.rhs}`,+          });+        } else if (difference.kind === 'N') {+          ADDED.push({+            message: 'This new object was added.',+            category: 'types',+            object: { ...NEW_OBJECT },+          });+        } else if (difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Change in the fields in this object.',+            category: 'types',+            object: CURRENT_OBJECT,+          });+        }+      });+    }+  });++  MISSING_TYPES.forEach(type => {+    const DELETED_OBJECT = current_schema.types.find(object => object.name === type);+    CONFLICTS.push({+      message: 'This object was deleted.',+      category: 'types',+      object: { ...DELETED_OBJECT },+    });+  });++  return [CONFLICTS, ADDED];+}++const diff_schema_checker = (new_schema, current_schema) => {+  const CONFLICTS = [];+  const ADDED = [];+  const PREDICATES_TO_CHECK = [];+  const MISSING_PREDICATES = [];++  new_schema.schema.forEach(element => {+    PREDICATES_TO_CHECK.push(element.predicate);+  });++  current_schema.schema.forEach(element => {+    if (!PREDICATES_TO_CHECK.includes(element.predicate)) {+      MISSING_PREDICATES.push(element.predicate);+    }+  });++  PREDICATES_TO_CHECK.forEach(predicate => {+    const NEW_OBJECT = new_schema.schema.find(object => object.predicate === predicate);+    const CURRENT_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    const DIFFERENCES = diff(CURRENT_OBJECT, NEW_OBJECT); // Can have multiple diff for 1 object+    if (typeof DIFFERENCES !== 'undefined') {+      DIFFERENCES.forEach(difference => {+        if (difference.kind === 'E') {+          CONFLICTS.push({+            message: `This object was edited at path:${difference.path[0]}`,+            category: 'schema',+            object: { ...CURRENT_OBJECT },+            additional_information: `Expected${difference.rhs}found${difference.lhs}`,+          });+        } else if (difference.kind === 'N') {+          if (typeof CURRENT_OBJECT === 'undefined') {+            ADDED.push({+              message: 'This object was added.',+              object: { ...NEW_OBJECT },+            });+          } else {+            CONFLICTS.push({+              message: 'This object was edited',+              category: 'schema',+              object: { ...NEW_OBJECT },+            });+          }+        } else if (difference.kind === 'D' && difference.path[0] === 'list') {+          CONFLICTS.push({+            message: 'This object was edited, should be a list.',+            category: 'schema',+            object: { ...NEW_OBJECT },+          });+        } else if (typeof NEW_OBJECT !== 'undefined' && typeof NEW_OBJECT.index !== 'undefined' && NEW_OBJECT.index === true && difference.kind === 'A') {+          CONFLICTS.push({+            message: 'Tokenizer of this objects was edited.',+            category: 'schema',+            object: { ...CURRENT_OBJECT },+          });+        }+      });+    }+  });+  MISSING_PREDICATES.forEach(predicate => {+    const DELETED_OBJECT = current_schema.schema.find(object => object.predicate === predicate);+    CONFLICTS.push({+      message: 'This object was deleted.',+      object: { ...DELETED_OBJECT },+    });+  });

Use map here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}

Same comments that function before

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++// Custom comparator for sorting types+const compare_name_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.name.toUpperCase();+  const PREDICATE_B = object_b.name.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;+}++const prepare_new_schema = () => {+  const SORTED_SCHEMA = create_json_schema().sort(compare_predicate_object);+  const SORTED_TYPES = create_json_types().sort(compare_name_object);+  return {+    schema: SORTED_SCHEMA,+    types: SORTED_TYPES,+  };+}++// Removes Dgraph autogenerated predicates & types+const remove_dgraph_data = uneprepared_schema => {+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.graphql.schema') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.schema.length; i++) {+    if (uneprepared_schema.schema[i].predicate === 'dgraph.type') {+      uneprepared_schema.schema.splice(i, 1);+      break;+    }+  }+  for (let i = 0; i < uneprepared_schema.types.length; i++) {+    if (uneprepared_schema.types[i].name === 'dgraph.graphql') {+      uneprepared_schema.types.splice(i, 1);+      break;+    }+  }+  return uneprepared_schema;+}++const prepare_current_schema = async client => {+  const FETECHED_SCHEMA = await get_schema(client);+  const FORMATED_SCHEMA = remove_dgraph_data(FETECHED_SCHEMA);+  FORMATED_SCHEMA.schema.sort(compare_predicate_object);+  FORMATED_SCHEMA.types.sort(compare_name_object);+  return FORMATED_SCHEMA;+}++const compare_types_fields = (field_a, field_b) => {+  const TYPE_A = field_a.name.toUpperCase();+  const TYPE_B = field_b.name.toUpperCase();++  let comparator = 0;+  if (TYPE_A > TYPE_B) {+    comparator = 1;+  } else if (TYPE_A < TYPE_B) {+    comparator = -1;+  }+  return comparator;+}

Same comment as the other comparation functions

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {+    const OBJECT = { name: key };+    const FIELDS = [];+    value.forEach(field => {+      FIELDS.push({ name: field });+    });+    OBJECT.fields = FIELDS;+    JSON_TYPES.push(OBJECT);+  });+  return JSON_TYPES;+}++// Custom comparator for sorting our schema+const compare_predicate_object = (object_a, object_b) => {+  const PREDICATE_A = object_a.predicate.toUpperCase();+  const PREDICATE_B = object_b.predicate.toUpperCase();++  let comparator = 0;+  if (PREDICATE_A > PREDICATE_B) {+    comparator = 1;+  } else if (PREDICATE_A < PREDICATE_B) {+    comparator = -1;+  }+  return comparator;

Since this is now 1 line with the change suggested by @Sceat the function seems to be useless, use a lambda directly inside sort

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;+}++const create_json_types = () => {+  const JSON_TYPES = [];+  Object.entries(TYPES).forEach(([key, value]) => {

You should take TYPES as parameter

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {

You should take SCHEMA as parameter

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);

other_options seems to be only used here, I don't think you need to separate it in another function

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);

index_check seems to be only used here, I don't think you need to separate it in another function

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);

type_check seems to be only used here, I don't think you need to separate it in another function

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');

7 is a magic value prefer using

value.slice("@index(".length, -1)
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}++const create_json_schema = () => {+  const JSON_SCHEMA = [];+  Object.entries(SCHEMA).forEach(([key, value]) => {+    const OBJECT = { predicate: key };+    const PREDICATES_ARRAY = prepare_value_string(value);+    try {+      type_check(PREDICATES_ARRAY[0], OBJECT);+    } catch (error) {+      console.error(error);+    }+    PREDICATES_ARRAY.shift();+    try {+      index_check(PREDICATES_ARRAY, OBJECT);+    } catch (error) {+      console.error(error);+    }+    other_options(PREDICATES_ARRAY, OBJECT);+    JSON_SCHEMA.push(OBJECT);+  });+  return JSON_SCHEMA;

You should use map instead of forEach here

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};++const other_options = (aValues, object) => {+  aValues.forEach(value => {+    if (value.includes('@upsert')) {+      object.upsert = true;+    } else if (value.includes('@lang')) {+      object.lang = true;+    }+  })+}

You should not modify object

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};++const index_check = (aValues, object) => {+  const TOKENIZER_ARRAY = [];+  const INDEX = aValues.some(value => {+    if (value.includes('@index')) {+      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {+        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');+      }+      const FIELDS = value.slice(7, -1).split(',');+      FIELDS.forEach(field => {+        TOKENIZER_ARRAY.push(field.trim());+      });+      return true;+    }+    return false;+  });+  if (INDEX) {+    object.index = INDEX;+    object.tokenizer = TOKENIZER_ARRAY;+  }+};

You should not modify object

You can use map & flatMap instead of some & forEach

const index_check = (aValues, object) => {
  const TOKENIZER_ARRAY = aValues.flatMap(value => {
    if (value.includes('@index')) {
      if (value.slice(6, 7) !== '(' || value.slice(-1) !== ')') {
        throw new Error('@index is invalid, missing parenthesis or there are spaces in tokenizer.');
      }
      const FIELDS = value.slice(7, -1).split(',');
      return FIELDS.map(field =>field.trim());
    }
    return [];
  });
  if (TOKENIZER_ARRAY.length) {
    object.index = INDEX;
    object.tokenizer = TOKENIZER_ARRAY;
  }
};
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};++const type_check = (type, object) => {+  const NORMAL_TYPES = ['default', 'bool', 'datetime', 'float', 'geo', 'int', 'password', 'string', 'uid'];+  const LIST_TYPES = ['[default]', '[bool]', '[datetime]', '[float]', '[geo]', '[int]', '[string]', '[uid]'];+  const TYPE_IS_NOT_ALIST = NORMAL_TYPES.some(value => value === type);+  const TYPE_IS_LIST = LIST_TYPES.some(value => value === type);+  if (!TYPE_IS_NOT_ALIST && !TYPE_IS_LIST) {+    throw new Error('Incorrect or missing type in predicate.');+  } else if (TYPE_IS_LIST) {+    object.type = type.slice(1, -1);+  } else {+    object.type = type;+  }+  if (TYPE_IS_LIST) {+    object.list = true;+  }+};

:+1:

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;++const create_client = () => {+  const CLIENT_STUB = new dgraph.DgraphClientStub(DB_URL, grpc.credentials.createInsecure());+  return new dgraph.DgraphClient(CLIENT_STUB);+}++const get_schema = async client => (await client.newTxn().query('schema {}')).getJson();++const prepare_value_string = predicate => {+  const PREPARED_ARRAY = predicate.split(' ');+  if (PREPARED_ARRAY[PREPARED_ARRAY.length - 1] === '.') {+    PREPARED_ARRAY.pop();+  } else {+    throw new Error('Missing . at the end of predicate, or incorrect spacing.');+  }+  return PREPARED_ARRAY;+};
const prepare_value_string = predicate => {
  if (!predicate.endsWith('.')) throw new Error('Missing . at the end of predicate, or incorrect spacing.');
  return predicate.slice(-1).split(' ');
};
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};

I don't think having two CLI is good (one with "prompt" style and another with flags) You should consider keeping only one If you want still to have both or keep the "prompt" one your readline interface interface is not really user friendly, some lib provide nicer interface like https://www.npmjs.com/package/inquirer

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+import diff from 'deep-diff';+import dgraph from 'dgraph-js';+import grpc from 'grpc';++import { SCHEMA, TYPES } from './schema';++const DB_URL = process.env.DGRAPH_URL;
const {
  DB_URL: DGRAPH_URL
} = process.env;
Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);+});++program.command('get_diff').action(async () => {+  const CLIENT = helper.create_client();+  const DIFFERENCES = await get_diff(CLIENT);+  print_diff(DIFFERENCES);+  process.exit(0);

Why do you need to exit the event loop by hand It will stop automatically when there is no work left

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {+    if (toDo !== '1' && toDo !== '2' && toDo !== '3') {+      console.log(c.underline.yellow('Incorrect action'));+      main();+    } else if (toDo === '1') {+      console.log(c.greenBright('\nCurrent Dgraph schema:'));+      get_schema();+      rl.close();+    } else if (toDo === '2') {+      const CLIENT = helper.create_client();+      const DIFFERENCES = await get_diff(CLIENT);+      print_diff(DIFFERENCES);+      rl.close();+    } else if (toDo === '3') {+      const FORCE_FLAG = !!program.force;+      const CLIENT = helper.create_client();+      await helper.diff_checker(CLIENT, FORCE_FLAG);+      rl.close();+    }+  });+};+++program+  .version('0.0.1')+  .option('-F, --force', 'Used to force alter a schema even if there are conflicts.')+  .action(cmd => {+    const { args } = cmd;+    if (args.length === 0) {+      main();+    } else {+      console.log('There are args:', args);+      try {+        if (!fs.existsSync('./schemaa.js')) {+          console.error(c.redBright('File ./schema.js does not exists. It is required to continue.'));+        }+      } catch (error) {+        console.error(error);+      }+      process.exit(0);+    }+  });++program.command('get_schema').action(async () => {+  await get_schema();+  process.exit(0);

Why do you need to exit the event loop by hand It will stop automatically when there is no work left

Sceat

comment created time in a month

Pull request review commentHydreIO/dgraph-schema

WIP: feature/cli

+#!/usr/bin/env node+import c from 'chalk';+import program from 'commander';+import fs from 'fs';+import readline from 'readline';+import util from 'util';++import helper from './dgraphHelper';++const rl = readline.createInterface({+  input: process.stdin,+  output: process.stdout,+});++const get_schema = async () => {+  const CLIENT = helper.create_client();+  const fetched_schema = await helper.get_schema(CLIENT);+  console.log(util.inspect(fetched_schema, false, null, true));+}++const get_diff = async client => helper.diff_checker(client);++const print_diff = differences => {+  const CONFLICTS = differences[0];+  const ADDED = differences[1];++  if (CONFLICTS.length > 0) {+    console.log(c.redBright('Can\'t alter schema, there are conflicts.'));+    CONFLICTS.forEach(element => {+      console.log(element);+    });+  } else if (ADDED.length > 0) {+    console.log(c.greenBright('New changes only.'));+    ADDED.forEach(element => {+      console.log(element);+    });+  } else {+    console.log(c.greenBright('Same schema, no alter needed.'));+  }+}++const alter_schema = async (client, force_flag) => {+  const DIFFERENCES = await get_diff(client);+  print_diff(DIFFERENCES);+  if (force_flag) {+    console.log(c.bgRedBright(' Force altering schema. '));+    await helper.alter_schema(client);+  } else if (DIFFERENCES[1].length > 0) {+    await helper.alter_schema(client);+  }+}++const main = async () => {+  console.log(c.blueBright('\nDgraph schema CLI\n'));+  console.log('Please enter en action to continue:');+  console.log('1 - Get current dgraph schema.');+  console.log('2 - Diff output only.');+  console.log('3 - Alter dgraph schema with diff output.');+  rl.question('\nWhat to do next ? ', async toDo => {

The callback here should not be async, since the rejection will not be handled: You can here:

  • Use a sync function and handle the failure
  • Try catch
  • https://nodejs.org/api/process.html#process_event_unhandledrejection
Sceat

comment created time in a month

pull request commentHydreIO/dgraph-schema

WIP: feature/cli

Why all your local variables are UPERCASE ?

Sceat

comment created time in a month

startedrefactoringui/heroicons

started time in a month

startedaristocratos/bashtop

started time in a month

created repositoryDeltaEvo/stackdiagram

created time in a month

startedpacketcraft-inc/cordio

started time in a month

startedrmoral45/PPS

started time in a month

startedHenriChataing/n64

started time in a month

push eventHydreIO/hydre.io

David Duarte

commit sha 4c6baafec2e26161aa032d7c9732f53926a290c3

remove setTimeout

view details

push time in a month

startedpmiddend/nixos-manager

started time in a month

push eventHydreIO/graphql-http

David Duarte

commit sha 2ec821509a6ae5a5076a4f79c4c15cfb8a2a3c63

create LICENSE

view details

push time in a month

push eventHydreIO/graphql-http

David Duarte

commit sha 6bf5ea4f2d7571e9c9b038bc11e32bf4a3accd26

Create LICENSE

view details

push time in a month

push eventHydreIO/graphql-http

push time in a month

push eventHydreIO/graphql-http

Duarte David

commit sha abb783dc2b5ffbd33c0bfac73c757086b8e0153c

add validation

view details

Duarte David

commit sha dfab2ef09fa126a8ad02027e92c680040acd113d

remove useless graphql-tools, thanks @Sceat

view details

push time in a month

delete branch HydreIO/graphql-http

delete branch : feature/readme

delete time in a month

push eventHydreIO/graphql-http

Sceat

commit sha 82155ea9fb46c44b59857ad2ce00a337a7676197

add readme

view details

push time in a month

PR merged HydreIO/graphql-http

Reviewers
add readme
+11 -0

0 comment

1 changed file

Sceat

pr closed time in a month

push eventHydreIO/graphql-http

Duarte David

commit sha 6fe7556afbf67157df38ff800fecd6ffc987d192

basic support of subscriptions

view details

push time in a month

push eventHydreIO/graphql-http

Duarte David

commit sha ffa6704972c20e3eea0e41ab02ca50b58d9219ce

simple koa implementation

view details

push time in a month

more