<commit_before>import * as uuid from "uuid"

import * as Hub from "../../hub"
import { SegmentActionError } from "./segment_error"

const segment: any = require("analytics-node")

interface SegmentFields {
  idFieldNames: string[],
  idField: Hub.Field,
  userIdField: Hub.Field,
  groupIdField: Hub.Field,
  emailField: Hub.Field,
  anonymousIdField: Hub.Field,
}

export enum SegmentTags {
  UserId = "user_id",
  SegmentAnonymousId = "segment_anonymous_id",
  Email = "email",
  SegmentGroupId = "segment_group_id",
}

export enum SegmentCalls {
  Identify = "identify",
  Track = "track",
  Group = "group",
}

export class SegmentAction extends Hub.Action {

  allowedTags = [SegmentTags.Email, SegmentTags.UserId, SegmentTags.SegmentAnonymousId]

  name = "segment_event"
  label = "Segment Identify"
  iconName = "segment/segment.png"
  description = "Add traits via identify to your Segment users."
  params = [
    {
      description: "A write key for Segment.",
      label: "Segment Write Key",
      name: "segment_write_key",
      required: true,
      sensitive: true,
    },
  ]
  minimumSupportedLookerVersion = "4.20.0"
  supportedActionTypes = [Hub.ActionType.Query]
  usesStreaming = true
  supportedFormats = [Hub.ActionFormat.JsonDetail]
  supportedFormattings = [Hub.ActionFormatting.Unformatted]
  supportedVisualizationFormattings = [Hub.ActionVisualizationFormatting.Noapply]
  requiredFields = [{ any_tag: this.allowedTags }]

  async execute(request: Hub.ActionRequest) {
    return this.executeSegment(request, SegmentCalls.Identify)
  }

