Analyze relation between entities

@param currentSchema
@throws @throws
IOException
327732
private void analyzeRelations(SQLiteDatabaseSchema schema) {
		// resolve child entity
		for (SQLiteEntity entity : schema.getEntities()) {
			// if there is not relations, go on
			if (entity.relations.size() == 0)
				continue;

			for (Touple<SQLProperty, String, SQLiteEntity, SQLRelationType> item : entity.relations) {
				TypeName typeName = TypeUtility.typeName(item.value0.getElement());

				if (TypeUtility.isSet(typeName) || TypeUtility.isList(typeName)) {
					// ASSERT: list, set of type
					AssertKripton.assertTrueOfInvalidDefinition(
							((ParameterizedTypeName) typeName).typeArguments.size() == 1, item.value0, String.format(
									"invalid type for @%s annotated element", BindSqlRelation.class.getSimpleName()));

					typeName = ((ParameterizedTypeName) typeName).typeArguments.get(0);

					SQLiteEntity referredEntity = schema.getEntity(typeName.toString());

					checkForeignKeyContraint(entity, item, referredEntity);

					item.value2 = referredEntity;
					item.value3 = SQLRelationType.ONE_2_MANY;
				} else {
					SQLiteEntity referredEntity = schema.getEntity(typeName.toString());

					checkForeignKeyContraint(entity, item, referredEntity);

					item.value2 = referredEntity;
					item.value3 = SQLRelationType.ONE_2_ONE;
				}

				// get dao definition for entity
				SQLiteDaoDefinition parentDaoDefinition = schema.findDaoDefinitionForEntity(entity);

				for (final SQLiteModelMethod method : parentDaoDefinition.getCollection()) {
					if (method.hasChildrenSelects()) {
						// Pair<relation name, method name>
						for (Triple<String, String, SQLiteModelMethod> childrenSelect : method.childrenSelects) {
							final Touple<SQLProperty, String, SQLiteEntity, SQLRelationType> relation = entity
									.findRelationByParentProperty(childrenSelect.value0);

							AssertKripton.assertTrueOrInvalidMethodSignException(relation != null, method,
									" property '%s#%s' does not exits (referred by annotation @%s(%s='%s', %s='%s'))",
									entity.getSimpleName(), childrenSelect.value0,
									BindSqlChildSelect.class.getSimpleName(), AnnotationAttributeType.FIELD.getValue(),
									childrenSelect.value0, AnnotationAttributeType.METHOD.getValue(),
									childrenSelect.value1);

							final SQLiteDaoDefinition childDaoDefinition = schema
									.findDaoDefinitionForEntity(relation.value2);
							AssertKripton.assertTrueOrInvalidMethodSignException(childDaoDefinition != null, method,
									" dao for entity '%s', referred by @%s annotation, does not exists",
									relation.value2, BindSqlChildSelect.class.getSimpleName());

							final SQLiteModelMethod subMethod = childDaoDefinition.get(childrenSelect.value1);

							AssertKripton.assertTrueOrInvalidMethodSignException(subMethod != null, method,
									" method '%s#%s', referred by @%s annotation, does not exists",
									childDaoDefinition.getElement().getSimpleName().toString(), childrenSelect.value1,
									BindSqlChildSelect.class.getSimpleName());

							AssertKripton.assertTrueOrInvalidMethodSignException(subMethod.getParameters().size() == 1,
									method,
									" method '%s#%s', referred by annotation @%s(%s='%s', %s='%s'), can have only one parameter",
									childDaoDefinition.getTypeName(), subMethod.getName(),
									BindSqlChildSelect.class.getSimpleName(), AnnotationAttributeType.FIELD.getValue(),
									childrenSelect.value0, AnnotationAttributeType.METHOD.getValue(),
									childrenSelect.value1);

							// set sub method to invoke
							childrenSelect.value2 = subMethod;

							final String defaultConditionToTest1 = relation.value1 + "=" + SqlAnalyzer.PARAM_PREFIX
									+ subMethod.findParameterAliasByName(subMethod.getParameters().get(0).value0)
									+ SqlAnalyzer.PARAM_SUFFIX;
							final String defaultConditionToTest2 = SqlAnalyzer.PARAM_PREFIX
									+ subMethod.findParameterAliasByName(subMethod.getParameters().get(0).value0)
									+ SqlAnalyzer.PARAM_SUFFIX + "=" + relation.value1;

							final Set<String> conditionToTest = new HashSet<String>();
							String[] prefix = { "${", ":{", ":" };
							String[] suffix = { "}", "}", "" };

							for (int i = 0; i < prefix.length; i++) {
								final String conditionToTest1 = relation.value1 + "=" + prefix[i]
										+ subMethod.findParameterAliasByName(subMethod.getParameters().get(0).value0)
										+ suffix[i];
								final String conditionToTest2 = prefix[i]
										+ subMethod.findParameterAliasByName(subMethod.getParameters().get(0).value0)
										+ suffix[i] + "=" + relation.value1;

								conditionToTest.add(conditionToTest1);
								conditionToTest.add(conditionToTest2);
							}

							JQLChecker.getInstance().analyze(subMethod, subMethod.jql, new JqlBaseListener() {

								@Override
								public void enterWhere_stmt_clauses(Where_stmt_clausesContext ctx) {
									boolean found = false;

									for (String item : conditionToTest) {
										if (ctx.getText().contains(item)) {
											found = true;
										}
									}

									AssertKripton.assertTrueOrInvalidMethodSignException(found, method,
											" method '%s#%s' referred by @%s annotation must have a where condition like '%s' or '%s'",
											childDaoDefinition.getTypeName(), subMethod.getName(),
											BindSqlChildSelect.class.getSimpleName(), defaultConditionToTest1,
											defaultConditionToTest2);
								}

							});

							AssertKripton.assertTrueOrInvalidMethodSignException(
									TypeUtility.isEquals(subMethod.getParameters().get(0).value1,
											entity.getPrimaryKey().getPropertyType().getTypeName()),
									method,
									" method '%s#%s' referred by annotation @%s(%s='%s', %s='%s') has invalid parameter type ",
									childDaoDefinition.getTypeName(), subMethod.getName(),
									BindSqlChildSelect.class.getSimpleName(), AnnotationAttributeType.FIELD.getValue(),
									childrenSelect.value0, AnnotationAttributeType.METHOD.getValue(),
									childrenSelect.value1);

							TypeName parentFieldTypeName = relation.value0.getPropertyType().getTypeName();
							AssertKripton.assertTrueOrInvalidMethodSignException(

									(parentFieldTypeName.equals(subMethod.getReturnClass())
											|| (TypeUtility.isList(parentFieldTypeName) == TypeUtility
													.isList(subMethod.getReturnClass()))
													&& (TypeUtility.isSet(parentFieldTypeName) == TypeUtility
															.isSet(subMethod.getReturnClass()))),
									method, "field '%s#%s' is incompatible with '%s#%s' referred by @%s annotation ",
									TypeUtility.typeName(relation.value0.getParent().getElement()).toString(),
									relation.value0.getName(), childDaoDefinition.getTypeName(), childrenSelect.value1,
									BindSqlChildSelect.class.getSimpleName());

							// check existence of method
							AssertKripton.assertTrueOrInvalidMethodSignException(subMethod != null, method,
									"an nonexistent method '%s#%s' is referred by @%s annotation ",
									childDaoDefinition.getTypeName(), relation.value1,
									BindSqlChildSelect.class.getSimpleName());

							// check signature
							AssertKripton.assertTrueOrInvalidMethodSignException(subMethod.getParameters().size() == 1,
									method,
									" method '%s#%s' referred by @%s annotation can have one parameter binded to %s property",
									childDaoDefinition.getTypeName(), relation.value1,
									BindSqlChildSelect.class.getSimpleName(), relation.value1);

							// check parameter type
							AssertKripton.assertTrueOrInvalidMethodSignException(
									TypeUtility.isTypeIncludedIn(subMethod.getParameters().get(0).value1, Long.TYPE,
											Long.class, String.class),
									method,
									" method '%s#%s' referred by @%s annotation can have only one parameter of type String, Long or long",
									childDaoDefinition.getTypeName(), relation.value1,
									BindSqlChildSelect.class.getSimpleName(), relation.value1);

							SelectType selectSubMethodResultType = SelectBuilderUtility.detectSelectType(subMethod);
							// specified dao can only return bean of a type
							// TypeName returnTypeName =
							// method.getReturnClass();

							switch (relation.value3) {
							case ONE_2_MANY:
								// we can have a set or a list
								AssertKripton.assertTrueOrInvalidMethodSignException(
										selectSubMethodResultType == SelectType.LIST_BEAN, method,
										" method '%s#%s' referred by @%s annotation does not return an acceptable value from '%s' property",
										childDaoDefinition.getTypeName(), relation.value1,
										BindSqlChildSelect.class.getSimpleName(), relation.value1);
								break;
							case ONE_2_ONE:
								// we can receive only a bean
								AssertKripton.assertTrueOrInvalidMethodSignException(
										selectSubMethodResultType == SelectType.BEAN, method,
										" method '%s#%s' referred by @%s annotation does not return an acceptable value from '%s' property",
										childDaoDefinition.getTypeName(), relation.value1,
										BindSqlChildSelect.class.getSimpleName(), relation.value1);
								break;
							}

						}
					}
				}

			}
		}
	}
