Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions Resources/Controller/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@


require ('json-bigint-patch')
import { ApolloError, UserInputError } from 'apollo-server-express'


class Controller {


constructor ( Data, Fields, Schema ) {

this.Data = Data
this.Fields = Fields
this.Model = Schema

}


async Create ( Exception = 'Excepcion en el guardado de datos' ) {

try {

return await this.Model(this.Data).save()

} catch ({ message: m }) {

throw await new ApolloError ( m || Exception )

}

}


async FindOne ( Filter, Excepcion = 'Excepcion en la consulta' ) {

try {

return await this.Model.findOne(JSON.parse(JSON.stringify(Filter)))

} catch ({ message: m }) {

throw new ApolloError ( m || Excepcion )

}

}


async Find ( Limit = 1, OffSet, Excepcion = 'Excepcion en la consulta' ) {

try {

return await this.Model.find(this.Data && JSON.parse(JSON.stringify(this.Data)), this.Fields).limit(Limit).skip(OffSet)

} catch ({ message: m }) {

throw new ApolloError ( m || Excepcion )

}

}


async FindOneAndUpdateBy ( Filter, Exception = 'Excepcion en la actualizacion del dato', UpSert ) {

try {

await this.Model.updateOne(JSON.parse(JSON.stringify(Filter)), this.Data, { upsert: UpSert, runValidators: true })

console.log(await this.FindOne(Object.assign(Filter, this.Data)))

return await this.FindOne(Object.assign(Filter, this.Data)) || new UserInputError (Exception)

} catch ({ message: m }) {

throw await new ApolloError ( m || Exception )

}

}


async FindOneAndRemove ( Filter, Exception = 'Excepcion en la eliminacion del dato' ) {

try {

return await this.Model.findOneAndRemove(JSON.parse(JSON.stringify(Filter))) || new UserInputError ('El elemento a eleminar no se encontro')

} catch ({ message: m }) {

throw await new ApolloError ( m || Exception )

}

}


}


export { Controller }

16 changes: 16 additions & 0 deletions Resources/Database/Schema/Category.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


import { Schema, model } from 'mongoose'

require ('dotenv').config()

const { Category } = process.env, { ObjectId } = Schema.Types

export default model ( Category, new Schema ({

Name: { type: String, unique: true, trim: true, maxlength: 20, required: true },

Image: { type: String, trim: true, maxlength: 100, required: true },

}, { timestamps: true, versionKey: false }), Category )

22 changes: 22 additions & 0 deletions Resources/Database/Schema/Product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@


import { Schema, model } from 'mongoose'

require ('dotenv').config()

const { Product, Category } = process.env, { ObjectId } = Schema.Types

export default model ( Product, new Schema ({

Name: { type: String, unique: true, trim: true, maxlength: 20, required: true },

Price: { type: Number, min: 1, required: true },

Description: { type: String, trim: true, maxlength: 40 },

CategoryID: { type: ObjectId, trim: true, ref: Category, required: true },

Image: { type: String, trim: true, maxlength: 100, required: true },

}, { timestamps: true, versionKey: false }), Product )

10 changes: 10 additions & 0 deletions Resources/Database/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@


import Category from './Schema/Category'


import Product from './Schema/Product'


export { Category, Product }

80 changes: 80 additions & 0 deletions Resources/Schema/Resolvers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@


require ('dotenv').config()
import { hash, compare } from 'bcryptjs'
import { sign, verify } from 'jsonwebtoken'
import { Controller as C } from '../../Controller'

import { UserInputError, AuthenticationError } from 'apollo-server-express'


import { Category, Product } from '../../Database'


import {
ObjectIDResolver as ObjectID,
TimestampResolver as Timestamp,
DateResolver as Date,
BigIntResolver as BigInt,
NonEmptyStringResolver as NonEmptyString,
EmailAddressResolver as EmailAddress,
PositiveIntResolver as PositiveInt,
PositiveFloatResolver as PositiveFloat
} from 'graphql-scalars'


const ExecuteCategory = (Data, Fields) => new C ( Data, Fields, Category ),
ExecuteProduct = (Data, Fields) => new C ( Data, Fields, Product )


