cryogenic22 commited on
Commit
a101aa2
·
verified ·
1 Parent(s): de01648

Create utils/collections.py

Browse files
Files changed (1) hide show
  1. utils/collections.py +296 -0
utils/collections.py ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/collections.py
2
+
3
+ import sqlite3
4
+ from typing import List, Dict, Optional
5
+ import streamlit as st
6
+ from datetime import datetime
7
+ from threading import Lock
8
+
9
+ # Create a lock for database operations
10
+ db_lock = Lock()
11
+
12
+ def create_collection_tables(conn: sqlite3.Connection) -> None:
13
+ """
14
+ Create the necessary tables for the collections system.
15
+ """
16
+ with db_lock:
17
+ try:
18
+ # Collections table
19
+ conn.execute('''
20
+ CREATE TABLE IF NOT EXISTS collections (
21
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
22
+ name TEXT NOT NULL UNIQUE,
23
+ description TEXT,
24
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
25
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
26
+ )
27
+ ''')
28
+
29
+ # Document-Collections relationship table
30
+ conn.execute('''
31
+ CREATE TABLE IF NOT EXISTS document_collections (
32
+ document_id INTEGER,
33
+ collection_id INTEGER,
34
+ added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
35
+ PRIMARY KEY (document_id, collection_id),
36
+ FOREIGN KEY (document_id) REFERENCES documents (id) ON DELETE CASCADE,
37
+ FOREIGN KEY (collection_id) REFERENCES collections (id) ON DELETE CASCADE
38
+ )
39
+ ''')
40
+
41
+ # Index for faster lookups
42
+ conn.execute('CREATE INDEX IF NOT EXISTS idx_collection_name ON collections(name)')
43
+ conn.execute('CREATE INDEX IF NOT EXISTS idx_doc_collection ON document_collections(collection_id)')
44
+
45
+ conn.commit()
46
+
47
+ except sqlite3.Error as e:
48
+ st.error(f"Database error: {e}")
49
+ raise
50
+
51
+ def create_collection(conn: sqlite3.Connection, name: str, description: str = "") -> Optional[int]:
52
+ """
53
+ Create a new collection.
54
+ Returns the ID of the new collection or None if creation fails.
55
+ """
56
+ with db_lock:
57
+ try:
58
+ cursor = conn.cursor()
59
+ cursor.execute('''
60
+ INSERT INTO collections (name, description)
61
+ VALUES (?, ?)
62
+ ''', (name, description))
63
+ conn.commit()
64
+ return cursor.lastrowid
65
+ except sqlite3.IntegrityError:
66
+ st.error(f"Collection '{name}' already exists!")
67
+ return None
68
+ except sqlite3.Error as e:
69
+ st.error(f"Error creating collection: {e}")
70
+ return None
71
+
72
+ def get_collections(conn: sqlite3.Connection) -> List[Dict]:
73
+ """
74
+ Get all collections with their document counts.
75
+ """
76
+ with db_lock:
77
+ try:
78
+ cursor = conn.cursor()
79
+ cursor.execute('''
80
+ SELECT
81
+ c.id,
82
+ c.name,
83
+ c.description,
84
+ c.created_at,
85
+ COUNT(dc.document_id) as doc_count
86
+ FROM collections c
87
+ LEFT JOIN document_collections dc ON c.id = dc.collection_id
88
+ GROUP BY c.id
89
+ ORDER BY c.name
90
+ ''')
91
+
92
+ collections = []
93
+ for row in cursor.fetchall():
94
+ collections.append({
95
+ 'id': row[0],
96
+ 'name': row[1],
97
+ 'description': row[2],
98
+ 'created_at': row[3],
99
+ 'doc_count': row[4]
100
+ })
101
+ return collections
102
+
103
+ except sqlite3.Error as e:
104
+ st.error(f"Error retrieving collections: {e}")
105
+ return []
106
+
107
+ def get_collection_documents(conn: sqlite3.Connection, collection_id: int) -> List[Dict]:
108
+ """
109
+ Get all documents in a specific collection.
110
+ """
111
+ with db_lock:
112
+ try:
113
+ cursor = conn.cursor()
114
+ cursor.execute('''
115
+ SELECT
116
+ d.id,
117
+ d.name,
118
+ d.upload_date,
119
+ d.content
120
+ FROM documents d
121
+ JOIN document_collections dc ON d.id = dc.document_id
122
+ WHERE dc.collection_id = ?
123
+ ORDER BY d.upload_date DESC
124
+ ''', (collection_id,))
125
+
126
+ documents = []
127
+ for row in cursor.fetchall():
128
+ documents.append({
129
+ 'id': row[0],
130
+ 'name': row[1],
131
+ 'upload_date': row[2],
132
+ 'content': row[3]
133
+ })
134
+ return documents
135
+
136
+ except sqlite3.Error as e:
137
+ st.error(f"Error retrieving collection documents: {e}")
138
+ return []
139
+
140
+ def add_document_to_collection(
141
+ conn: sqlite3.Connection,
142
+ document_id: int,
143
+ collection_id: int
144
+ ) -> bool:
145
+ """
146
+ Add a document to a collection.
147
+ Returns True if successful, False otherwise.
148
+ """
149
+ with db_lock:
150
+ try:
151
+ cursor = conn.cursor()
152
+ cursor.execute('''
153
+ INSERT OR IGNORE INTO document_collections (document_id, collection_id)
154
+ VALUES (?, ?)
155
+ ''', (document_id, collection_id))
156
+ conn.commit()
157
+ return True
158
+
159
+ except sqlite3.Error as e:
160
+ st.error(f"Error adding document to collection: {e}")
161
+ return False
162
+
163
+ def remove_document_from_collection(
164
+ conn: sqlite3.Connection,
165
+ document_id: int,
166
+ collection_id: int
167
+ ) -> bool:
168
+ """
169
+ Remove a document from a collection.
170
+ Returns True if successful, False otherwise.
171
+ """
172
+ with db_lock:
173
+ try:
174
+ cursor = conn.cursor()
175
+ cursor.execute('''
176
+ DELETE FROM document_collections
177
+ WHERE document_id = ? AND collection_id = ?
178
+ ''', (document_id, collection_id))
179
+ conn.commit()
180
+ return True
181
+
182
+ except sqlite3.Error as e:
183
+ st.error(f"Error removing document from collection: {e}")
184
+ return False
185
+
186
+ def delete_collection(conn: sqlite3.Connection, collection_id: int) -> bool:
187
+ """
188
+ Delete a collection and all its document associations.
189
+ Returns True if successful, False otherwise.
190
+ """
191
+ with db_lock:
192
+ try:
193
+ cursor = conn.cursor()
194
+ # Delete the collection (cascade will handle document_collections)
195
+ cursor.execute('DELETE FROM collections WHERE id = ?', (collection_id,))
196
+ conn.commit()
197
+ return True
198
+
199
+ except sqlite3.Error as e:
200
+ st.error(f"Error deleting collection: {e}")
201
+ return False
202
+
203
+ def update_collection(
204
+ conn: sqlite3.Connection,
205
+ collection_id: int,
206
+ name: Optional[str] = None,
207
+ description: Optional[str] = None
208
+ ) -> bool:
209
+ """
210
+ Update a collection's details.
211
+ Returns True if successful, False otherwise.
212
+ """
213
+ with db_lock:
214
+ try:
215
+ updates = []
216
+ params = []
217
+
218
+ if name is not None:
219
+ updates.append("name = ?")
220
+ params.append(name)
221
+ if description is not None:
222
+ updates.append("description = ?")
223
+ params.append(description)
224
+
225
+ if not updates:
226
+ return True
227
+
228
+ updates.append("updated_at = CURRENT_TIMESTAMP")
229
+ params.append(collection_id)
230
+
231
+ query = f'''
232
+ UPDATE collections
233
+ SET {', '.join(updates)}
234
+ WHERE id = ?
235
+ '''
236
+
237
+ cursor = conn.cursor()
238
+ cursor.execute(query, params)
239
+ conn.commit()
240
+ return True
241
+
242
+ except sqlite3.Error as e:
243
+ st.error(f"Error updating collection: {e}")
244
+ return False
245
+
246
+ def get_document_collections(conn: sqlite3.Connection, document_id: int) -> List[Dict]:
247
+ """
248
+ Get all collections that a document belongs to.
249
+ """
250
+ with db_lock:
251
+ try:
252
+ cursor = conn.cursor()
253
+ cursor.execute('''
254
+ SELECT
255
+ c.id,
256
+ c.name,
257
+ c.description,
258
+ dc.added_at
259
+ FROM collections c
260
+ JOIN document_collections dc ON c.id = dc.collection_id
261
+ WHERE dc.document_id = ?
262
+ ORDER BY c.name
263
+ ''', (document_id,))
264
+
265
+ collections = []
266
+ for row in cursor.fetchall():
267
+ collections.append({
268
+ 'id': row[0],
269
+ 'name': row[1],
270
+ 'description': row[2],
271
+ 'added_at': row[3]
272
+ })
273
+ return collections
274
+
275
+ except sqlite3.Error as e:
276
+ st.error(f"Error retrieving document collections: {e}")
277
+ return []
278
+
279
+ # Example usage in your main app:
280
+ """
281
+ # Initialize tables
282
+ conn = create_connection('your_database.db')
283
+ create_collection_tables(conn)
284
+
285
+ # Create a new collection
286
+ collection_id = create_collection(conn, "RFP 2024", "RFP documents for 2024 projects")
287
+
288
+ # Add a document to the collection
289
+ add_document_to_collection(conn, document_id, collection_id)
290
+
291
+ # Get all collections
292
+ collections = get_collections(conn)
293
+
294
+ # Get documents in a collection
295
+ documents = get_collection_documents(conn, collection_id)
296
+ """