994372
private void parseRelations(String persistenceUnit, List<TableInfo> tableInfos, EntityMetadata entityMetadata,
            TableInfo tableInfo, List<Relation> relations)
    {
        for (Relation relation : relations)
        {
            if (relation != null)
            {
                Class entityClass = relation.getTargetEntity();
                EntityMetadata targetEntityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                        entityClass);
                if (targetEntityMetadata == null)
                {
                    log.error("Persistence unit for class : " + entityClass + " is not loaded");
                    throw new SchemaGenerationException(
                            "Persistence unit for class : " + entityClass + " is not loaded");
                }
                ForeignKey relationType = relation.getType();

                // if relation type is one to many or join by primary key
                if (targetEntityMetadata != null && relationType.equals(ForeignKey.ONE_TO_MANY)
                        && relation.getJoinColumnName(kunderaMetadata) != null)
                {
                    // if self association
                    if (targetEntityMetadata.equals(entityMetadata))
                    {
                        tableInfo.addColumnInfo(getJoinColumn(tableInfo, relation.getJoinColumnName(kunderaMetadata),
                                entityMetadata.getIdAttribute().getJavaType()));
                    }
                    else
                    {
                        String pu = targetEntityMetadata.getPersistenceUnit();
                        Type targetEntityType = targetEntityMetadata.getType();
                        Class idClass = targetEntityMetadata.getIdAttribute().getJavaType();
                        String idName = ((AbstractAttribute) targetEntityMetadata.getIdAttribute()).getJPAColumnName();
                        TableInfo targetTableInfo = new TableInfo(targetEntityMetadata.getTableName(),
                                targetEntityType.name(), idClass, idName);

                        // In case of different persistence unit. case for poly
                        // glot
                        // persistence.
                        if (!pu.equals(persistenceUnit))
                        {
                            List<TableInfo> targetTableInfos = getSchemaInfo(pu);

                            addJoinColumnToInfo(relation.getJoinColumnName(kunderaMetadata), targetTableInfo,
                                    targetTableInfos, entityMetadata);

                            // add for newly discovered persistence unit.
                            puToSchemaMetadata.put(pu, targetTableInfos);
                        }
                        else
                        {
                            addJoinColumnToInfo(relation.getJoinColumnName(kunderaMetadata), targetTableInfo,
                                    tableInfos, entityMetadata);
                        }
                    }
                }
                // if relation type is one to one or many to one.
                else if (relation.isUnary() && relation.getJoinColumnName(kunderaMetadata) != null)
                {
                    if (!relation.isJoinedByPrimaryKey())
                    {
                        tableInfo.addColumnInfo(getJoinColumn(tableInfo, relation.getJoinColumnName(kunderaMetadata),
                                targetEntityMetadata.getIdAttribute().getJavaType()));
                    }
                }
                // if relation type is many to many and relation via join table.
                else if ((relationType.equals(ForeignKey.MANY_TO_MANY)) && (entityMetadata.isRelationViaJoinTable()))
                {
                    JoinTableMetadata joinTableMetadata = relation.getJoinTableMetadata();
                    String joinTableName = joinTableMetadata != null ? joinTableMetadata.getJoinTableName() : null;
                    String joinColumnName = joinTableMetadata != null
                            ? (String) joinTableMetadata.getJoinColumns().toArray()[0] : null;
                    String inverseJoinColumnName = joinTableMetadata != null
                            ? (String) joinTableMetadata.getInverseJoinColumns().toArray()[0] : null;
                    if (joinTableName != null)
                    {
                        TableInfo joinTableInfo = new TableInfo(joinTableName, Type.COLUMN_FAMILY.name(), String.class,
                                "key");
                        if (!tableInfos.isEmpty() && !tableInfos.contains(joinTableInfo) || tableInfos.isEmpty())
                        {
                            joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo, joinColumnName,
                                    entityMetadata.getIdAttribute().getJavaType()));
                            joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo, inverseJoinColumnName,
                                    targetEntityMetadata.getIdAttribute().getJavaType()));

                            // // Do not delete above lines. Currently join
                            // table
                            // columns are of type string only.
                            // // It needs to be fixed later.
                            // joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo,
                            // joinColumnName, String.class));
                            // joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo,
                            // inverseJoinColumnName, String.class));

                            tableInfos.add(joinTableInfo);
                        }
                    }
                }
            }
        }
    }
