1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use std::sync::Arc;

use alloy_primitives::Address;
use arrow::{
    array::{
        Array, ArrayRef, BooleanBuilder, StringBuilder, StructArray, UInt64Builder, UInt8Builder,
    },
    datatypes::{DataType, Field, Schema},
    error::ArrowError,
    record_batch::RecordBatch,
};
use brontes_types::db::address_metadata::AddressMetadata;
use itertools::Itertools;

use super::utils::{build_string_array, get_list_string_array, get_string_array};

pub fn address_metadata_to_record_batch(
    address_metadata: Vec<(Address, AddressMetadata)>,
) -> Result<RecordBatch, ArrowError> {
    let address_array = build_string_array(
        address_metadata
            .iter()
            .map(|am| am.0.to_string())
            .collect_vec(),
    );

    let entity_name_array = get_string_array(
        address_metadata
            .iter()
            .map(|am| am.1.entity_name.as_deref())
            .collect_vec(),
    );
    let nametag_array = get_string_array(
        address_metadata
            .iter()
            .map(|am| am.1.nametag.as_deref())
            .collect_vec(),
    );

    let labels_array =
        get_list_string_array(address_metadata.iter().map(|am| &am.1.labels).collect_vec());

    let address_type_array = get_string_array(
        address_metadata
            .iter()
            .map(|am| am.1.address_type.as_deref())
            .collect_vec(),
    );
    let ens_array = get_string_array(
        address_metadata
            .iter()
            .map(|am| am.1.ens.as_deref())
            .collect_vec(),
    );

    let contract_info_array =
        get_contract_info_array(address_metadata.iter().map(|am| &am.1).collect_vec());
    let socials_array = get_socials_array(address_metadata.iter().map(|am| &am.1).collect_vec());

    let schema = Schema::new(vec![
        Field::new("address", DataType::Utf8, false),
        Field::new("entity_name", DataType::Utf8, true),
        Field::new("nametag", DataType::Utf8, true),
        Field::new(
            "labels",
            DataType::List(Arc::new(Field::new("item", DataType::Utf8, true))),
            true,
        ),
        Field::new("address_type", DataType::Utf8, true),
        Field::new("ens", DataType::Utf8, true),
        Field::new("contract_info", contract_info_array.data_type().clone(), true),
        Field::new("social_metadata", socials_array.data_type().clone(), true),
    ]);

    RecordBatch::try_new(
        Arc::new(schema),
        vec![
            Arc::new(address_array),
            Arc::new(entity_name_array),
            Arc::new(nametag_array),
            Arc::new(labels_array),
            Arc::new(address_type_array),
            Arc::new(ens_array),
            Arc::new(contract_info_array),
            Arc::new(socials_array),
        ],
    )
}

fn get_contract_info_array(address_metadata: Vec<&AddressMetadata>) -> StructArray {
    let mut verified_contract_builder = BooleanBuilder::new();
    let mut contract_creator_builder = StringBuilder::new();
    let mut reputation_builder = UInt8Builder::new();

    for meta in address_metadata {
        if let Some(contract_info) = &meta.contract_info {
            verified_contract_builder.append_option(contract_info.verified_contract);
            contract_creator_builder.append_option(
                contract_info
                    .contract_creator
                    .as_ref()
                    .map(|addr| addr.to_string()),
            );
            reputation_builder.append_option(contract_info.reputation);
        } else {
            verified_contract_builder.append_null();
            contract_creator_builder.append_null();
            reputation_builder.append_null();
        }
    }

    let verified_contract_array = verified_contract_builder.finish();
    let contract_creator_array = contract_creator_builder.finish();
    let reputation_array = reputation_builder.finish();

    let fields = vec![
        Field::new("verified_contract", DataType::Boolean, true),
        Field::new("contract_creator", DataType::Utf8, true),
        Field::new("reputation", DataType::UInt8, true),
    ];

    let arrays = vec![
        Arc::new(verified_contract_array) as ArrayRef,
        Arc::new(contract_creator_array) as ArrayRef,
        Arc::new(reputation_array) as ArrayRef,
    ];

    StructArray::try_new(fields.into(), arrays, None).expect("Failed to init struct arrays")
}

fn get_socials_array(address_metadata: Vec<&AddressMetadata>) -> StructArray {
    let mut twitter_builder = StringBuilder::new();
    let mut twitter_followers_builder = UInt64Builder::new();
    let mut website_url_builder = StringBuilder::new();
    let mut crunchbase_builder = StringBuilder::new();
    let mut linkedin_builder = StringBuilder::new();

    for meta in address_metadata {
        twitter_builder.append_option(meta.social_metadata.twitter.as_deref());
        twitter_followers_builder.append_option(meta.social_metadata.twitter_followers);
        website_url_builder.append_option(meta.social_metadata.website_url.as_deref());
        crunchbase_builder.append_option(meta.social_metadata.crunchbase.as_deref());
        linkedin_builder.append_option(meta.social_metadata.linkedin.as_deref());
    }

    let twitter_array = twitter_builder.finish();
    let twitter_followers_array = twitter_followers_builder.finish();
    let website_url_array = website_url_builder.finish();
    let crunchbase_array = crunchbase_builder.finish();
    let linkedin_array = linkedin_builder.finish();

    let fields = vec![
        Field::new("twitter", DataType::Utf8, true),
        Field::new("twitter_followers", DataType::UInt64, true),
        Field::new("website_url", DataType::Utf8, true),
        Field::new("crunchbase", DataType::Utf8, true),
        Field::new("linkedin", DataType::Utf8, true),
    ];

    let arrays = vec![
        Arc::new(twitter_array) as ArrayRef,
        Arc::new(twitter_followers_array) as ArrayRef,
        Arc::new(website_url_array) as ArrayRef,
        Arc::new(crunchbase_array) as ArrayRef,
        Arc::new(linkedin_array) as ArrayRef,
    ];

    StructArray::try_new(fields.into(), arrays, None).expect("Failed to init struct arrays")
}