原型GraphQL,MongoDB-少架构吗?

时间:2018-09-04 18:35:04

标签: mongodb postgresql graphql

我正在研究数据繁重的应用程序的原型。我有SQL经验,但是由于缺少模式,我目前对MongoDB颇有好感,这对于原型来说将是理想的,因为它允许我在开发过程中扩展模式,直到一切都正确为止。而且我喜欢GraphQL的原因很多,其中之一就是我可以直接在API上进行很多测试和试验,而无需创建简单的UI。

但是,据我了解,GraphQL需要严格的架构定义。这意味着它不能与MongoDB一起使用,至少在保留无模式属性的情况下不会。

绝对要求是具有后端处理功能的能力。我需要能够触发数据计算,因此我需要某种方式针对数据库编写代码,理想情况下,是在用于API的同一框架中进行(当然,我总是可以编写一些以DB为中心的任意应用程序,但是为什么我应该这样做?使用两个框架?)

是对的还是我被误导了?是否有一个等效的Graphile for MongoDB,它允许我仅在一个地方定义我的架构(在原型开发期间会经常更改),并即时进行所有更新?还是我完全走错了路?

注意:

  • 这不是生产代码。它是原型代码,需要与各个涉众进行多次迭代才能正确使用。这就是为什么我需要可以快速开发和更改的东西的原因,如果可能的话,可以在那时和那里迅速测试替代方法。
  • 我需要非编码人员至少可以掌握的某种接口。 GraphQL查询语言足以满足此目的(利益相关者是技术人员,而不是编码人员)。纯SQL是有问题的,除此之外的任何事情都对编码太重要了。
  • 我不太在乎SQL或NoSQL甚至是Graph DB,也不在乎它们是否全部用PHP,Java,NodeJS或其他我可以理解和破解的东西(即不在Brainfuck中)编写。

1 个答案:

答案 0 :(得分:0)

const { graphql, buildSchema } = require('graphql');

const schema = buildSchema(`
type Query {
}

type SchemalessDoc {
    _id: ID!
    json: String!
    get(k:String!): SchemalessDoc!
}

type Mutation {
    # Authentication
    auth(name: String!, phrase: String!): SchemalessDoc!
    deauth: Boolean!

    # CRUD for all models
    create(type:String!, json:String!): SchemalessDoc!
    update(type:String!, _id:ID!, json:String!): SchemalessDoc!
    delete(type:String!, _id:ID!): SchemalessDoc!
}
`);

// NOTICE: the only difference between Query and Mutation is Parallel vs. Serial execution;
//         the labels are more presumptive than prescriptive.

class SchemalessDoc {
    constructor(o) {
        this.o = o;
    }

    _id() {
        return this.o._id;
    }

    json() {
        // TODO: could return 'null' but that isn't precise. 'undefined' is invalid JSON, but its no biggie,
        //     just check first: return 'undefined' === s ? undefined : JSON.parse(s);
        if (undefined === this.o) return 'undefined';
        return JSON.stringify(this.o);
    }

    get({k}, args, context, info) {
        // NOTICE: this would be perfect if an error didn't abort the query
        //     returning zero results, instead of partial results
        // if (undefined === this.o[k]) {
        //     throw Error(`key ${k} was undefined`);
        // }
        return new SchemalessDoc(this.o[k]);
    }
}

const root = {
    // authenticate
    auth: function ({ name, phrase }, args, context, info) {
        // throw Error(`whats up?`);
        return new SchemalessDoc({ _id: 'abcd-efgh-hij', a: { b: { c: 3 }}});
    },
    deauth(obj, args, context, info) {
        debugger;
    },

    // crud for all models
    create(obj, args, context, info) {
        debugger;
    },
    update(obj, args, context, info) {
        debugger;
    },
    delete(obj, args, context, info) {
        debugger;
    },
};

const query = async s =>
    graphql(schema, s, root);

describe('graphql', () => {
    it('works', async () => {
        const output = await query(`
        mutation {
            auth(
                name: "mike",
                phrase: "turkey"
            ) {
                _id,
                a: get(k:"a") { 
                    b: get(k:"b") {
                        x: get(k:"x") {
                            json
                        },                        
                        c: get(k:"c") {
                            json
                        }
                    } 
                }
            }
        }
        `);
        console.log(JSON.stringify(output)); // => 
            // {"data":{"auth":{"_id":"abcd-efgh-hij","a":{"b":{"x":{"json":"undefined"},"c":{"json":"\"hamster\""}}}}}}
        debugger;
    });
});

// obviously this method requires you to both
// insert data as a JSON string,
// and parse JSON at the very end
// but you can still reduce keys server-side using your get() query

// honestly this is how they should have made it
// and support should be first-class
// no type validation just run it and see
// and stop recursing once you resolve the first null
// and for parallel resolves with some null just return the partial results you have
// and include errors[] for the keys which were undefined

// one downside without that first-class support is 
// the json comes back double-escaped as json string inside json.

// the other downside is that it removes the ability to
// do dynamic lookups on foreign key references
// unless you define a specific string or data type for that.
// ie. if it finds a string 'TypeName#abcd-defgh' then it 
// could go lookup and attach that document

另请参阅(其他方法):

(我喜欢这一点,因为它提供了类型化的吸气剂,而不是像字符串一样的东西)

http://blog.riand.com/2017/03/schemaless-graphql.html

https://blog.hasura.io/working-with-schemaless-data-with-graphql-on-postgres-574a1ee2e87f/

https://github.com/hasura/graphql-engine/issues/403

更新

我最终实现了从头开始的极大简化。分享,希望其他人可以从中获得免费的灵感:

https://gist.github.com/ancmikesmullin/526b64b262561fb4ca1be824c2faec7f#file-test-sgql-alpha2-js-L63-L67