16580
void resolveColumnIndexesUsingSchema(NodeSchema inputSchema) {
        // get all the TVEs in the output columns
        int difftor = 0;
        for (SchemaColumn col : m_outputSchema) {
            col.setDifferentiator(difftor);
            ++difftor;
            Collection<TupleValueExpression> allTves =
                    ExpressionUtil.getTupleValueExpressions(col.getExpression());
            // and update their indexes against the table schema
            for (TupleValueExpression tve : allTves) {
                tve.setColumnIndexUsingSchema(inputSchema);
                assert (tve.getColumnIndex() >= 0 && tve.getColumnIndex() < inputSchema.size());
            }
        }
        // DON'T RE-SORT HERE
    }
642703
private void populateCollectionFromJoinTable(Object entity, EntityMetadata entityMetadata,
            PersistenceDelegator delegator, Relation relation)
    {
        JoinTableMetadata jtMetadata = relation.getJoinTableMetadata();
        Client pClient = delegator.getClient(entityMetadata);

        String schema = entityMetadata.getSchema();

        EntityMetadata owningEntityMetadata = KunderaMetadataManager.getEntityMetadata(delegator.getKunderaMetadata(),
                relation.getTargetEntity());
        Class columnJavaType = owningEntityMetadata.getIdAttribute().getJavaType();
        if (jtMetadata == null)
        {
            columnJavaType = entityMetadata.getIdAttribute().getJavaType();
            Relation owningEntityMetadataRelation = owningEntityMetadata.getRelation(relation.getMappedBy());
            jtMetadata = owningEntityMetadataRelation.getJoinTableMetadata();
            pClient = delegator.getClient(owningEntityMetadata);
            schema = owningEntityMetadata.getSchema();
        }

        String joinTableName = jtMetadata.getJoinTableName();

        Set<String> joinColumns = jtMetadata.getJoinColumns();
        Set<String> inverseJoinColumns = jtMetadata.getInverseJoinColumns();

        String joinColumnName = (String) joinColumns.toArray()[0];
        String inverseJoinColumnName = (String) inverseJoinColumns.toArray()[0];

        Object entityId = PropertyAccessorHelper.getId(entity, entityMetadata);
        List<?> foreignKeys = pClient.getColumnsById(schema, joinTableName, joinColumnName, inverseJoinColumnName,
                entityId, columnJavaType);

        List childrenEntities = new ArrayList();

        if (foreignKeys != null)
        {
            for (Object foreignKey : foreignKeys)
            {
                EntityMetadata childMetadata = KunderaMetadataManager.getEntityMetadata(delegator.getKunderaMetadata(),
                        relation.getTargetEntity());

                Object child = delegator.find(relation.getTargetEntity(), foreignKey);
                Object obj = child instanceof EnhanceEntity && child != null ? ((EnhanceEntity) child).getEntity()
                        : child;

                // If child has any bidirectional relationship, process them
                // here
                Field biDirectionalField = relation.getBiDirectionalField();
                boolean isBidirectionalRelation = (biDirectionalField != null);

                if (isBidirectionalRelation && obj != null)
                {
                    Object columnValue = PropertyAccessorHelper.getId(obj, childMetadata);
                    Object[] pKeys = pClient.findIdsByColumn(entityMetadata.getSchema(), joinTableName, joinColumnName,
                            inverseJoinColumnName, columnValue, entityMetadata.getEntityClazz());
                    List parents = delegator.find(entity.getClass(), pKeys);
                    PropertyAccessorHelper.set(obj, biDirectionalField,
                            ObjectUtils.getFieldInstance(parents, biDirectionalField));
                    PersistenceCacheManager.addEntityToPersistenceCache(obj, delegator, columnValue);
                }

                childrenEntities.add(obj);
            }
        }
        Field childField = relation.getProperty();

        try
        {
            PropertyAccessorHelper.set(
                    entity,
                    childField,
                    PropertyAccessorHelper.isCollection(childField.getType()) ? ObjectUtils.getFieldInstance(
                            childrenEntities, childField) : childrenEntities.get(0));
            PersistenceCacheManager.addEntityToPersistenceCache(entity, delegator, entityId);
        }
        catch (PropertyAccessException ex)
        {
            throw new EntityReaderException(ex);
        }
    }
