graphile-build-pg
Advanced tools
Comparing version 0.1.0-alpha.34 to 0.1.0-alpha.35
@@ -77,30 +77,30 @@ "use strict"; | ||
if (attr.type.type === "c") { | ||
return { | ||
pgQuery: function pgQuery(queryBuilder) { | ||
// json_build_object | ||
/* | ||
queryBuilder.select( | ||
sql.identifier(queryBuilder.getTableAlias(), attr.name), | ||
alias | ||
); | ||
*/ | ||
var resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, ReturnType); | ||
var jsonBuildObject = (0, _queryFromResolveData2.default)(sql.identifier((0, _symbol2.default)()), // Ignore! | ||
sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
resolveData, { onlyJsonField: true }); | ||
queryBuilder.select(jsonBuildObject, alias); | ||
} | ||
}; | ||
} else { | ||
return { | ||
pgQuery: function pgQuery(queryBuilder) { | ||
queryBuilder.select(pgTweakFragmentForType(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)}`, attr.type), alias); | ||
} | ||
}; | ||
} | ||
return { | ||
pgQuery: function pgQuery(queryBuilder) { | ||
var getSelectValueForFieldAndType = function getSelectValueForFieldAndType(sqlFullName, type) { | ||
if (type.arrayItemType) { | ||
var ident = sql.identifier((0, _symbol2.default)()); | ||
return sql.fragment` | ||
( | ||
select json_agg(${getSelectValueForFieldAndType(ident, type.arrayItemType)}) | ||
from unnest(${sqlFullName}) as ${ident} | ||
) | ||
`; | ||
} else if (type.type === "c") { | ||
var resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, ReturnType); | ||
var jsonBuildObject = (0, _queryFromResolveData2.default)(sql.identifier((0, _symbol2.default)()), // Ignore! | ||
sqlFullName, resolveData, { onlyJsonField: true }); | ||
return jsonBuildObject; | ||
} else { | ||
return pgTweakFragmentForType(sqlFullName, type); | ||
} | ||
}; | ||
queryBuilder.select(getSelectValueForFieldAndType(sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
attr.type), alias); | ||
} | ||
}; | ||
}); | ||
return { | ||
description: attr.description, | ||
type: nullableIf(!attr.isNotNull, ReturnType), | ||
type: nullableIf(!attr.isNotNull && !attr.type.domainIsNotNull, ReturnType), | ||
resolve: function resolve(data, _args, _context, resolveInfo) { | ||
@@ -140,3 +140,3 @@ var alias = getAliasFromResolveInfo(resolveInfo); | ||
description: attr.description, | ||
type: nullableIf(isPgPatch || !attr.isNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeId(attr.typeId) || _graphql.GraphQLString) | ||
type: nullableIf(isPgPatch || !attr.isNotNull && !attr.type.domainIsNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeId(attr.typeId) || _graphql.GraphQLString) | ||
}); | ||
@@ -143,0 +143,0 @@ return memo; |
@@ -148,2 +148,9 @@ "use strict"; | ||
return pg2gql(val, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
if (!Array.isArray(val)) { | ||
throw new Error(`Expected array when converting PostgreSQL data into GraphQL; failing type: '${type.namespaceName}.${type.name}'`); | ||
} | ||
return val.map(function (v) { | ||
return pg2gql(v, type.arrayItemType); | ||
}); | ||
} else { | ||
@@ -161,2 +168,9 @@ return val; | ||
return gql2pg(val, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
if (!Array.isArray(val)) { | ||
throw new Error(`Expected array when converting GraphQL data into PostgreSQL data; failing type: '${type.namespaceName}.${type.name}' (type: ${type === null ? "null" : typeof type})`); | ||
} | ||
return sql.fragment`array[${sql.join(val.map(function (v) { | ||
return gql2pg(v, type.arrayItemType); | ||
}), ", ")}]::${sql.identifier(type.namespaceName)}.${sql.identifier(type.name)}`; | ||
} else { | ||
@@ -273,2 +287,10 @@ return sql.value(val); | ||
return pgTweakFragmentForType(fragment, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
var error = new Error("Internal graphile-build-pg error: should not attempt to tweak an array, please process array before tweaking (type: `${type.namespaceName}.${type.name}`)"); | ||
if (process.env.NODE_ENV === "test") { | ||
throw error; | ||
} | ||
// eslint-disable-next-line no-console | ||
console.error(error); | ||
return fragment; | ||
} else { | ||
@@ -275,0 +297,0 @@ return fragment; |
@@ -11,6 +11,2 @@ "use strict"; | ||
var _stringify = require("babel-runtime/core-js/json/stringify"); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _regenerator = require("babel-runtime/regenerator"); | ||
@@ -96,3 +92,3 @@ | ||
var isPgClassLike = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; | ||
var result, rows, fields, typeID, jsonTypeId, jsonbTypeId, mapValue, values; | ||
var selectionField, result, rows, firstRow, firstKey, values, convertFieldBack; | ||
return _regenerator2.default.wrap(function _callee2$(_context2) { | ||
@@ -117,3 +113,15 @@ while (1) { | ||
case 6: | ||
_context2.next = 8; | ||
/* | ||
* In this code we're converting the rows to a string representation within | ||
* PostgreSQL itself, then we can send it back into PostgreSQL and have it | ||
* re-interpret the results cleanly (using it's own serializer/parser | ||
* combination) so we should be fairly confident that it will work | ||
* correctly every time assuming none of the PostgreSQL types are broken. | ||
* | ||
* If you have a way to improve this, I'd love to see a PR - but please | ||
* make sure that the integration tests pass with your solution first as | ||
* there are a log of potential pitfalls! | ||
*/ | ||
selectionField = isPgClassLike ? sqlResultSourceAlias : _pgSql2.default.query`(${sqlResultSourceAlias}.${sqlResultSourceAlias})::${sqlTypeIdentifier}`; | ||
_context2.next = 9; | ||
return performQuery(pgClient, _pgSql2.default.query` | ||
@@ -123,39 +131,21 @@ with ${sqlResultSourceAlias} as ( | ||
) | ||
select ${isPgClassLike ? sqlResultSourceAlias : _pgSql2.default.query`${sqlResultSourceAlias}.${sqlResultSourceAlias}`}::${sqlTypeIdentifier} from ${sqlResultSourceAlias}`); | ||
select (${selectionField})::text from ${sqlResultSourceAlias}`); | ||
case 8: | ||
case 9: | ||
result = _context2.sent; | ||
rows = result.rows; | ||
firstRow = rows[0]; | ||
// TODO: we should be able to have `pg` not interpret the results as | ||
// objects and instead just return them as arrays - then we can just do | ||
// `row[0]`. PR welcome! | ||
/* | ||
* This is a bit of a hack. Basically `pg` likes to send us JSON parsed, | ||
* but doesn't like it when we send JSON back through without stringifying. | ||
* We're not really mapping back to GraphQL here so we shouldn't use | ||
* pg2gql. So we're just going to JSON.stringify the value if we don't | ||
* think that `pg` will be happy with it. | ||
* | ||
* The optimium solution would be to have the `pg` module not parse the | ||
* data at all and just send it through to us as a string which we can then | ||
* post straight back to postgres. There may be options to enable this - if | ||
* you find them then a pull request would be welcome! | ||
*/ | ||
rows = result.rows, fields = result.fields; | ||
typeID = String(fields[0].dataTypeID); | ||
jsonTypeId = "114"; | ||
jsonbTypeId = "3802"; | ||
mapValue = function mapValue(val) { | ||
if (val && (typeof val === "object" || typeID === jsonTypeId || typeID === jsonbTypeId)) { | ||
return (0, _stringify2.default)(val); | ||
} else { | ||
return val; | ||
} | ||
}; | ||
firstKey = firstRow && (0, _keys2.default)(firstRow)[0]; | ||
values = rows.map(function (row) { | ||
return mapValue(row[(0, _keys2.default)(row)[0]]); | ||
return row[firstKey]; | ||
}); | ||
convertFieldBack = isPgClassLike ? _pgSql2.default.query`(str::${sqlTypeIdentifier}).*` : _pgSql2.default.query`str::${sqlTypeIdentifier} as ${sqlResultSourceAlias}`; | ||
_context2.next = 17; | ||
return performQuery(pgClient, _pgSql2.default.query` | ||
with ${sqlResultSourceAlias} as ( | ||
select ${isPgClassLike ? _pgSql2.default.query`(str::${sqlTypeIdentifier}).*` : _pgSql2.default.query`str::${sqlTypeIdentifier} as ${sqlResultSourceAlias}`} | ||
select ${convertFieldBack} | ||
from unnest((${_pgSql2.default.value(values)})::text[]) str | ||
@@ -162,0 +152,0 @@ ) |
@@ -61,30 +61,30 @@ "use strict"; | ||
const { alias } = parsedResolveInfoFragment; | ||
if (attr.type.type === "c") { | ||
return { | ||
pgQuery: queryBuilder => { | ||
// json_build_object | ||
/* | ||
queryBuilder.select( | ||
sql.identifier(queryBuilder.getTableAlias(), attr.name), | ||
alias | ||
); | ||
*/ | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, ReturnType); | ||
const jsonBuildObject = (0, _queryFromResolveData2.default)(sql.identifier((0, _symbol2.default)()), // Ignore! | ||
sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
resolveData, { onlyJsonField: true }); | ||
queryBuilder.select(jsonBuildObject, alias); | ||
} | ||
}; | ||
} else { | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(pgTweakFragmentForType(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)}`, attr.type), alias); | ||
} | ||
}; | ||
} | ||
return { | ||
pgQuery: queryBuilder => { | ||
const getSelectValueForFieldAndType = (sqlFullName, type) => { | ||
if (type.arrayItemType) { | ||
const ident = sql.identifier((0, _symbol2.default)()); | ||
return sql.fragment` | ||
( | ||
select json_agg(${getSelectValueForFieldAndType(ident, type.arrayItemType)}) | ||
from unnest(${sqlFullName}) as ${ident} | ||
) | ||
`; | ||
} else if (type.type === "c") { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, ReturnType); | ||
const jsonBuildObject = (0, _queryFromResolveData2.default)(sql.identifier((0, _symbol2.default)()), // Ignore! | ||
sqlFullName, resolveData, { onlyJsonField: true }); | ||
return jsonBuildObject; | ||
} else { | ||
return pgTweakFragmentForType(sqlFullName, type); | ||
} | ||
}; | ||
queryBuilder.select(getSelectValueForFieldAndType(sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
attr.type), alias); | ||
} | ||
}; | ||
}); | ||
return { | ||
description: attr.description, | ||
type: nullableIf(!attr.isNotNull, ReturnType), | ||
type: nullableIf(!attr.isNotNull && !attr.type.domainIsNotNull, ReturnType), | ||
resolve: (data, _args, _context, resolveInfo) => { | ||
@@ -124,3 +124,3 @@ const alias = getAliasFromResolveInfo(resolveInfo); | ||
description: attr.description, | ||
type: nullableIf(isPgPatch || !attr.isNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeId(attr.typeId) || _graphql.GraphQLString) | ||
type: nullableIf(isPgPatch || !attr.isNotNull && !attr.type.domainIsNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeId(attr.typeId) || _graphql.GraphQLString) | ||
}); | ||
@@ -127,0 +127,0 @@ return memo; |
@@ -132,2 +132,7 @@ "use strict"; | ||
return pg2gql(val, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
if (!Array.isArray(val)) { | ||
throw new Error(`Expected array when converting PostgreSQL data into GraphQL; failing type: '${type.namespaceName}.${type.name}'`); | ||
} | ||
return val.map(v => pg2gql(v, type.arrayItemType)); | ||
} else { | ||
@@ -145,2 +150,7 @@ return val; | ||
return gql2pg(val, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
if (!Array.isArray(val)) { | ||
throw new Error(`Expected array when converting GraphQL data into PostgreSQL data; failing type: '${type.namespaceName}.${type.name}' (type: ${type === null ? "null" : typeof type})`); | ||
} | ||
return sql.fragment`array[${sql.join(val.map(v => gql2pg(v, type.arrayItemType)), ", ")}]::${sql.identifier(type.namespaceName)}.${sql.identifier(type.name)}`; | ||
} else { | ||
@@ -247,2 +257,10 @@ return sql.value(val); | ||
return pgTweakFragmentForType(fragment, type.domainBaseType); | ||
} else if (type.arrayItemType) { | ||
const error = new Error("Internal graphile-build-pg error: should not attempt to tweak an array, please process array before tweaking (type: `${type.namespaceName}.${type.name}`)"); | ||
if (process.env.NODE_ENV === "test") { | ||
throw error; | ||
} | ||
// eslint-disable-next-line no-console | ||
console.error(error); | ||
return fragment; | ||
} else { | ||
@@ -249,0 +267,0 @@ return fragment; |
@@ -11,6 +11,2 @@ "use strict"; | ||
var _stringify = require("babel-runtime/core-js/json/stringify"); | ||
var _stringify2 = _interopRequireDefault(_stringify); | ||
var _pgSql = require("pg-sql2"); | ||
@@ -73,2 +69,14 @@ | ||
} else { | ||
/* | ||
* In this code we're converting the rows to a string representation within | ||
* PostgreSQL itself, then we can send it back into PostgreSQL and have it | ||
* re-interpret the results cleanly (using it's own serializer/parser | ||
* combination) so we should be fairly confident that it will work | ||
* correctly every time assuming none of the PostgreSQL types are broken. | ||
* | ||
* If you have a way to improve this, I'd love to see a PR - but please | ||
* make sure that the integration tests pass with your solution first as | ||
* there are a log of potential pitfalls! | ||
*/ | ||
const selectionField = isPgClassLike ? sqlResultSourceAlias : _pgSql2.default.query`(${sqlResultSourceAlias}.${sqlResultSourceAlias})::${sqlTypeIdentifier}`; | ||
const result = await performQuery(pgClient, _pgSql2.default.query` | ||
@@ -78,30 +86,14 @@ with ${sqlResultSourceAlias} as ( | ||
) | ||
select ${isPgClassLike ? sqlResultSourceAlias : _pgSql2.default.query`${sqlResultSourceAlias}.${sqlResultSourceAlias}`}::${sqlTypeIdentifier} from ${sqlResultSourceAlias}`); | ||
/* | ||
* This is a bit of a hack. Basically `pg` likes to send us JSON parsed, | ||
* but doesn't like it when we send JSON back through without stringifying. | ||
* We're not really mapping back to GraphQL here so we shouldn't use | ||
* pg2gql. So we're just going to JSON.stringify the value if we don't | ||
* think that `pg` will be happy with it. | ||
* | ||
* The optimium solution would be to have the `pg` module not parse the | ||
* data at all and just send it through to us as a string which we can then | ||
* post straight back to postgres. There may be options to enable this - if | ||
* you find them then a pull request would be welcome! | ||
*/ | ||
const { rows, fields } = result; | ||
const typeID = String(fields[0].dataTypeID); | ||
const jsonTypeId = "114"; | ||
const jsonbTypeId = "3802"; | ||
const mapValue = val => { | ||
if (val && (typeof val === "object" || typeID === jsonTypeId || typeID === jsonbTypeId)) { | ||
return (0, _stringify2.default)(val); | ||
} else { | ||
return val; | ||
} | ||
}; | ||
const values = rows.map(row => mapValue(row[(0, _keys2.default)(row)[0]])); | ||
select (${selectionField})::text from ${sqlResultSourceAlias}`); | ||
const { rows } = result; | ||
const firstRow = rows[0]; | ||
// TODO: we should be able to have `pg` not interpret the results as | ||
// objects and instead just return them as arrays - then we can just do | ||
// `row[0]`. PR welcome! | ||
const firstKey = firstRow && (0, _keys2.default)(firstRow)[0]; | ||
const values = rows.map(row => row[firstKey]); | ||
const convertFieldBack = isPgClassLike ? _pgSql2.default.query`(str::${sqlTypeIdentifier}).*` : _pgSql2.default.query`str::${sqlTypeIdentifier} as ${sqlResultSourceAlias}`; | ||
return await performQuery(pgClient, _pgSql2.default.query` | ||
with ${sqlResultSourceAlias} as ( | ||
select ${isPgClassLike ? _pgSql2.default.query`(str::${sqlTypeIdentifier}).*` : _pgSql2.default.query`str::${sqlTypeIdentifier} as ${sqlResultSourceAlias}`} | ||
select ${convertFieldBack} | ||
from unnest((${_pgSql2.default.value(values)})::text[]) str | ||
@@ -108,0 +100,0 @@ ) |
{ | ||
"name": "graphile-build-pg", | ||
"version": "0.1.0-alpha.34", | ||
"version": "0.1.0-alpha.35", | ||
"description": "Build a GraphQL schema by reflection over a PostgreSQL schema. Easy to customize since it's built with plugins on graphile-build", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1443587
9995
8