-
-
Notifications
You must be signed in to change notification settings - Fork 610
Description
Issue Description
PostGraphile v5 fails to generate GraphQL schema when database tables/views contain column names with non-ASCII characters (e.g., Chinese, Japanese, Korean characters), resulting in schema generation failure.
Error Message
TypeError: Object type 'TJcBmnfV' attempted to define a field with invalid name "期间".
Names must only contain [_a-zA-Z0-9] but "期间" does not.
at assertValidName (/node_modules/graphile-build/dist/makeNewBuild.js:373:27)
at fieldWithHooks (/node_modules/graphile-build/dist/newWithHooks/index.js:104:57)
at processAttribute (/node_modules/graphile-build-pg/dist/plugins/PgAttributesPlugin.js:111:39)
Environment
- PostGraphile Version: v5 (latest)
- Runtime: Bun v1.3.3
- Database: PostgreSQL
- OS: macOS
Steps to Reproduce
- Create a database view with non-ASCII column names:
CREATE VIEW t_jc_bmnf_v AS
SELECT
id,
"期间" as period, -- Chinese column name
name
FROM some_table;- Configure PostGraphile v5:
const preset: GraphileConfig.Preset = {
extends: [PostGraphileAmberPreset, PgSimplifyInflectionPreset],
pgServices: [
makePgService({
connectionString: DATABASE_URL,
schemas: ['public'],
}),
],
}- Start PostGraphile - schema generation fails
Expected Behavior
PostGraphile should be able to:
- Automatically skip fields with non-ASCII column names
- Transform non-ASCII column names into valid GraphQL field names
- Provide configuration/plugin options for users to customize handling
Actual Behavior
PostGraphile calls fieldWithHooks directly in PgAttributesPlugin.processAttribute, which invokes assertValidName to validate field names. This validation occurs before any user-defined hooks can intercept, making it impossible to handle via plugins.
Attempted Solutions
1. Using @omit Smart Tags (Failed)
COMMENT ON VIEW t_jc_bmnf_v IS '@omit';Result: v5 doesn't seem to support this or requires additional configuration
2. Using entityBehavior to Hide Resources (Failed)
schema: {
entityBehavior: {
pgResource: {
inferred(behavior: string, resource: any) {
if (SKIP_TABLES.includes(resource.name)) {
return `${behavior} -*`
}
return behavior
},
},
},
}Result: Only hides query fields, but types are still created and field name validation still fails
3. Using pgCodecAttribute Behavior (Failed)
pgCodecAttribute: {
inferred(behavior: string, entity: any) {
const attributeName = entity.attribute.name
if (/[^\x00-\x7F]/.test(attributeName)) {
return `${behavior} -*`
}
return behavior
},
}Result: Field name validation occurs before behavior checks
4. Using Schema Hooks (Failed)
hooks: {
GraphQLObjectType_fields(fields, build, context) {
// Attempt to return empty fields or filter fields
},
}Result: Hook executes after PgAttributesPlugin, validation has already failed
5. Using Inflection Override (Failed)
inflection: {
replace: {
attribute(previous, options, details) {
// Attempt to rename non-ASCII fields
},
},
}Result: Inflection executes after field name validation
6. Using Gather Hooks (Failed)
gather: {
hooks: {
pgCodecs_PgCodec(info, event) {
// Attempt to modify or skip codec
},
},
}Result: Cannot prevent type creation
Root Cause
In PostGraphile v5's architecture, field name validation occurs in the processAttribute function of PgAttributesPlugin:
// PgAttributesPlugin.js:111
const fieldName = inflection.attribute({ codec, attributeName, ... });
const field = fieldWithHooks({ // <- This calls assertValidName
fieldName,
...
});assertValidName is a mandatory requirement of the GraphQL specification that disallows non-ASCII characters. This validation occurs before any user-interceptable hooks.
Proposed Solutions
Solution A: Filter at Gather Stage (Recommended)
Filter out attributes with non-ASCII characters before PgAttributesPlugin processes them:
// In PgAttributesPlugin, before processAttribute
if (/[^\x00-\x7F]/.test(attributeName)) {
return; // Skip this attribute
}Solution B: Provide Configuration Options
Allow users to configure how to handle non-ASCII field names:
gather: {
pgNonAsciiFieldBehavior: 'skip' | 'sanitize' | 'error',
pgFieldNameSanitizer: (name: string) => string,
}Solution C: Support Smart Tags
Restore support for @omit and other smart tags in v5, or provide clear documentation on how to achieve the same functionality in v5.
Current Workaround
#!/usr/bin/env bun
import { readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
const PLUGIN_PATH = join(
process.cwd(),
'node_modules/graphile-build-pg/dist/plugins/PgAttributesPlugin.js'
)
const PATCH_MARKER = '// PATCHED: Skip non-ASCII attributes'
async function applyPatch() {
console.log('📦 Applying PostGraphile patch for non-ASCII field names...')
try {
let content = readFileSync(PLUGIN_PATH, 'utf-8')
if (content.includes(PATCH_MARKER)) {
console.log('✅ Patch already applied!')
return
}
// 找到 processAttribute 函数的开始
const searchPattern = 'function processAttribute(fields, build, context, attributeName, overrideName, isNotNull) {'
const insertAfterPattern = 'const { extend, inflection, dataplanPg: { pgSelectFromRecords, pgSelectSingleFromRecord }, } = build;'
if (!content.includes(searchPattern)) {
console.error('❌ Could not find processAttribute function!')
process.exit(1)
}
const patchCode = `
${PATCH_MARKER}
// Skip attributes with non-ASCII characters in their names
if (/[^\\x00-\\x7F]/.test(attributeName)) {
return;
}
`
content = content.replace(
insertAfterPattern,
insertAfterPattern + patchCode
)
writeFileSync(PLUGIN_PATH, content, 'utf-8')
console.log('✅ Patch applied successfully!')
console.log('📝 Modified file:', PLUGIN_PATH)
console.log('')
console.log('⚠️ Note: This patch will be lost when you reinstall node_modules.')
console.log(' Run this script again after reinstalling dependencies.')
} catch (error) {
console.error('❌ Error applying patch:', error)
process.exit(1)
}
}
applyPatch()
Impact
This issue affects all databases using non-English field names, including:
- Chinese
- Japanese
- Korean
- Arabic
- Russian
- Other non-ASCII character sets
Related Links
- GraphQL Specification - Naming Rules: https://spec.graphql.org/October2021/#sec-Names
- PostGraphile v5 Documentation: https://postgraphile.org/postgraphile/next/
- Related Issues: (if any)