private bool TryCreateUserDefinedType(string argType, out Type mappedArgType)
        {
            bool isArray       = argType.StartsWith("_");
            var  pgTypeName    = argType.TrimStart('_');
            var  udtAttributes = connection.Query(SqlHelper.LoadSql("QueryUdtAttributes.sql"), new { typname = pgTypeName }).ToList();

            mappedArgType = null;
            if (udtAttributes.Any())
            {
                var typeName    = $"{nameSpace}.{cxInfo.GetTypeName(pgTypeName)}";
                var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);

                foreach (var attr in udtAttributes)
                {
                    var attrName     = cxInfo.GetColumnName((string)attr.AttributeName);
                    var attrTypeData = DbTypeData.FromString(attr.AttributeType);
                    var attrType     = SqlHelper.MapDbTypeToType(attrTypeData.DbType, attrTypeData.UdtName, false, true);
                    if (attrType == null)
                    {
                        throw new InvalidOperationException("Unknown type: " + attr.AttributeType);
                    }

                    typeBuilder.DefineField(attrName, attrType, FieldAttributes.Public);
                }

                var udt = typeBuilder.CreateType();

                if (isArray)
                {
                    mappedArgType = udt.MakeArrayType();
                }
                else
                {
                    mappedArgType = typeBuilder.CreateType();
                }

                return(true);
            }

            return(false);
        }
        private static TableData PrepareTableEntity(IConnectionInfo cxInfo, ModuleBuilder moduleBuilder, IDbConnection dbConnection, string nameSpace, string databaseName, string tableSchema, string tableName, ExplorerItem tableExplorerItem)
        {
            // get primary key columns
            var primaryKeyColumns = dbConnection.GetPrimaryKeyColumns(tableSchema, tableName);

            var typeName = $"{nameSpace}.{tableSchema}.{cxInfo.GetTypeName(tableName)}";

            // ToDo make sure tablename can be used
            var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public, typeof(Entity));

            // add the table attribute to the class
            typeBuilder.AddTableAttribute($"\"{tableSchema}\".\"{tableName}\"");

            var query = SqlHelper.LoadSql("QueryColumns.sql");
            var propertyAndFieldNames = new HashSet <string>();

            var columns = dbConnection.Query(query, new { DatabaseName = databaseName, TableSchema = tableSchema, TableName = tableName });

            foreach (var column in columns)
            {
                var columnName         = cxInfo.GetColumnName((string)column.ColumnName);
                var isPrimaryKeyColumn = primaryKeyColumns.Contains((string)column.ColumnName); // always use the unmodified column name
                var columnDefault      = (string)column.ColumnDefault;

                // always make primary key columns nullable (otherwise auto increment can't be used with an insert)
                var fieldType = (Type)SqlHelper.MapDbTypeToType(column.DataType, column.UdtName, "YES".Equals(column.Nullable, StringComparison.InvariantCultureIgnoreCase), cxInfo.UseAdvancedTypes());

                string text;

                if (fieldType != null)
                {
                    // ToDo make sure name can be used
                    var fieldBuilder = typeBuilder.DefineField(columnName, fieldType, FieldAttributes.Public);
                    fieldBuilder.AddColumnAttribute((string)column.ColumnName); // always use the unmodified column name

                    if (isPrimaryKeyColumn)
                    {
                        // check if the column is an identity column
                        if (!string.IsNullOrEmpty(columnDefault) && columnDefault.ToLower().StartsWith("nextval"))
                        {
                            fieldBuilder.AddIdentityAttribute();
                        }

                        fieldBuilder.AddPrimaryKeyAttribute();
                    }

                    text = $"{columnName} ({fieldType.GetTypeName()})";
                    propertyAndFieldNames.Add(columnName);
                }
                else
                {
                    // field type is not mapped
                    text = $"{columnName} (unsupported - {column.DataType})";
                }

                var explorerItem = new ExplorerItem(text, ExplorerItemKind.Property, ExplorerIcon.Column)
                {
                    SqlTypeDeclaration = column.DataType,
                    DragText           = columnName
                };

                tableExplorerItem.Children.Add(explorerItem);
            }

            return(new TableData(tableName, tableExplorerItem, typeBuilder, propertyAndFieldNames));
        }
      private static TableData PrepareTableEntity(IConnectionInfo cxInfo, ModuleBuilder moduleBuilder, IDbConnection dbConnection, string nameSpace, string databaseName, string tableName, ExplorerItem tableExplorerItem)
      {
         // get primary key columns
         var primaryKeyColumns = dbConnection.GetPrimaryKeyColumns(tableName);

         var typeName = $"{nameSpace}.{cxInfo.GetTypeName(tableName)}";

         // ToDo make sure tablename can be used
         var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public, typeof(Entity));

         // add the table attribute to the class
         typeBuilder.AddTableAttribute(tableName);

         var query = SqlHelper.LoadSql("QueryColumns.sql");
         var propertyAndFieldNames = new HashSet<string>();

         var columns = dbConnection.Query(query, new { DatabaseName = databaseName, TableName = tableName });
         foreach (var column in columns)
         {
            var columnName = cxInfo.GetColumnName((string)column.ColumnName);
            var isPrimaryKeyColumn = primaryKeyColumns.Contains((string)column.ColumnName); // always use the unmodified column name
            var columnDefault = (string)column.ColumnDefault;

            // always make primary key columns nullable (otherwise auto increment can't be used with an insert)
            var fieldType = (Type)SqlHelper.MapDbTypeToType(column.DataType, column.UdtName, "YES".Equals(column.Nullable, StringComparison.InvariantCultureIgnoreCase), cxInfo.UseAdvancedTypes());

            string text;

            if (fieldType != null)
            {
               // ToDo make sure name can be used
               var fieldBuilder = typeBuilder.DefineField(columnName, fieldType, FieldAttributes.Public);
               fieldBuilder.AddColumnAttribute((string)column.ColumnName); // always use the unmodified column name

               if (isPrimaryKeyColumn)
               {
                  // check if the column is an identity column
                  if (!string.IsNullOrEmpty(columnDefault) && columnDefault.ToLower().StartsWith("nextval"))
                  {
                     fieldBuilder.AddIdentityAttribute();
                  }

                  fieldBuilder.AddPrimaryKeyAttribute();
               }

               text = $"{columnName} ({fieldType.GetTypeName()})";
               propertyAndFieldNames.Add(columnName);
            }
            else
            {
               // field type is not mapped
               text = $"{columnName} (unsupported - {column.DataType})";
            }

            var explorerItem = new ExplorerItem(text, ExplorerItemKind.Property, ExplorerIcon.Column)
            {
               SqlTypeDeclaration = column.DataType,
               DragText = columnName
            };

            tableExplorerItem.Children.Add(explorerItem);
         }

         return new TableData(tableName, tableExplorerItem, typeBuilder, propertyAndFieldNames);
      }