abstract-solcatcher-database 0.0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. abstract_solcatcher_database-0.0.0.1/PKG-INFO +37 -0
  2. abstract_solcatcher_database-0.0.0.1/README.md +3 -0
  3. abstract_solcatcher_database-0.0.0.1/pyproject.toml +3 -0
  4. abstract_solcatcher_database-0.0.0.1/setup.cfg +4 -0
  5. abstract_solcatcher_database-0.0.0.1/setup.py +34 -0
  6. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/__init__.py +6 -0
  7. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/db_funcs.py +454 -0
  8. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/managers/__init__.py +1 -0
  9. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/managers/meta_data_manager.py +120 -0
  10. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/pair_updates.py +186 -0
  11. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/__init__.py +3 -0
  12. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/__init__.py +7 -0
  13. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_account_data.py +17 -0
  14. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_log_data.py +11 -0
  15. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_meta_data.py +25 -0
  16. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_misc.py +66 -0
  17. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_pair_data.py +48 -0
  18. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/call_transactions_data.py +25 -0
  19. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/call_functions/queries.py +3 -0
  20. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/filter_functions/__init__.py +1 -0
  21. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/filter_functions/filter_data_functions.py +62 -0
  22. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/queries.py +3 -0
  23. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/query_functions/__init__.py +2 -0
  24. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/query_functions/fetch_utils.py +105 -0
  25. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/query_functions/query_functions/queries.py +132 -0
  26. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/__init__.py +3 -0
  27. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/charts/__init__.py +1 -0
  28. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/charts/price_chart.py +131 -0
  29. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/pair_txns/__init__.py +2 -0
  30. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/pair_txns/pool_metrics.py +255 -0
  31. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/pair_txns/transaction_processor.py +428 -0
  32. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/user_txns/__init__.py +2 -0
  33. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/user_txns/tally_profits.py +35 -0
  34. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/transaction_utils/user_txns/transaction_history.py +115 -0
  35. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/utils/__init__.py +3 -0
  36. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/utils/get_time_data.py +182 -0
  37. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/utils/image_utils.py +120 -0
  38. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database/utils/utils.py +103 -0
  39. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database.egg-info/PKG-INFO +37 -0
  40. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database.egg-info/SOURCES.txt +41 -0
  41. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database.egg-info/dependency_links.txt +1 -0
  42. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database.egg-info/requires.txt +5 -0
  43. abstract_solcatcher_database-0.0.0.1/src/abstract_solcatcher_database.egg-info/top_level.txt +1 -0
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.2
2
+ Name: abstract_solcatcher_database
3
+ Version: 0.0.0.1
4
+ Home-page: https://github.com/AbstractEndeavors/abstract_solcatcher_database
5
+ Author: putkoff
6
+ Author-email: partners@abstractendeavors.com
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Topic :: Software Development :: Libraries
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.6
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.6
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: psycopg2-binary
22
+ Requires-Dist: abstract_solcatcher
23
+ Requires-Dist: abstract_apis
24
+ Requires-Dist: abstract_security
25
+ Requires-Dist: abstract_utilities
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+
35
+ ## Abstract Solana
36
+
37
+
@@ -0,0 +1,3 @@
1
+ ## Abstract Solana
2
+
3
+
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,34 @@
1
+ from time import time
2
+ import setuptools
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+ setuptools.setup(
6
+ name='abstract_solcatcher_database',
7
+ version='0.0.0.1',
8
+ author='putkoff',
9
+ author_email='partners@abstractendeavors.com',
10
+ description="",
11
+ long_description=long_description,
12
+ long_description_content_type='text/markdown',
13
+ url='https://github.com/AbstractEndeavors/abstract_solcatcher_database',
14
+ classifiers=[
15
+ 'Development Status :: 3 - Alpha',
16
+ 'Intended Audience :: Developers',
17
+ 'Topic :: Software Development :: Libraries',
18
+ 'License :: OSI Approved :: MIT License',
19
+ 'Programming Language :: Python :: 3',
20
+ 'Programming Language :: Python :: 3.6',
21
+ 'Programming Language :: Python :: 3.7',
22
+ 'Programming Language :: Python :: 3.8',
23
+ 'Programming Language :: Python :: 3.9',
24
+ 'Programming Language :: Python :: 3.10',
25
+ 'Programming Language :: Python :: 3.11',
26
+ 'Programming Language :: Python :: 3.12',
27
+ ],
28
+ install_requires=['psycopg2-binary','abstract_solcatcher','abstract_apis','abstract_security','abstract_utilities'],
29
+ package_dir={"": "src"},
30
+ packages=setuptools.find_packages(where="src"),
31
+ python_requires=">=3.6",
32
+ # Add this line to include wheel format in your distribution
33
+ setup_requires=['wheel'],
34
+ )
@@ -0,0 +1,6 @@
1
+ from .db_funcs import *
2
+ from .pair_updates import *
3
+ from .query_functions import *
4
+ from .utils import *
5
+ from .transaction_utils import *
6
+ from .managers import *
@@ -0,0 +1,454 @@
1
+ import logging
2
+
3
+ # Configure logging
4
+ logging.basicConfig(level=logging.INFO) # Set level to INFO or higher
5
+ from psycopg2 import sql, connect
6
+ from psycopg2.extras import DictCursor
7
+ from abstract_utilities import make_list, SingletonMeta, is_number
8
+ from abstract_security import get_env_value
9
+ import psycopg2,time
10
+
11
+ env_path = '/home/solcatcher/.env'
12
+
13
+ def get_env_val(key):
14
+ return get_env_value(key=key, path=env_path)
15
+
16
+ RABBITMQ_HOST = get_env_val("SOLCATCHER_AMQP_HOST") or 'solcatcher.io'
17
+ RABBITMQ_PORT = get_env_val("SOLCATCHER_AMQP_PORT") or '5672'
18
+ RABBITMQ_USER = get_env_val("SOLCATCHER_AMQP_USER") or 'solcatcher'
19
+ RABBITMQ_NAME = get_env_val("SOLCATCHER_AMQP_NAME") or 'solcatcher'
20
+ RABBITMQ_PASSWORD = get_env_val("SOLCATCHER_AMQP_PASSWORD") or 'solcatcher123'
21
+
22
+ POSTGRESQL_HOST = get_env_val("SOLCATCHER_POSTGRESQL_HOST") or 'solcatcher.io'
23
+ POSTGRESQL_PORT = get_env_val("SOLCATCHER_POSTGRESQL_PORT") or '5432'
24
+ POSTGRESQL_USER = get_env_val("SOLCATCHER_POSTGRESQL_USER") or 'solcatcher'
25
+ POSTGRESQL_NAME = get_env_val("SOLCATCHER_POSTGRESQL_NAME") or 'solcatcher'
26
+ POSTGRESQL_PASSWORD = get_env_val("SOLCATCHER_POSTGRESQL_PASSWORD") or 'solcatcher123!!!456'
27
+
28
+ DB_URL = f"postgresql://{POSTGRESQL_USER}:{POSTGRESQL_PASSWORD}@{POSTGRESQL_HOST}:{POSTGRESQL_PORT}/{POSTGRESQL_NAME}"
29
+
30
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
31
+
32
+ def get_connection():
33
+ """Establish a database connection."""
34
+ return psycopg2.connect(
35
+ dbname=POSTGRESQL_NAME,
36
+ user=POSTGRESQL_USER,
37
+ password=POSTGRESQL_PASSWORD,
38
+ host=POSTGRESQL_HOST,
39
+ port=POSTGRESQL_PORT
40
+ )
41
+
42
+ def get_all_table_names(schema='public'):
43
+ """Fetch all table names from a specified schema."""
44
+ conn = get_connection()
45
+ query = """
46
+ SELECT table_name
47
+ FROM information_schema.tables
48
+ WHERE table_schema = %s AND table_type = 'BASE TABLE';
49
+ """
50
+ try:
51
+ with conn.cursor() as cursor:
52
+ cursor.execute(query, (schema,))
53
+ table_names = [row[0] for row in cursor.fetchall()]
54
+ return table_names
55
+ except Exception as e:
56
+ print(f"An error occurred in get all tyables: {e}")
57
+ finally:
58
+ conn.close()
59
+ def get_time_interval(seconds =0,minutes=0, hours=0, days=0, weeks=0,months=0, years=0,*args,**kwargs):
60
+ """Calculate a UNIX timestamp for the given time offset."""
61
+ secs = 1
62
+ mins = secs*60
63
+ hr = 60 * mins
64
+ day = 24 * hr
65
+ week = 7 * day
66
+ year = 365 * day
67
+ month = year/12
68
+ return ((secs * seconds) + (mins * minutes) + (hr * hours) + (day * days) + (week * weeks) + (month * months) + (year * years))
69
+
70
+ def get_time(time_interval,*args,**kwargs):
71
+ timeStamp = time.time() - time_interval
72
+ return int(timeStamp) # Return integer timestamp
73
+
74
+ def derive_timestamp(timestamp=None,seconds =0,minutes=0, hours=0, days=0, weeks=0,months=0, years=0,*args,**kwargs):
75
+ time_interval = get_time_interval(seconds=seconds,minutes=minutes, hours=hours, days=days, weeks=weeks,months=months, years=years)
76
+ if time_interval:
77
+ timestamp = get_time(time_interval)
78
+ return timestamp
79
+ def get_timestamp_from_data(data,*args,**kwargs):
80
+ years = data.get('years',0)
81
+ months = data.get('months',0)
82
+ weeks = data.get('weeks',0)
83
+ days = data.get('days',0)
84
+ hours = data.get('hours',0)
85
+ minutes = data.get('minutes',0)
86
+ seconds = data.get('seconds',0)
87
+ timestamp = data.get('timestamp')
88
+ time_interval = get_time_interval(seconds=seconds,minutes=minutes, hours=hours, days=days, weeks=weeks,months=months, years=years)
89
+ if time_interval:
90
+ timestamp = get_time(time_interval)
91
+ return timestamp
92
+
93
+ def get_query_result(query, conn):
94
+ """Executes a query and returns the results or commits the transaction."""
95
+ with conn.cursor() as cursor:
96
+ cursor.execute(query)
97
+ if query.strip().lower().startswith("select"):
98
+ return cursor.fetchall() # Return data for SELECT queries
99
+ conn.commit()
100
+
101
+ def query_data(query, values=None, error="Error executing query:", zipRows=True):
102
+ """Execute a query and handle transactions with error management."""
103
+ with get_connection() as conn:
104
+ # Choose the cursor type based on whether you want to zip rows with column names
105
+ cursor_factory = DictCursor if zipRows else None
106
+ with conn.cursor(cursor_factory=cursor_factory) as cursor:
107
+ try:
108
+ cursor.execute(query, values)
109
+ result = cursor.fetchall()
110
+ # Log the first row to see its structure
111
+ if result:
112
+ logging.info("First row data structure: %s", result[0])
113
+ return result
114
+ except Exception as e:
115
+ conn.rollback()
116
+ logging.error("%s %s\nValues: %s\n%s", error, query, values, e)
117
+
118
+ #####################################
119
+ # Fix #1: Correct the usage in fetch_any_combo
120
+ #####################################
121
+ def fetch_any_combo(columnNames='*',
122
+ tableName=None,
123
+ searchColumn=None,
124
+ searchValue=None,
125
+ anyValue=False,
126
+ zipit=True,
127
+ schema='public'):
128
+ """
129
+ Fetch rows based on dynamic SQL built from parameters.
130
+
131
+ :param columnNames: Comma separated columns or '*' for all.
132
+ :param tableName: The table to query. Must not be None or '*'.
133
+ :param searchColumn: The column on which to filter.
134
+ :param searchValue: The value to match in searchColumn.
135
+ :param anyValue: If True, uses = ANY(%s) for arrays.
136
+ :param zipit: If True, uses DictCursor in query_data.
137
+ :param schema: The DB schema.
138
+ """
139
+ if not tableName or tableName == '*':
140
+ logging.error("Invalid tableName provided to fetch_any_combo: %s", tableName)
141
+ return [] # or raise an Exception
142
+
143
+ # Build the SELECT list
144
+ if columnNames == '*':
145
+ select_cols = sql.SQL('*')
146
+ else:
147
+ # Convert "col1,col2" -> [col1, col2]
148
+ col_list = [c.strip() for c in columnNames.split(',')]
149
+ select_cols = sql.SQL(", ").join(sql.Identifier(col) for col in col_list)
150
+
151
+ # Build the base query: SELECT ... FROM schema.tableName
152
+ base_query = sql.SQL("SELECT {} FROM {}.{}").format(
153
+ select_cols,
154
+ sql.Identifier(schema),
155
+ sql.Identifier(tableName)
156
+ )
157
+
158
+ # Build the WHERE clause if needed
159
+ params = []
160
+ if searchColumn and searchValue is not None:
161
+ if anyValue:
162
+ base_query += sql.SQL(" WHERE {} = ANY(%s)").format(sql.Identifier(searchColumn))
163
+ params.append(searchValue if isinstance(searchValue, list) else [searchValue])
164
+ else:
165
+ base_query += sql.SQL(" WHERE {} = %s").format(sql.Identifier(searchColumn))
166
+ params.append(searchValue)
167
+
168
+ return query_data(base_query, values=params, zipRows=zipit)
169
+
170
+ def get_anything(*args, **kwargs):
171
+ if args:
172
+ for arg in args:
173
+ if 'tableName' not in kwargs:
174
+ kwargs['tableName'] = arg
175
+ response = fetch_any_combo(**kwargs)
176
+ logging.info("Received data: %s", response) # Log to see the data
177
+ if isinstance(response, list) and len(response) == 1:
178
+ response = response[0]
179
+ return response
180
+
181
+ def get_table_name_from_query(query):
182
+ """Extract table name from SQL query."""
183
+ if isinstance(query, sql.Composed):
184
+ query = query.as_string(get_connection()) # Convert to string
185
+ parts = query.split()
186
+ if 'from' in parts:
187
+ return parts[parts.index('from') + 1]
188
+ return None
189
+
190
+ def get_all_pair_info(**kwargs):
191
+ pair = get_pair(**kwargs)
192
+ if not pair:
193
+ return {}
194
+ pair = pair[0]
195
+ pair['meta_data'] = get_meta_data_from_meta_id(pair.get('meta_id'))
196
+ pair['txns'] = get_all_txns_for_pair_id(pair.get('id'))
197
+ return pair
198
+
199
+ class columnNamesManager(metaclass=SingletonMeta):
200
+ def __init__(self):
201
+ if not hasattr(self, 'initialized'):
202
+ self.initialized = True
203
+ self.columnNames = {}
204
+
205
+ def get_column_names(self, tableName, schema='public'):
206
+ if tableName not in self.columnNames:
207
+ self.columnNames[tableName] = self.fetch_column_names(tableName, schema)
208
+ return self.columnNames[tableName]
209
+
210
+ def fetch_column_names(self, tableName, schema='public'):
211
+ query = """
212
+ SELECT column_name
213
+ FROM information_schema.columns
214
+ WHERE table_name = %s AND table_schema = %s
215
+ ORDER BY ordinal_position;
216
+ """
217
+ results = query_data(query, [tableName, schema], error='Error fetching column names')
218
+ if not results:
219
+ logging.warning(f"No columns found for table {tableName} in schema {schema}")
220
+ return []
221
+ return [row[0] for row in results]
222
+
223
+ def zip_rows(self, tableName, rows, schema='public'):
224
+ column_names = self.get_column_names(tableName, schema)
225
+ return [dict(zip(column_names, make_list(row))) for row in rows]
226
+
227
+ def get_pair_id(*args, **kwargs):
228
+ """
229
+ Example function that tries to retrieve a pair's ID by various criteria.
230
+ There's a potential bug with 'is_mint(obj)' references, so watch out for that.
231
+ """
232
+ id_val = None
233
+ for key,value in kwargs.items():
234
+ if key == 'pair_id':
235
+ id_val = value
236
+ if key == 'pair' and isinstance(value, dict):
237
+ id_val = value.get('id')
238
+ if key == 'mint':
239
+ rows = fetch_any_combo(tableName='transactions', searchColumn='mint', searchValue=value)
240
+ if rows:
241
+ id_val = rows[0].get('id')
242
+ if key == 'signature':
243
+ rows = fetch_any_combo(tableName='transactions', searchColumn='signature', searchValue=value)
244
+ if rows:
245
+ id_val = rows[0].get('id')
246
+
247
+ for arg in args:
248
+ if is_number(arg):
249
+ id_val = arg
250
+ elif isinstance(arg, dict):
251
+ id_val = arg.get('id')
252
+ # Potential bug fix #2: changed 'obj' -> 'arg'
253
+ # elif is_signature(arg):
254
+ # ...
255
+ # elif is_mint(arg):
256
+ # ...
257
+ # etc.
258
+
259
+ if id_val:
260
+ return id_val
261
+ def get_max_for_row(tableName):
262
+ return query_data(f"SELECT COUNT(*) FROM {tableName};")
263
+ #####################################
264
+ # Fix #2: Correctly use get_pair_from_* in get_pair
265
+ #####################################
266
+ def get_pair(mint=None, signature=None, pair_id=None):
267
+ """Retrieve row(s) from 'pairs' table by mint, signature, or pair_id."""
268
+ if pair_id:
269
+ return get_pair_from_pair_id(pair_id)
270
+ elif mint:
271
+ return get_pair_from_mint(mint)
272
+ elif signature:
273
+ return get_pair_from_signature(signature)
274
+ return []
275
+
276
+ def get_pair_from_mint(mint):
277
+ response = fetch_any_combo(tableName='pairs', searchColumn="mint", searchValue=mint, zipit=True)
278
+ return getZipRows('pairs', response)
279
+
280
+ def get_pair_from_signature(signature):
281
+ response = fetch_any_combo(tableName='pairs', searchColumn="signature", searchValue=signature, zipit=True)
282
+ return getZipRows('pairs', response)
283
+
284
+ def get_pair_from_pair_id(pair_id):
285
+ response = fetch_any_combo(tableName='pairs', searchColumn="id", searchValue=pair_id, zipit=True)
286
+ return getZipRows('pairs', response)
287
+
288
+ def getZipRows(tableName, rows, schema='public'):
289
+ column_names = get_column_names(tableName, schema)
290
+ return [dict(zip(column_names, row)) for row in make_list(rows) if row]
291
+
292
+ def get_column_names(tableName, schema='public'):
293
+ return columnNamesManager().get_column_names(tableName, schema)
294
+
295
+ def get_transaction_from_txn_id(txn_id):
296
+ response = fetch_any_combo(tableName='transactions', searchColumn="id", searchValue=txn_id, zipit=True)
297
+ return getZipRows('transactions', response)
298
+ def get_transaction_from_signature(signature):
299
+ response = fetch_any_combo(tableName='transactions', searchColumn="signature", searchValue=signature, zipit=True)
300
+ return getZipRows('transactions', response)
301
+
302
+ def get_transaction_from_log_id(log_id):
303
+ """
304
+ Example that first fetches signature from logdata, then fetches transactions by signature.
305
+ """
306
+ signature_rows = fetch_any_combo(columnNames='signature',
307
+ tableName='logdata',
308
+ searchColumn='id',
309
+ searchValue=log_id,
310
+ zipit=True)
311
+ if signature_rows and len(signature_rows) == 1:
312
+ signature = signature_rows[0].get('signature')
313
+ tx_rows = fetch_any_combo(tableName='transactions',
314
+ searchColumn='signature',
315
+ searchValue=signature,
316
+ zipit=True)
317
+ return getZipRows('transactions', tx_rows)
318
+ return []
319
+
320
+ def get_all_txns_for_pair_id(pair_id):
321
+ response = fetch_any_combo(tableName='transactions', searchColumn='pair_id', searchValue=pair_id, zipit=True)
322
+ return getZipRows('transactions', response)
323
+
324
+ #####################################
325
+ # Fix #3: Add missing signature clause in get_transactions
326
+ #####################################
327
+ def get_transactions(txn_id=None, log_id=None, signature=None, pair_id=None):
328
+ if pair_id:
329
+ return get_all_txns_for_pair_id(pair_id)
330
+ if txn_id:
331
+ return get_transaction_from_txn_id(txn_id)
332
+ if log_id:
333
+ return get_transaction_from_log_id(log_id)
334
+ if signature:
335
+ return get_transaction_from_signature(signature)
336
+ return []
337
+
338
+ def get_meta_data_from_mint(mint):
339
+ response = fetch_any_combo(tableName='metadata', searchColumn='mint', searchValue=mint, zipit=True)
340
+ return getZipRows('metadata', response)
341
+
342
+ def get_meta_data_from_meta_id(meta_id):
343
+ response = fetch_any_combo(tableName='metadata', searchColumn='id', searchValue=meta_id, zipit=True)
344
+ return getZipRows('metadata', response)
345
+
346
+ def get_meta_data_from_pair_id(pair_id):
347
+ pair_rows = get_pair_from_pair_id(pair_id)
348
+ if not pair_rows:
349
+ return []
350
+ pair = pair_rows[0]
351
+ meta_id = pair.get('meta_id')
352
+ if not meta_id:
353
+ return []
354
+ return get_meta_data_from_meta_id(meta_id)
355
+
356
+ #####################################
357
+ # Fix #4: get_meta_data uses correct references
358
+ #####################################
359
+ def get_meta_data(pair_id=None, meta_id=None, mint=None):
360
+ if mint:
361
+ return get_meta_data_from_mint(mint)
362
+ if pair_id:
363
+ return get_meta_data_from_pair_id(pair_id)
364
+ if meta_id:
365
+ return get_meta_data_from_meta_id(meta_id)
366
+ return []
367
+
368
+ #####################################
369
+ # Fix #5: Ensure get_all_pair_data aligns with the fixed get_pair
370
+ #####################################
371
+ def get_all_pair_data(mint=None, signature=None, pair_id=None):
372
+ """
373
+ Gathers pair info, associated transactions, and metadata.
374
+ """
375
+ pair_rows = get_pair(mint=mint, signature=signature, pair_id=pair_id)
376
+ if not pair_rows:
377
+ return {}
378
+ pair = pair_rows[0]
379
+ pair_id_val = pair.get('id')
380
+ mint_val = pair.get('mint')
381
+
382
+ pair_data = {}
383
+ pair_data["pair"] = pair
384
+ pair_data["txns"] = get_transactions(pair_id=pair_id_val)
385
+ pair_data["metadata"] = get_meta_data(mint=mint_val)
386
+ return pair_data
387
+
388
+ def fetch_filtered_transactions_paginated(
389
+ sol_amount,
390
+ operator=">",
391
+ timestamp_operator=None,
392
+ limit=50,
393
+ offset=0,
394
+ years=0,
395
+ months=0,
396
+ weeks=0,
397
+ days=0,
398
+ hours=0,
399
+ minutes=0,
400
+ seconds=0,
401
+ timestamp=None,
402
+ *args,
403
+ **kwargs
404
+ ):
405
+ # Build the base SQL query.
406
+ # Note that we're filtering on the first element of the JSON array in t.tcns
407
+ query = f"""
408
+ SELECT
409
+ p.*,
410
+ t.*,
411
+ m.*,
412
+ t2.id AS related_txn
413
+ FROM
414
+ transactions t
415
+ JOIN
416
+ pairs p ON t.pair_id = p.id
417
+ LEFT JOIN
418
+ metadata m ON p.meta_id = m.id
419
+ LEFT JOIN
420
+ transactions t2 ON t.pair_id = t2.pair_id AND t.signature != t2.signature
421
+ WHERE
422
+ t.signature IN (
423
+ SELECT signature FROM pairs WHERE signature IS NOT NULL
424
+ )
425
+ AND
426
+ t.program_id = p.program_id
427
+ AND
428
+ EXISTS (
429
+ SELECT 1
430
+ FROM jsonb_array_elements(t.tcns) AS elem
431
+ WHERE (elem ->> 'sol_amount')::numeric {operator} %s
432
+ """
433
+ params = [sol_amount]
434
+
435
+ # Derive a timestamp cutoff if provided (assuming derive_timestamp is implemented)
436
+ ts = derive_timestamp(
437
+ years=years,
438
+ months=months,
439
+ weeks=weeks,
440
+ days=days,
441
+ hours=hours,
442
+ minutes=minutes,
443
+ seconds=seconds,
444
+ timestamp=timestamp)
445
+
446
+ if ts and timestamp_operator:
447
+ query += f" AND (elem ->> 'timestamp')::bigint {timestamp_operator} %s"
448
+ params.append(int(ts))
449
+
450
+ # Close the EXISTS clause and add ordering/pagination
451
+ query += ") ORDER BY t.updated_at DESC LIMIT %s OFFSET %s;"
452
+ params.extend([limit, offset])
453
+
454
+ return query_data(query, params)
@@ -0,0 +1 @@
1
+ from .meta_data_manager import *
@@ -0,0 +1,120 @@
1
+ from abstract_utilities import get_any_value,SingletonMeta
2
+ import logging,os,json,requests
3
+ from abstract_pandas import pd
4
+ from abstract_apis import getRequest
5
+ from ..query_functions.call_functions.call_meta_data import get_meta_data
6
+ from ..utils.image_utils import *
7
+
8
+ metaDataLowerKeys = {
9
+ 'image': 'image',
10
+ 'uri': 'uri',
11
+ 'supply': 'supply',
12
+ 'symbol': 'symbol',
13
+ 'mintauthority': 'mintAuthority',
14
+ 'freezeauthority': 'freezeAuthority',
15
+ 'twitter': 'twitter',
16
+ 'website': 'website',
17
+ 'ismutable': 'isMutable',
18
+ 'creators': 'creators',
19
+ 'updateauthority': 'updateAuthority',
20
+ 'createdon': 'createdOn',
21
+ 'primarysalehappened': 'createdOn',
22
+ 'description': 'description'
23
+ }
24
+ metaDataTypeKeys = {
25
+ 'image': str,
26
+ 'uri': str,
27
+ 'supply': int,
28
+ 'name':str,
29
+ 'symbol': str,
30
+ 'mintAuthority': str,
31
+ 'freezeAuthority': str,
32
+ 'twitter': str,
33
+ 'website': str,
34
+ 'isMutable': bool,
35
+ 'creators': str,
36
+ 'updateAuthority': str,
37
+ 'createdOn': int,
38
+ 'primarySaleHappened': bool,
39
+ 'description': str
40
+ }
41
+ metaDataCheckKeys = {
42
+ 'image': True,
43
+ 'uri': True,
44
+ 'supply': True,
45
+ 'symbol': True,
46
+ 'name':True,
47
+ 'mintAuthority': True,
48
+ 'freezeAuthority': True,
49
+ 'twitter': True,
50
+ 'website': True,
51
+ 'isMutable': True,
52
+ 'creators': True,
53
+ 'updateAuthority': True,
54
+ 'createdOn': True,
55
+ 'primarySaleHappened': True,
56
+ 'description': True
57
+ }
58
+ metaKeys = list(metaDataTypeKeys.keys())
59
+
60
+ def make_insert(key):
61
+ key = key.replace(' ', '_').upper()
62
+ return f"-{key}-"
63
+ def make_insert_bool(key):
64
+ key = key.replace(' ', '_').upper()
65
+ return f"-{key}_BOOL-"
66
+ def make_check_bool(key):
67
+ key = key.replace(' ', '_').upper()
68
+ return f"-{key}_CHECK-"
69
+ def deKeyKey(key):
70
+ return key.lower()[1:-1].replace('_',' ')
71
+ def getBool(key, value):
72
+ return isinstance(value, metaDataTypeKeys.get(key))
73
+ class metaDataManager(metaclass=SingletonMeta):
74
+ def __init__(self):
75
+ self.allMetaData = {}
76
+ self.metaDataCheckKeys=metaDataCheckKeys
77
+ self.metaDataTypeKeys = metaDataTypeKeys
78
+ def changeTally(self,event,values):
79
+ lower_key = deKeyKey(event)
80
+ regularMetakey = metaDataLowerKeys.get(lower_key)
81
+ self.metaDataCheckKeys[regularMetakey] = values[event]
82
+ def processMetaData(self,mint,imageData=True):
83
+ if not self.allMetaData.get(mint):
84
+ metaData = get_meta_data(mint=mint)
85
+ self.get_meta_vars(metaData,imageData)
86
+ self.allMetaData[mint] = {"processed":self.datas_js,'bools':self.bool_js}
87
+ return self.allMetaData[mint]
88
+ def filter_meta_data(self,mint,filterMetaChecks={}):
89
+ metaData_js = self.processMetaData(mint)
90
+ bools = metaData_js['bools']
91
+ self.allMetaData[mint]['filtered']=True
92
+ for key,check in self.metaDataCheckKeys.items():
93
+ if check and not bools.get(key):
94
+ self.allMetaData[mint]['filtered']=False
95
+ break
96
+ return self.allMetaData[mint]['filtered']
97
+ def get_meta_vars(self,metaData,imageData=True):
98
+ self.datas_js = {}
99
+ self.bool_js = {}
100
+ self.metaData = self.get_uri(metaData,imageData)
101
+ for key in metaKeys:
102
+ self.get_from_any_meta(key,metaData)
103
+ def get_from_any_meta(self,key,metaData):
104
+ values = get_any_value(metaData, key) or None
105
+ value = values[0] if values and isinstance(values, list) else values
106
+ self.bool_js[key] =getBool(key, value)
107
+ self.datas_js[key] = value
108
+ return value
109
+ def get_uri(self,metaData,imageData=True):
110
+ key = 'uri'
111
+ self.get_from_any_meta(key,metaData)
112
+
113
+ if self.bool_js[key] and imageData:
114
+ try:
115
+ metaData[0].update(get_image_vars(self.datas_js[key]) or {})
116
+ except:
117
+ pass
118
+ return metaData
119
+
120
+