Ejemplo n.º 1
0
        /// <summary>
        /// Given a set of <see cref="FieldDescription"/> and existing RecordInfo, create a new RecordInfo with specified fields replacing existing ones or being appended.
        /// </summary>
        /// <param name="inputRecordInfo">Existing RecordInfo object.</param>
        /// <param name="fields">Set of Field Descriptions.</param>
        /// <returns>A configured RecordInfo object.</returns>
        public static AlteryxRecordInfoNet.RecordInfo CreateRecordInfo(
            AlteryxRecordInfoNet.RecordInfo inputRecordInfo,
            params FieldDescription[] fields)
        {
            var fieldDict = fields.ToDictionary(f => f.Name, f => false);
            var output    = new AlteryxRecordInfoNet.RecordInfo();

            if (inputRecordInfo != null)
            {
                for (int i = 0; i < inputRecordInfo.NumFields(); i++)
                {
                    var fieldInfo = inputRecordInfo[i];
                    var fieldName = fieldInfo.GetFieldName();

                    if (fieldDict.ContainsKey(fieldName))
                    {
                        fieldDict[fieldName] = true;
                        var descr = fields.First(f => f.Name == fieldName);
                        output.AddField(descr.Name, descr.FieldType, descr.Size, descr.Scale, descr.Source, descr.Description);
                        continue;
                    }

                    output.AddField(fieldInfo);
                }
            }

            foreach (var descr in fields.Where(d => !fieldDict[d.Name]))
            {
                output.AddField(descr.Name, descr.FieldType, descr.Size, descr.Scale, descr.Source, descr.Description);
            }

            return(output);
        }
Ejemplo n.º 2
0
        public static AlteryxRecordInfoNet.RecordInfo GetRecordInfo(XmlDocument xml, string elementName)
        {
            // This function will locate the first element with the specified elementName in the
            // provided XML document.  It will then create a RecordInfo object that contains a field
            // for each element within that element.

            // Create the RecordInfo object to be returned.
            AlteryxRecordInfoNet.RecordInfo recordInfo = new AlteryxRecordInfoNet.RecordInfo();

            // Get all elements with the specified element name.
            XmlNodeList nodes = xml.GetElementsByTagName(elementName);

            if (nodes.Count > 0)
            {
                // For each child node in the first found element...
                foreach (XmlNode child in nodes[0].ChildNodes)
                {
                    // ...add a field to the RecordInfo using the element's name aas the field name.
                    recordInfo.AddField(child.Name, AlteryxRecordInfoNet.FieldType.E_FT_String, 255, 0, "", "");
                }
            }

            return(recordInfo);
        }