121673
void populateRelationForM2M(Object entity, EntityMetadata entityMetadata, PersistenceDelegator delegator,
            Relation relation, Object relObject, Map<String, Object> relationsMap)
    {
        // For M-M relationship of Collection type, relationship entities are
        // always fetched from Join Table.
        if (relation.getPropertyType().isAssignableFrom(List.class)
                || relation.getPropertyType().isAssignableFrom(Set.class))
        {
            if (relation.isRelatedViaJoinTable() && (relObject == null || ProxyHelper.isProxyOrCollection(relObject)))
            {
                populateCollectionFromJoinTable(entity, entityMetadata, delegator, relation);
            }

        }
        else if (relation.getPropertyType().isAssignableFrom(Map.class))
        {
            if (relation.isRelatedViaJoinTable())
            {
                // TODO: Implement Map relationships via Join Table (not
                // supported as of now)
            }
            else
            {
                populateCollectionFromMap(entity, delegator, relation, relObject, relationsMap);
            }
        }
    }
1270361
private static void analyzeNode(TreeGraphNode t, TreeGraphNode root, Collection<GrammaticalRelation> relations) {
    // if (t.numChildren() > 0) {          // don't do leaves
    if (t.isPhrasal()) {    // don't do leaves or preterminals!
      TreeGraphNode tHigh = t.highestNodeWithSameHead();
      for (GrammaticalRelation egr : relations) {
        if (egr.isApplicable(t)) {
          for (Tree u : egr.getRelatedNodes(t, root)) {
            tHigh.addArc(GrammaticalRelation.getAnnotationClass(egr), (TreeGraphNode) u);
          }
        }
      }
      // now recurse into children
      for (TreeGraphNode kid : t.children()) {
        analyzeNode(kid, root, relations);
      }
    }
  }