  protected async executeSegment(request: Hub.ActionRequest, segmentCall: SegmentCalls) {
    const segmentClient = this.segmentClientFromRequest(request)

    let hiddenFields: string[] = []
    if (request.scheduledPlan &&
        request.scheduledPlan.query &&
        request.scheduledPlan.query.vis_config &&
        request.scheduledPlan.query.vis_config.hidden_fields) {
      hiddenFields = request.scheduledPlan.query.vis_config.hidden_fields
    }

    let segmentFields: SegmentFields | undefined
    let fieldset: Hub.Field[] = []
    const errors: Error[] = []

    let timestamp = new Date()
    const context = {
      app: {
        name: "looker/actions",
        version: process.env.APP_VERSION || "dev",
      },
    }
    const event = request.formParams.event

    try {

      await request.streamJsonDetail({
        onFields: (fields) => {
          fieldset = Hub.allFields(fields)
          segmentFields = this.segmentFields(fieldset)
          this.unassignedSegmentFieldsCheck(segmentFields)
        },
        onRanAt: (iso8601string) => {
          if (iso8601string) {
            timestamp = new Date(iso8601string)
          }
        },
        onRow: (row) => {
          this.unassignedSegmentFieldsCheck(segmentFields)
          const payload = {
            ...this.prepareSegmentTraitsFromRow(
              row, fieldset, segmentFields!, hiddenFields, segmentCall === SegmentCalls.Track),
            ...{event, context, timestamp},
          }
          if (payload.groupId === null) {
            delete payload.groupId
          }
          if (!payload.event) {
            delete payload.event
          }
          try {
            segmentClient[segmentCall](payload)
          } catch (e) {
            errors.push(e)
          }
        },
      })

      await segmentClient.flush(async (err: any) => {
        return new Promise<any>((resolve, reject) => {
          if (err) {
            reject(err)
          } else {
            resolve()
          }
        })
      })
    } catch (e) {
      errors.push(e)
    }

    if (errors) {
      return new Hub.ActionResponse({
        success: false,
        message: errors.map((e) => e.message).join(", "),
      })
    } else {
      return new Hub.ActionResponse({ success: true })<commit_msg>try to capture better error info for segment (#169)<commit_after>import * as uuid from "uuid"

import * as Hub from "../../hub"
import { SegmentActionError } from "./segment_error"

const segment: any = require("analytics-node")

interface SegmentFields {
  idFieldNames: string[],
  idField: Hub.Field,
  userIdField: Hub.Field,
  groupIdField: Hub.Field,
  emailField: Hub.Field,
  anonymousIdField: Hub.Field,
}

export enum SegmentTags {
  UserId = "user_id",
  SegmentAnonymousId = "segment_anonymous_id",
  Email = "email",
  SegmentGroupId = "segment_group_id",
}

export enum SegmentCalls {
  Identify = "identify",
  Track = "track",
  Group = "group",
}

export class SegmentAction extends Hub.Action {

  allowedTags = [SegmentTags.Email, SegmentTags.UserId, SegmentTags.SegmentAnonymousId]

  name = "segment_event"
  label = "Segment Identify"
  iconName = "segment/segment.png"
  description = "Add traits via identify to your Segment users."
  params = [
    {
      description: "A write key for Segment.",
      label: "Segment Write Key",
      name: "segment_write_key",
      required: true,
      sensitive: true,
    },
  ]
  minimumSupportedLookerVersion = "4.20.0"
  supportedActionTypes = [Hub.ActionType.Query]
  usesStreaming = true
  supportedFormats = [Hub.ActionFormat.JsonDetail]
  supportedFormattings = [Hub.ActionFormatting.Unformatted]
  supportedVisualizationFormattings = [Hub.ActionVisualizationFormatting.Noapply]
  requiredFields = [{ any_tag: this.allowedTags }]

  async execute(request: Hub.ActionRequest) {
    return this.executeSegment(request, SegmentCalls.Identify)
  }

  protected async executeSegment(request: Hub.ActionRequest, segmentCall: SegmentCalls) {
    const segmentClient = this.segmentClientFromRequest(request)

    let hiddenFields: string[] = []
    if (request.scheduledPlan &&
        request.scheduledPlan.query &&
        request.scheduledPlan.query.vis_config &&
        request.scheduledPlan.query.vis_config.hidden_fields) {
      hiddenFields = request.scheduledPlan.query.vis_config.hidden_fields
    }

    let segmentFields: SegmentFields | undefined
    let fieldset: Hub.Field[] = []
    const errors: Error[] = []

    let timestamp = new Date()
    const context = {
      app: {
        name: "looker/actions",
        version: process.env.APP_VERSION || "dev",
      },
    }
    const event = request.formParams.event

    try {

      await request.streamJsonDetail({
        onFields: (fields) => {
          fieldset = Hub.allFields(fields)
          segmentFields = this.segmentFields(fieldset)
          this.unassignedSegmentFieldsCheck(segmentFields)
        },
        onRanAt: (iso8601string) => {
          if (iso8601string) {
            timestamp = new Date(iso8601string)
          }
        },
        onRow: (row) => {
          this.unassignedSegmentFieldsCheck(segmentFields)
          const payload = {
            ...this.prepareSegmentTraitsFromRow(
              row, fieldset, segmentFields!, hiddenFields, segmentCall === SegmentCalls.Track),
            ...{event, context, timestamp},
          }
          if (payload.groupId === null) {
            delete payload.groupId
          }
          if (!payload.event) {
            delete payload.event
          }
          try {
            segmentClient[segmentCall](payload)
          } catch (e) {
            errors.push(e)
          }
        },
      })

      await segmentClient.flush(async (err: any) => {
        return new Promise<any>((resolve, reject) => {
          if (err) {
            reject(err)
          } else {
            resolve()
          }
        })
      })
    } catch (e) {
      errors.push(e)
    }

    if (errors) {
      return new Hub.ActionResponse({
        success: false,
        message: errors.map((e) => e.message || e).join(", "),
      })
    } else {
      return new Hub.ActionResponse({ success: true })
{'fraction_non_alphanumeric': 0.11271044852846678, 'fraction_numerical': 0.004498136486312814, 'mean_word_length': 2.513318284424379, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4644784', 'n_tokens_mistral': 2284, 'n_tokens_neox': 2245, 'n_words': 483}