Ejemplo n.º 3
0
        public bool PI_PushAllRecords(long nRecordLimit)
        {
            if (nRecordLimit < 0)
            {
                nRecordLimit = long.MaxValue;
            }
            var success = false;
            var connStr = $"Data Source={dataSource};Catalog={catalog}";

            var conn = new AdomdConnection(connStr);

            try
            {
                AdomdDataReader reader;
                conn.Open();
                engine.OutputMessage(toolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, "Connected to server, processing the query...");
                engine.OutputToolProgress(toolId, 0.05);
                output.UpdateProgress(0.05);

                var command = new AdomdCommand(mdx, conn);
                if (nRecordLimit == 0)
                {
                    reader = command.ExecuteReader(CommandBehavior.SchemaOnly);
                }
                else
                {
                    reader = command.ExecuteReader();
                }

                engine.OutputMessage(toolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, "Query finished executing, retrieving schema...");
                engine.OutputToolProgress(toolId, 0.50);
                output.UpdateProgress(0.50);

                var fields     = reader.GetSchemaTable();
                var outputInfo = new AlteryxRecordInfoNet.RecordInfo();

                foreach (DataRow field in fields.Rows)
                {
                    var fieldName = field[0].ToString();

                    outputInfo.AddField(fieldName, AlteryxRecordInfoNet.FieldType.E_FT_V_WString, 1073741823, 0, $"SSAS Input ({toolId})", "");
                }

                output.Init(outputInfo, "Output", null, config);
                engine.OutputMessage(toolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, "Prepared output schema, retrieving data...");
                engine.OutputToolProgress(toolId, 0.55);
                output.UpdateProgress(0.55);

                var record    = outputInfo.CreateRecord();
                int totalRead = 0;

                while (totalRead < nRecordLimit && reader.Read())
                {
                    record.Reset();
                    for (int i = 0; i < outputInfo.NumFields(); i++)
                    {
                        AlteryxRecordInfoNet.FieldBase fieldBase = outputInfo[i];

                        if (reader[i] == null)
                        {
                            fieldBase.SetNull(record);
                        }
                        else
                        {
                            fieldBase.SetFromString(record, reader[i].ToString());
                        }
                    }
                    output.PushRecord(record.GetRecord());

                    totalRead++;
                }

                reader.Close();
                reader.Dispose();

                engine.OutputMessage(toolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Complete, $"Data retrieval completed.  {totalRead} records output.");
                engine.OutputToolProgress(toolId, 1.00);
                output.UpdateProgress(1.00);
                success = true;
            }
            catch (Exception ex)
            {
                engine.OutputMessage(toolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Error, $"Error: {ex.Message}  Stack trace: {ex.StackTrace}");
                success = false;
            }
            finally
            {
                conn.Close();
                conn.Dispose();
            }

            output.Close();
            return(success);
        }
        // Called by Alteryx for an Input tool to request all of the records.
        public bool PI_PushAllRecords(long nRecordLimit)
        {
            // The nRecordLimit parameter specifies the maximum number of records that
            // should be provided, or -1 for unlimited.  If it is -1, set it to
            // long.MaxValue to make the processing easier later on.  Sometimes Alteryx
            // will call this function with a record limit of 0 just to get the output
            // record configuration.
            if (nRecordLimit < 0)
            {
                nRecordLimit = long.MaxValue;
            }

            m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, nRecordLimit.ToString());

            if (m_engineInterface.GetInitVar("UpdateOnly") == "True")
            {
                m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Complete, nRecordLimit.ToString());
            }
            else
            {
                // Get the configuration section out of the properties xml that was passed
                // into PI_Init() and use it to determine the xml file, container element,
                // and field configuration for our tool.

                XmlElement            configXml = m_xmlProperties.SelectSingleNode("Configuration") as XmlElement;
                XmlInputConfiguration xmlConfig = XmlInputConfiguration.LoadFromConfiguration(configXml);

                if (xmlConfig == null)
                {
                    throw new ApplicationException("Invalid configuration.  Ensure that the input file is set correctly.");
                }

                if (xmlConfig.Fields.Count == 0)
                {
                    throw new ApplicationException("There are no fields.  Make sure your container element is set properly.");
                }

                // Create a new RecordInfo object to describe our outgoing message records and
                // configure it based on the field information in our saved configuration.
                AlteryxRecordInfoNet.RecordInfo recordInfoOut = new AlteryxRecordInfoNet.RecordInfo();
                foreach (XmlInputField field in xmlConfig.Fields)
                {
                    // For each field in our configuration, add it to our RecordInfo object.
                    recordInfoOut.AddField(field.Name, field.FieldType, field.Size, field.Scale, "", "");
                }

                // Use the new RecordInfo object to initialize the PluginOutputConnectionHelper.
                // The PluginOutputConnectionHelper can't be used until this step is performed.
                m_outputHelper.Init(recordInfoOut, "Message Output", null, m_xmlProperties);

                // Create a Record object to hold the data for each outgoing message record.
                AlteryxRecordInfoNet.Record recordOut = recordInfoOut.CreateRecord();

                // Create a new RecordInfo object to describe our outgoing attachment records and
                // configure it based on the field information in our saved configuration.
                AlteryxRecordInfoNet.RecordInfo recordInfoOut_AttachmentPaths = new AlteryxRecordInfoNet.RecordInfo();

                // For each field in our configuration, add it to our RecordInfo object.
                recordInfoOut_AttachmentPaths.AddField("Id", AlteryxRecordInfoNet.FieldType.E_FT_String, 4000, 0, "", "");
                recordInfoOut_AttachmentPaths.AddField("AttachmentPath", AlteryxRecordInfoNet.FieldType.E_FT_String, 4000, 0, "", "");

                // Use the new RecordInfo object to initialize the PluginOutputConnectionHelper.
                // The PluginOutputConnectionHelper can't be used until this step is performed.
                m_attachmentOutputHelper.Init(recordInfoOut_AttachmentPaths, "Attachment Output", null, m_xmlProperties);

                // Create a Record object to hold the data for each outgoing attachment record.
                AlteryxRecordInfoNet.Record recordOut_AttachmentPaths = recordInfoOut_AttachmentPaths.CreateRecord();

                // Define the necessary PropertyDefinitionBase objects for each field in the XML configuration document.
                PropertyDefinitionBase[] propertyDefinitionBase = new PropertyDefinitionBase[xmlConfig.Fields.Count];

                for (int i = 0; i < xmlConfig.Fields.Count; i++)
                {
                    if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Calendar && typeof(AppointmentSchema).GetField(xmlConfig.Fields[i].Name) != null)
                    {
                        propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(AppointmentSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null);
                    }
                    else if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Inbox && typeof(EmailMessageSchema).GetField(xmlConfig.Fields[i].Name) != null)
                    {
                        propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(EmailMessageSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null);
                    }
                    else if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Tasks && typeof(TaskSchema).GetField(xmlConfig.Fields[i].Name) != null)
                    {
                        propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(TaskSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null);
                    }
                    else
                    {
                        propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(ItemSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null);
                    }
                }

                // Assign the configuration settings and field list to the OutlookEmail object.
                OutlookEmail email = new OutlookEmail()
                {
                    UserName = xmlConfig.UserName, Password = xmlConfig.Password, ExchangeServerVersion = xmlConfig.ExchangeVersion, UseManualServiceURL = xmlConfig.UseManualServiceURL, ServiceURL = xmlConfig.ServiceURL, UseDifferentMailbox = xmlConfig.UseDifferentMailbox, Mailbox = xmlConfig.Mailbox, Folder = (WellKnownFolderName)xmlConfig.Folder, IncludeRecurringEvents = xmlConfig.IncludeRecurringEvents, StartDate = xmlConfig.StartDate, EndDate = xmlConfig.EndDate, AttachmentPath = xmlConfig.AttachmentPath, QueryString = xmlConfig.QueryString, IncludeSubFolders = xmlConfig.IncludeSubFolders, SubFolderName = xmlConfig.SubFolderName, SkipRootFolder = xmlConfig.SkipRootFolder, UseUniqueFileName = xmlConfig.UseUniqueFileName, AttachmentFilter = xmlConfig.AttachmentFilter
                };
                email.Fields = new PropertySet(propertyDefinitionBase);

                // Get the list of items (this includes attachments if the Attachment field was selected for output).
                List <OItem> oItems = email.GetItems(nRecordLimit);

                // We will need to send status updates to Alteryx at regular intervals during
                // this process, so we'll do that based on an elapsed time.
                DateTime last = DateTime.Now;

                // We need to keep track of how many records we have processed.
                long nRecords = 0;

                // Process the data in each message object.
                foreach (var oItem in oItems)
                {
                    // If we've exceeded the record limit, stop processing.
                    if (nRecords >= nRecordLimit)
                    {
                        break;
                    }

                    // Reset our output record so we can reuse it.  This is better than
                    // creating a new Record in each iteration as these objects can get large.
                    recordOut.Reset();

                    // For each field, load the data from the corresponding element into the Record.
                    foreach (XmlInputField field in xmlConfig.Fields)
                    {
                        // Get the FieldBase from the RecordInfo for the field.
                        AlteryxRecordInfoNet.FieldBase fieldBase = recordInfoOut.GetFieldByName(field.Name, false);
                        if (fieldBase != null)
                        {
                            // Find the element within the container element that has the same name as the field.
                            var value = Convert.ToString(oItem.Item.GetType().GetProperty(field.Name).GetValue(oItem.Item, null));

                            if (value == null)
                            {
                                // If the field element doesn't exist, set the output field's value to null.
                                fieldBase.SetNull(recordOut);
                            }
                            else
                            {
                                // Otherwise, set the output field's value based on the element's inner text.
                                fieldBase.SetFromString(recordOut, value);
                            }
                        }
                    }

                    // Return message attachments if applicable.
                    if (!string.IsNullOrWhiteSpace(xmlConfig.AttachmentPath))
                    {
                        foreach (var attachment in oItem.Attachments)
                        {
                            // Reset our output record so we can reuse it.  This is better than
                            // creating a new Record in each iteration as these objects can get large.
                            recordOut_AttachmentPaths.Reset();

                            // Get the FieldBase from the RecordInfo for the ID field.
                            AlteryxRecordInfoNet.FieldBase fieldBase_ID = recordInfoOut_AttachmentPaths.GetFieldByName("ID", false);
                            if (fieldBase_ID != null)
                            {
                                fieldBase_ID.SetFromString(recordOut_AttachmentPaths, oItem.Item.Id.ToString());
                            }

                            // Get the FieldBase from the RecordInfo for the AttachmentPath field.
                            AlteryxRecordInfoNet.FieldBase fieldBase_AttachmentPath = recordInfoOut_AttachmentPaths.GetFieldByName("AttachmentPath", false);
                            if (fieldBase_AttachmentPath != null)
                            {
                                fieldBase_AttachmentPath.SetFromString(recordOut_AttachmentPaths, attachment.AttachmentPath);
                            }

                            // Send the record to the downstream tools through the PluginOutputConnectionHelper.
                            m_attachmentOutputHelper.PushRecord(recordOut_AttachmentPaths.GetRecord());
                        }
                    }

                    // Send the record to the downstream tools through the PluginOutputConnectionHelper.
                    m_outputHelper.PushRecord(recordOut.GetRecord());

                    // If at least 1 second has passed since we started or our last update, update progress.
                    if (DateTime.Now.Subtract(last).TotalSeconds >= 1)
                    {
                        // Determine the percent complete:  (Records Processed) / Min(RecordLimit, # of Container Elements)
                        double percentComplete = (double)nRecords / Math.Min(nRecordLimit, oItems.Count);

                        // Output the progress
                        if (m_engineInterface.OutputToolProgress(m_nToolId, percentComplete) != 0)
                        {
                            // If this returns anything but 0, then the user has canceled the operation.
                            throw new AlteryxRecordInfoNet.UserCanceledException();
                        }

                        // Have the PluginOutputConnectionHelper ask the downstream tools to update their progress.
                        m_outputHelper.UpdateProgress(percentComplete);

                        // Reset the timer.
                        last = DateTime.Now;
                    }

                    // Have the PluginOutputConnectionHelper update the record count display in Alteryx.
                    // The PluginOutputConnectionHelper will actually only do this if enough time and data has elapsed,
                    // so it's ok to call this in every iteration.
                    m_outputHelper.OutputRecordCount(false);

                    // Update our record count.
                    nRecords++;
                }

                // If we weren't just getting the output config, send a status message to Alterys that
                // will display the number of records that we output.
                if (nRecordLimit > 0)
                {
                    m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, nRecords.ToString() + " records read from " + xmlConfig.UserName);
                }


                // Tell Alteryx that we are done sending data so that it can close the connections to our plugin.
                m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Complete, "");
            }

            // Close our ouput connections.
            m_outputHelper.Close();
            m_attachmentOutputHelper.Close();

            // Return true to indicate that we successfully processed our data.
            return(true);
        }