1191502
function defineRelationshipResolution(
  schema: GraphQLSchema,
  relationships: Relationship[],
  database: DatabaseInterface,
): void {
  relationships.forEach(relationship => {
    defineFieldResolve(
      schema,
      relationship.path[0].fromType,
      relationship.fieldName,
      database.generateRelationshipResolver(relationship),
    );
  });
}
1366977
protected void setSchema(final String schema) throws DatabaseEngineException {
        try {
            this.conn.setSchema(schema);
        } catch (final Exception e) {
            throw new DatabaseEngineException(String.format("Could not set current schema to '%s'", schema), e);
        }
    }
139162
private void analyzeForeignKey(SQLiteDatabaseSchema schema) {
		for (SQLiteEntity entity : schema.getEntities()) {
			for (SQLProperty property : entity.getCollection()) {
				if (property.isForeignKey()) {
					SQLiteEntity reference = schema.getEntity(property.foreignParentClassName);

					AssertKripton.asserTrueOrUnspecifiedBeanException(reference != null, schema, entity,
							property.foreignParentClassName);

					if (!entity.equals(reference)) {
						entity.referedEntities.add(reference);
					}
				}

			}
		}

		for (SQLiteDaoDefinition dao : schema.getCollection()) {
			if (dao.getElement().getAnnotation(BindDaoMany2Many.class) != null) {
				ClassName entity1 = TypeUtility.className(AnnotationUtility.extractAsClassName(dao.getElement(),
						BindDaoMany2Many.class, AnnotationAttributeType.ENTITY_1));
				ClassName entity2 = TypeUtility.className(AnnotationUtility.extractAsClassName(dao.getElement(),
						BindDaoMany2Many.class, AnnotationAttributeType.ENTITY_2));

				// only if dao has an entity
				if (dao.getEntity() != null) {
					// check foreign key to entity1 and entity2
					checkForeignKeyForM2M(schema, dao.getEntity(), entity1);
					checkForeignKeyForM2M(schema, dao.getEntity(), entity2);
				}
			}
		}
	}
