2018-05-07 17:41:22 +09:00
// see https://github.com/apollographql/graphql-tools/blob/master/docs/source/schema-directives.md#marking-strings-for-internationalization
2018-05-08 12:23:42 +09:00
import { addGraphQLDirective , addGraphQLSchema } from '../modules/graphql' ;
2018-05-07 17:41:22 +09:00
import { SchemaDirectiveVisitor } from 'graphql-tools' ;
import { defaultFieldResolver } from 'graphql' ;
2018-05-09 10:38:21 +09:00
import { Collections } from '../modules/collections' ;
2018-05-10 18:00:37 +09:00
import { getSetting } from '../modules/settings' ;
2018-05-09 10:38:21 +09:00
import Vulcan from '../modules/config' ;
2018-05-21 10:02:43 +09:00
import { isIntlField } from '../modules/intl' ;
2018-05-09 10:38:21 +09:00
import { Connectors } from './connectors' ;
import pickBy from 'lodash/pickBy' ;
2018-05-07 17:41:22 +09:00
2018-05-21 10:02:43 +09:00
/ *
Create GraphQL types
* /
2018-05-21 09:42:08 +09:00
const intlValueSchemas =
` type IntlValue {
locale : String
value : String
}
input IntlValueInput {
locale : String
value : String
} ` ;
addGraphQLSchema ( intlValueSchemas ) ;
2018-05-21 10:02:43 +09:00
/ *
Take an array of translations , a locale , and a default locale , and return a matching string
* /
const getLocaleString = ( translations , locale , defaultLocale ) => {
const localeObject = translations . find ( translation => translation . locale === locale ) ;
const defaultLocaleObject = translations . find ( translation => translation . locale === defaultLocale ) ;
return localeObject && localeObject . value || defaultLocaleObject && defaultLocaleObject . value ;
} ;
/ *
GraphQL @ intl directive resolver
* /
2018-05-07 17:41:22 +09:00
class IntlDirective extends SchemaDirectiveVisitor {
visitFieldDefinition ( field , details ) {
2018-05-21 09:42:08 +09:00
const { resolve = defaultFieldResolver , name } = field ;
2018-05-07 17:41:22 +09:00
field . resolve = async function ( ... args ) {
2018-05-21 09:42:08 +09:00
const [ doc , graphQLArguments , context ] = args ;
2018-05-07 17:41:22 +09:00
const fieldValue = await resolve . apply ( this , args ) ;
const locale = graphQLArguments . locale || context . locale ;
2018-05-10 18:00:37 +09:00
const defaultLocale = getSetting ( 'locale' ) ;
2018-05-21 09:42:08 +09:00
const intlField = doc [ ` ${ name } _intl ` ] ;
// Return string in requested or default language, or else field's original value
return intlField && getLocaleString ( intlField , locale , defaultLocale ) || fieldValue ;
2018-05-07 17:41:22 +09:00
} ;
}
}
addGraphQLDirective ( { intl : IntlDirective } ) ;
2018-09-12 11:59:00 +09:00
addGraphQLSchema ( 'directive @intl on FIELD_DEFINITION' ) ;
2018-05-09 10:38:21 +09:00
2018-05-21 10:02:43 +09:00
/ *
Migration function
* /
2018-05-09 10:38:21 +09:00
const migrateIntlFields = async ( defaultLocale ) => {
if ( ! defaultLocale ) {
2018-09-12 11:59:00 +09:00
throw new Error ( 'Please pass the id of the locale to which to migrate your current content (e.g. migrateIntlFields(\'en\'))' ) ;
2018-05-09 10:38:21 +09:00
}
Collections . forEach ( async collection => {
const schema = collection . simpleSchema ( ) . _schema ;
const intlFields = pickBy ( schema , isIntlField ) ;
const intlFieldsNames = Object . keys ( intlFields ) ;
2018-05-21 09:42:08 +09:00
2018-05-09 10:38:21 +09:00
if ( intlFieldsNames . length ) {
2018-05-09 11:22:19 +09:00
console . log ( ` ### Found ${ intlFieldsNames . length } field to migrate for collection ${ collection . options . collectionName } : ${ intlFieldsNames . join ( ', ' ) } ### \n ` ) ; // eslint-disable-line no-console
2018-05-09 10:38:21 +09:00
2018-06-30 11:34:17 +02:00
// const intlFieldsWithLocale = intlFieldsNames.map(f => `${f}_intl`);
2018-05-09 10:38:21 +09:00
// find all documents with one or more unmigrated intl fields
2018-05-22 08:43:27 +09:00
const selector = {
$or : intlFieldsNames . map ( f => {
return { $and : [
{ [ ` ${ f } ` ] : { $exists : true } } ,
{ [ ` ${ f } _intl ` ] : { $exists : false } }
] } ;
} )
} ;
2018-05-09 10:38:21 +09:00
const documentsToMigrate = await Connectors . find ( collection , selector ) ;
if ( documentsToMigrate . length ) {
2018-05-09 11:22:19 +09:00
console . log ( ` -> found ${ documentsToMigrate . length } documents to migrate \n ` ) ; // eslint-disable-line no-console
2018-08-21 17:48:06 +09:00
for ( const doc of documentsToMigrate ) {
2018-05-09 11:22:19 +09:00
console . log ( ` // Migrating document ${ doc . _id } ` ) ; // eslint-disable-line no-console
2018-05-21 09:42:08 +09:00
const modifier = { $push : { } } ;
2018-05-09 10:38:21 +09:00
intlFieldsNames . forEach ( f => {
2018-05-21 09:42:08 +09:00
if ( doc [ f ] && ! doc [ ` ${ f } _intl ` ] ) {
2018-05-22 08:43:27 +09:00
const translationObject = { locale : defaultLocale , value : doc [ f ] } ;
2018-05-21 09:42:08 +09:00
console . log ( ` -> Adding field ${ f } _intl: ${ JSON . stringify ( translationObject ) } ` ) ; // eslint-disable-line no-console
modifier . $push [ ` ${ f } _intl ` ] = translationObject ;
2018-05-09 10:38:21 +09:00
}
} ) ;
2018-05-22 08:43:27 +09:00
if ( ! _ . isEmpty ( modifier . $push ) ) {
// update document
2018-09-12 11:59:00 +09:00
// eslint-disable-next-line no-await-in-loop
2018-08-21 17:48:06 +09:00
const n = await Connectors . update ( collection , { _id : doc . _id } , modifier ) ;
2018-05-22 08:43:27 +09:00
console . log ( ` -> migrated ${ n } documents \n ` ) ; // eslint-disable-line no-console
}
2018-05-09 11:22:19 +09:00
console . log ( '\n' ) ; // eslint-disable-line no-console
2018-05-09 10:38:21 +09:00
2018-08-21 17:48:06 +09:00
}
2018-05-22 08:43:27 +09:00
} else {
2018-09-12 11:59:00 +09:00
console . log ( '-> found no documents to migrate.' ) ; // eslint-disable-line no-console
2018-05-09 10:38:21 +09:00
}
}
} ) ;
}
2018-05-21 09:42:08 +09:00
Vulcan . migrateIntlFields = migrateIntlFields ;