1+ import mysql .connector
12import requests
2- import pickle
33
44
55class API :
@@ -41,8 +41,7 @@ def latest(self, category: str or int) -> dict | None:
4141 # /list endpoint
4242 def list_ (self , category : str or int , amount : int = - 1 ) -> list | None :
4343 """The `/list` endpoint returns a list of circulars from a particular category"""
44- if type (category ) == int :
45- category = int (category )
44+ if type (category ) is int :
4645 if not 1 < category < 100 :
4746 raise ValueError ("Invalid category Number" )
4847
@@ -106,7 +105,7 @@ def getpng(self, url: str) -> list | None:
106105
107106
108107class CircularChecker :
109- def __init__ (self , category , url : str = "https://bpsapi.rajtech.me/" , cache_method = None , debug : bool = False ,
108+ def __init__ (self , category , url : str = "https://bpsapi.rajtech.me/" , cache_method = 'sqlite' , debug : bool = False ,
110109 ** kwargs ):
111110 self .url = url
112111 self .category = category
@@ -134,87 +133,69 @@ def __init__(self, category, url: str = "https://bpsapi.rajtech.me/", cache_meth
134133
135134 self .cache_method = cache_method
136135
137- if cache_method is not None :
138- if cache_method == "database" :
139- try :
140- self .db_name = kwargs ['db_name' ]
141- self .db_path = kwargs ['db_path' ]
142- self .db_table = kwargs ['db_table' ]
143- except KeyError :
144- raise ValueError ("Invalid Database Parameters" )
145-
146- import sqlite3
147- import os
148-
149- if not os .path .exists (self .db_path + f"/{ self .db_name } .db" ):
150- os .mkdir (self .db_path )
151-
152- self ._con = sqlite3 .connect (self .db_path + f"/{ self .db_name } .db" )
153- self ._cur = self ._con .cursor ()
154-
155- self ._cur .execute (
156- f"CREATE TABLE IF NOT EXISTS { self .db_table } (title TEXT, category TEXT, data BLOB)" )
157-
158- # check if the cache exists
159- self ._cur .execute (f"SELECT * FROM { self .db_table } WHERE title = ? AND category = ?" ,
160- ("circular_list" , self .category ))
161- if self ._cur .fetchone () is None :
162- self ._cur .execute (f"INSERT INTO { self .db_table } VALUES (?, ?, ?)" ,
163- ("circular_list" , self .category , pickle .dumps ([])))
164- self ._con .commit ()
165-
166- elif cache_method == "pickle" :
167- try :
168- self .pickle_path = kwargs ['pickle_path' ]
169- self .pickle_name = kwargs ['pickle_name' ]
170- except KeyError :
171- raise ValueError ("Invalid Pickle Path" )
172-
173- if self .pickle_name .endswith (".pickle" ):
174- self .pickle_name = self .pickle_name [:- 7 ]
175-
176- import os
177- if not os .path .exists (self .pickle_path ):
178- os .mkdir (self .pickle_path )
179-
180- # create a pickle file if it doesn't exist
181- if not os .path .exists (self .pickle_path + f"/{ self .pickle_name } .pickle" ):
182- with open (self .pickle_path + f"/{ self .pickle_name } .pickle" , "wb" ) as f :
183- pickle .dump ([], f )
184-
185- else :
186- raise ValueError ("Invalid Cache Method" )
136+ if cache_method is None :
137+ raise ValueError ("Invalid Cache Method" )
187138
188- def get_cache (self ) -> list [list ]:
189- if self .cache_method == "database" :
190- self ._cur .execute (f"SELECT * FROM { self .db_table } WHERE category = ?" , (self .category ,))
191- res = self ._cur .fetchone ()
192- if res is None :
193- return []
194- else :
195- return pickle .loads (res [2 ])
139+ if cache_method == "sqlite" :
140+ try :
141+ self .db_name = kwargs ['db_name' ]
142+ self .db_path = kwargs ['db_path' ]
143+ self .db_table = kwargs ['db_table' ]
144+ except KeyError :
145+ raise ValueError ("Invalid Database Parameters. One of db_name, db_path, db_table not passed into kwargs" )
196146
197- elif self .cache_method == "pickle" :
147+ import sqlite3
148+ import os
198149
199- with open (self .pickle_path + f"/{ self .pickle_name } .pickle" , "rb" ) as f :
200- return pickle . load ( f )
150+ if not os . path . exists (self .db_path + f"/{ self .db_name } .db" ) :
151+ os . mkdir ( self . db_path )
201152
202- else :
203- return self ._cache
153+ self . _con = sqlite3 . connect ( self . db_path + f"/ { self . db_name } .db" )
154+ self . _cur = self ._con . cursor ()
204155
205- def _set_cache (self , data , title : str = "circular_list" ):
206- if self .cache_method == "database" :
207- self ._cur .execute (f"DELETE FROM { self .db_table } WHERE category = ?" , (self .category ,))
208- self ._cur .execute (f"INSERT INTO { self .db_table } VALUES (?, ?, ?)" ,
209- (title , self .category , pickle .dumps (data )))
210- self ._con .commit ()
156+ elif cache_method == "mysql" :
157+ try :
158+ self .db_name = kwargs ['db_name' ]
159+ self .db_user = kwargs ['db_user' ]
160+ self .db_host = kwargs ['db_host' ]
161+ self .db_port = kwargs ['db_port' ]
162+ self .db_password = kwargs ['db_password' ]
163+ self .db_table = kwargs ['db_table' ]
211164
212- elif self .cache_method == "pickle" :
213- with open (self .pickle_path + f"/{ self .pickle_name } .pickle" , "wb" ) as f :
214- pickle .dump (data , f )
165+ except KeyError :
166+ raise ValueError ("Invalid Database Parameters. One of db_name, db_user, db_host, db_port, db_password, db_table not passed into kwargs" )
215167
216- else :
217- self ._cache = data
168+ self ._con = mysql .connector .python (
169+ host = self .db_host , port = self .db_port , password = self .db_password ,
170+ user = self .db_user , database = self .db_name ,
171+ )
172+
173+ self ._cur = self ._con .cursor ()
174+
175+ self ._cur .execute (
176+ f"CREATE TABLE IF NOT EXISTS { self .db_table } (category TEXT, id INTEGER, title TEXT, link TEXT)"
177+ )
178+ self ._con .commit ()
179+
180+ def get_cache (self ) -> list [list ]:
181+ self ._cur .execute (f"SELECT * FROM { self .db_table } WHERE category = ?" , (self .category ,))
182+ res = self ._cur .fetchall ()
183+
184+ return res
185+
186+ def _set_cache (self , data ):
187+ # data [ (id, title, link) ]
188+ self ._cur .executemany (
189+ f"INSERT IGNORE INTO { self .db_table } (category, id, title, link) VALUES ({ self .category } , ?, ?, ?)" ,
190+ data
191+ )
192+ self ._con .commit ()
193+
194+ def _add_to_cache (self , id_ , title , link ):
195+ self ._cur .execute (
196+ f"INSERT IGNORE INTO { self .db_table } (id, title, link) VALUES (?, ?, ?, ?)" ,
197+ (self .category , id_ , title , link )
198+ )
218199
219200 def _refresh_cache (self ):
220201 request = requests .get (f"{ self .url } list/{ self .category } " )
@@ -229,37 +210,34 @@ def _refresh_cache(self):
229210 self ._set_cache (json ['data' ])
230211
231212 def check (self ) -> list [dict ] | list [None ]:
232- return_dict = []
233- old_cached = self .get_cache ()
234-
235- if not old_cached :
236- self ._refresh_cache ()
237- return []
238-
239- self ._cur .execute (f"SELECT * FROM { self .db_table } WHERE category = ?" , (self .category ,))
240- res = self ._cur .fetchone ()
241-
242- if res is None :
243- cache = []
244- else :
245- cache = pickle .loads (res [2 ])
213+ self ._cur .execute (f"SELECT COUNT(*) FROM { self .db_table } WHERE category = ?" , (self .category ,))
214+ cached_circular_amount = self ._cur .fetchone ()[0 ]
246215
247216 self ._refresh_cache ()
248- final_dict = self .get_cache ()
217+ new_circular_list = self .get_cache ()
218+ # data[(id, title, link)]
249219
250- if final_dict != old_cached : # If the old and new dict are not the same
251- new_circular_objects = [ i for i in final_dict if i not in old_cached ]
220+ if len ( new_circular_list ) != cached_circular_amount :
221+ self . _cur . execute ( f"SELECT id FROM { self . db_table } WHERE category = ?" , ( self . category ,))
252222
253- for circular in new_circular_objects :
254- # check if they are in the database
255- if circular in cache :
256- continue
223+ cached_circular_ids = self ._cur .fetchall ()
224+ cached_circular_ids = [i [0 ] for i in cached_circular_ids ]
257225
258- return_dict . append ( circular )
226+ new_circular_objects = [ i for i in new_circular_list if i [ 0 ] not in cached_circular_ids ]
259227
260- # sort the return_dict by circular id in ascending order
261- return_dict .sort (key = lambda x : x ['id' ])
262- return return_dict
228+ # (id, title, link) -> {'id': id, 'title': title, 'link': link}
229+ new_circular_objects = [
230+ {
231+ 'id' : i [0 ],
232+ 'title' : i [1 ],
233+ 'link' : [2 ]
234+ }
235+ for i in new_circular_objects
236+ ]
237+
238+ # sort the new_circular_objects by circular id in ascending order
239+ new_circular_objects .sort (key = lambda x : x ['id' ])
240+ return new_circular_objects
263241
264242 else :
265243 return []
@@ -269,13 +247,10 @@ class CircularCheckerGroup:
269247 def __init__ (self , * args , ** kwargs ):
270248 self ._checkers = []
271249
272- if kwargs .get ("debug" ):
273- self .debug = True
274- else :
275- self .debug = False
250+ self .debug = bool (kwargs .get ("debug" ))
276251
277252 for arg in args :
278- if type (arg ) != CircularChecker :
253+ if type (arg ) is not CircularChecker :
279254 raise ValueError ("Invalid CircularChecker Object" )
280255 self ._checkers .append (arg )
281256
@@ -285,7 +260,7 @@ def __init__(self, *args, **kwargs):
285260 def add (self , checker : CircularChecker , * args : CircularChecker ):
286261 self ._checkers .append (checker )
287262 for arg in args :
288- if type (arg ) != CircularChecker :
263+ if type (arg ) is not CircularChecker :
289264 raise ValueError ("Invalid CircularChecker Object" )
290265 self ._checkers .append (arg )
291266
0 commit comments