644063
@Override
    public NonExceptionPostdominatorsAnalysis analyze(IAnalysisCache analysisCache, MethodDescriptor descriptor)
            throws CheckedAnalysisException {
        CFG cfg = getCFG(analysisCache, descriptor);
        ReverseDepthFirstSearch rdfs = getReverseDepthFirstSearch(analysisCache, descriptor);
        NonExceptionPostdominatorsAnalysis analysis = new NonExceptionPostdominatorsAnalysis(cfg, rdfs, getDepthFirstSearch(
                analysisCache, descriptor));
        Dataflow<java.util.BitSet, PostDominatorsAnalysis> dataflow = new Dataflow<>(cfg,
                analysis);
        dataflow.execute();
        return analysis;
    }
1194369
@Override
    public StoreDataflow analyze(IAnalysisCache analysisCache, MethodDescriptor descriptor) throws CheckedAnalysisException {
        MethodGen methodGen = getMethodGen(analysisCache, descriptor);
        if (methodGen == null) {
            return null;
        }
        StoreAnalysis analysis = new StoreAnalysis(getDepthFirstSearch(analysisCache, descriptor), getConstantPoolGen(
                analysisCache, descriptor.getClassDescriptor()));
        StoreDataflow dataflow = new StoreDataflow(getCFG(analysisCache, descriptor), analysis);
        dataflow.execute();
        return dataflow;
    }
928754
private void setRelationToEntity(Object entity, Object relationEntity, Relation relation)
    {
        if (relation.getTargetEntity().isAssignableFrom(getEntity(relationEntity).getClass()))
        {

            if (relation.isUnary())
            {
                PropertyAccessorHelper.set(entity, relation.getProperty(), getEntity(relationEntity));
            }
            else
            {
                Object associationObject = PropertyAccessorHelper.getObject(entity, relation.getProperty());
                if (associationObject == null || ProxyHelper.isProxyOrCollection(associationObject))
                {
                    associationObject = PropertyAccessorHelper.getCollectionInstance(relation.getProperty());
                    PropertyAccessorHelper.set(entity, relation.getProperty(), associationObject);
                }

                ((Collection) associationObject).add(getEntity(relationEntity));
            }
        }
    }
1230664
function includeSchema(mReferencedScope) {
			var oElement,
				sKey;

			if (!(sSchema in mReferencedScope)) {
				fnLog(WARNING, sUrl, " does not contain ", sSchema);
				return;
			}

			fnLog(DEBUG, "Including ", sSchema, " from ", sUrl);
			for (sKey in mReferencedScope) {
				// $EntityContainer can be ignored; $Reference, $Version is handled above
				if (sKey[0] !== "$" && schema(sKey) === sSchema) {
					oElement = mReferencedScope[sKey];
					mScope[sKey] = oElement;
					mergeAnnotations(oElement, mScope.$Annotations);
				}
			}
		}
87181
public void computeOrphan(Collection<Address> currentMembers) {
      if (!currentMembers.contains(getGlobalTransaction().getAddress())) {
         if (trace) log.tracef("This transaction's originator has left the cluster: %s", getGlobalTransaction());
         isOrphan = true;
      }
   }
1006630
@Override
  public String getSchema() throws IOException {
    try {
      return this.kafkaSchemaRegistry.getLatestSchemaByTopic(this.topicName);
    } catch (SchemaRegistryException e) {
      throw new RuntimeException(e);
    }
  }
1068070
static TableSchema parseTableSchema(String tableSchemaJson) throws IOException {
    JsonParser parser = JacksonFactory.getDefaultInstance().createJsonParser(tableSchemaJson);
    return parser.parseAndClose(TableSchema.class);
  }
412530
private boolean isRelational(EntityMetadata m)
    {
        // if related via join table OR contains relations.
        return m.isRelationViaJoinTable() || (m.getRelationNames() != null && (!m.getRelationNames().isEmpty()));
    }