export default {


Query: {

_: async () => await true,

// Categoria

getCategory: async (_, { ID: _id }) => await ExecuteCategory().FindOne({ _id }),
getCategories: async (_, { Query: { Limit, OffSet } = { } }) => await ExecuteCategory().Find(Limit, OffSet),

// Producto

getProduct: async (_, { ID: _id }) => await ExecuteProduct().FindOne({ _id }),
getProducts: async (_, { Query: { Limit, OffSet } = { } }) => await ExecuteProduct().Find(Limit, OffSet),

},


Mutation: {

_: async () => await true,

// Producto

createProduct: async (_, { Producto: { Name, Price, Description, CategoryID, Image } = { } }) => await ExecuteProduct({ Name, Price, Description, CategoryID, Image }).Create(),

updateProduct: async (_, { ID: _id, Producto: { Name, Price, Description, CategoryID, Image } = { } }) => await ExecuteProduct({ Name, Price, Description, CategoryID, Image }).FindOneAndUpdateBy({ _id: _id.trim() }),

deleteProduct: async (_, { ID: _id }) => await ExecuteProduct().FindOneAndRemove({ _id: _id.trim() }),

// Categoria

createCategory: async (_, { Categoria: { Name, Image } = { } }) => await ExecuteCategory({ Name, Image }).Create(),

updateCategory: async (_, { ID: _id, Categoria: { Name, Image } = { } }) => await ExecuteCategory({ Name, Image }).FindOneAndUpdateBy({ _id: _id.trim() }),

deleteCategory: async (_, { ID: _id }) => await ExecuteCategory().FindOneAndRemove({ _id: _id.trim() })

},


Producto: { CategoryID: async ({ CategoryID: _id }) => await ExecuteCategory().FindOne({ _id }) },


ObjectID, Date, Timestamp, BigInt, NonEmptyString, EmailAddress, PositiveInt, PositiveFloat


}

104 changes: 104 additions & 0 deletions Resources/Schema/Typedefs.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@


type Query {


"Verifica si el servidor reponde"
_: Boolean!

getProduct (ID: ObjectID!): Producto
getProducts (Query: QueryInput!): [ Producto ]

getCategory (ID: ObjectID!): Categoria
getCategories (Query: QueryInput!): [ Categoria ]

}


type Mutation {


"Verifica si las modificaciones responden"
_: Boolean!

createProduct (Producto: ProductInput!): Producto
updateProduct (ID: ObjectID! Producto: ProductOptionalInput!): Producto
deleteProduct (ID: ObjectID!): Producto

createCategory (Categoria: CategoryInput!): Categoria
updateCategory (ID: ObjectID! Categoria: CategoryInput!): Categoria
deleteCategory (ID: ObjectID!): Categoria


}


scalar ObjectID scalar Timestamp scalar Date scalar BigInt scalar NonEmptyString scalar EmailAddress scalar PositiveInt scalar PositiveFloat


input QueryInput {

Limit: PositiveInt!
OffSet: PositiveInt

}


type Producto {

id: ObjectID!
Name: NonEmptyString!
Price: PositiveFloat!
Description: NonEmptyString
CategoryID: Categoria
Image: NonEmptyString!

}


input ProductInput {

Name: NonEmptyString!
Price: PositiveFloat!
Description: NonEmptyString
CategoryID: ObjectID!
Image: NonEmptyString!

}


input ProductOptionalInput {

Name: NonEmptyString
Price: PositiveFloat
Description: NonEmptyString
CategoryID: ObjectID
Image: NonEmptyString

}


type Categoria {

id: ObjectID!
Name: NonEmptyString!
Image: NonEmptyString!

}


input CategoryInput {

Name: NonEmptyString!
Image: NonEmptyString!

}


input CategoryOptionalInput {

Name: NonEmptyString
Image: NonEmptyString

}

52 changes: 52 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


import express from 'express'

import { ApolloServer } from 'apollo-server-express'

import { loadSchemaSync } from '@graphql-tools/load'

import { addResolversToSchema } from '@graphql-tools/schema'

import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'

import { composeResolvers } from '@graphql-tools/resolvers-composition'

// import Contrains from './Resources/Schema/Resolvers/Constraints'

import resolvers from './Resources/Schema/Resolvers'


const { error } = require ('dotenv').config(), { connect, set } = require ('mongoose'),
app = express(), { PORT, MONGO_HOST, MONGO_PORT, MONGO_DB_NAME } = process.env,
server = new ApolloServer({ schema: addResolversToSchema({ schema: loadSchemaSync(`${ __dirname }/Resources/Schema/Typedefs.graphql`, { loaders: [ new GraphQLFileLoader() ] }), resolvers: composeResolvers(resolvers /* Contrains */ ) }), context: async ({ req: { headers: { auth: Auth } = { Auth: undefined } } }) => await ({ Auth }), tracing: true })


app.disable('x-powered-by')


server.applyMiddleware({ app })


app.listen({ port: PORT }, async () => {

try {

if (error)
throw await new Error ('Excepcion importando las variables de entorno')

set('useCreateIndex', true)

const MongoAddress = `mongodb://${ MONGO_HOST }:${ MONGO_PORT }/${ MONGO_DB_NAME }`

await connect(MongoAddress, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false }, async e => await console.log(`${ !e ? 'Conectado a mongo' : 'Excepcion en la conexion de mongo' }\n${ MongoAddress }\nServidor iniciado en localhost:${ PORT + server.graphqlPath }`) )


} catch (E) {

await console.log(E)

}

})

Loading