|
|
@@ -1,10 +1,153 @@
|
|
|
import 'dart:convert';
|
|
|
+import 'dart:io';
|
|
|
+import 'package:archive/archive_io.dart';
|
|
|
import 'package:jiffy/jiffy.dart';
|
|
|
import 'package:myshelf/models/dtinterval.dart';
|
|
|
+import 'package:supabase/supabase.dart';
|
|
|
|
|
|
-List<List<dynamic>> csv2list(String text,
|
|
|
+final Map<String, String> tables = {
|
|
|
+ "secondprgtype.txt": "aclegs_csv",
|
|
|
+ "ExportPGRGPNmois.txt": "pnlegs_csv",
|
|
|
+ "exportPGRGPN.txt": "pnlegs_csv",
|
|
|
+ "exportlicence.txt": "licences_csv",
|
|
|
+};
|
|
|
+
|
|
|
+final Map<String, List<String>> headers = {
|
|
|
+ "secondprgtype.txt": [
|
|
|
+ "leg_no",
|
|
|
+ "fn_carrier",
|
|
|
+ "fn_number",
|
|
|
+ "fn_suffix",
|
|
|
+ "day_of_origin",
|
|
|
+ "ac_owner",
|
|
|
+ "ac_subtype",
|
|
|
+ "ac_version",
|
|
|
+ "ac_registration",
|
|
|
+ "dep_ap_actual",
|
|
|
+ "dep_ap_sched",
|
|
|
+ "dep_dt_est",
|
|
|
+ "dep_sched_dt",
|
|
|
+ "arr_ap_actual",
|
|
|
+ "arr_ap_sched",
|
|
|
+ "arr_dt_est",
|
|
|
+ "arr_sched_dt",
|
|
|
+ "slot_time_actual",
|
|
|
+ "leg_type",
|
|
|
+ "status",
|
|
|
+ "employer_cockpit",
|
|
|
+ "employer_cabin",
|
|
|
+ "cycles",
|
|
|
+ "delay_code_01",
|
|
|
+ "delay_code_02",
|
|
|
+ "delay_code_03",
|
|
|
+ "delay_code_04",
|
|
|
+ "delay_time_01",
|
|
|
+ "delay_time_02",
|
|
|
+ "delay_time_03",
|
|
|
+ "delay_time_04",
|
|
|
+ "subdelay_code_01",
|
|
|
+ "subdelay_code_02",
|
|
|
+ "subdelay_code_03",
|
|
|
+ "subdelay_code_04",
|
|
|
+ "pax_booked_c",
|
|
|
+ "pax_booked_y",
|
|
|
+ "pax_booked_trs_c",
|
|
|
+ "pax_booked_trs_y",
|
|
|
+ "pad_booked_c",
|
|
|
+ "pad_booked_y",
|
|
|
+ "offblock_dt_a",
|
|
|
+ "airborne_dt_a",
|
|
|
+ "landing_dt_a",
|
|
|
+ "onblock_dt_a",
|
|
|
+ "offblock_dt_f",
|
|
|
+ "airborne_dt_f",
|
|
|
+ "landing_dt_f",
|
|
|
+ "onblock_dt_f",
|
|
|
+ "offblock_dt_m",
|
|
|
+ "airborne_dt_m",
|
|
|
+ "landing_dt_m",
|
|
|
+ "onblock_dt_m",
|
|
|
+ "eet",
|
|
|
+ ],
|
|
|
+ "exportPGRGPN.txt": [
|
|
|
+ "date",
|
|
|
+ "tlc",
|
|
|
+ "actype",
|
|
|
+ "al",
|
|
|
+ "fnum",
|
|
|
+ "ddep",
|
|
|
+ "hdep",
|
|
|
+ "ddes",
|
|
|
+ "hdes",
|
|
|
+ "dep",
|
|
|
+ "des",
|
|
|
+ "label",
|
|
|
+ "type",
|
|
|
+ ],
|
|
|
+ "ExportPGRGPNmois.txt": [
|
|
|
+ "date",
|
|
|
+ "tlc",
|
|
|
+ "actype",
|
|
|
+ "al",
|
|
|
+ "fnum",
|
|
|
+ "ddep",
|
|
|
+ "hdep",
|
|
|
+ "ddes",
|
|
|
+ "hdes",
|
|
|
+ "dep",
|
|
|
+ "des",
|
|
|
+ "label",
|
|
|
+ "type",
|
|
|
+ ],
|
|
|
+ "exportlicence.txt": [
|
|
|
+ "tlc",
|
|
|
+ "fname",
|
|
|
+ "mname",
|
|
|
+ "lname",
|
|
|
+ "expire",
|
|
|
+ "ac",
|
|
|
+ "college",
|
|
|
+ "base",
|
|
|
+ ],
|
|
|
+};
|
|
|
+final Map<String, String> scopes = {
|
|
|
+ "secondprgtype.txt": "day_of_origin",
|
|
|
+ "exportPGRGPN.txt": "date",
|
|
|
+ "ExportPGRGPNmois.txt": "date",
|
|
|
+ "exportlicence.txt": "tlc",
|
|
|
+};
|
|
|
+List<Map<String, String?>> createListOfMaps(
|
|
|
+ List<String> headers, List<List<dynamic>> data) {
|
|
|
+ // Initialize an empty list to hold the maps
|
|
|
+ List<Map<String, String?>> result = [];
|
|
|
+
|
|
|
+ // Iterate over each row of data
|
|
|
+ for (var row in data) {
|
|
|
+ // Create a map for the current row
|
|
|
+ Map<String, String?> map = {};
|
|
|
+
|
|
|
+ // Populate the map with header-value pairs
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ if (i < row.length) {
|
|
|
+ // Convert each value to String? and handle null values
|
|
|
+ map[headers[i]] = row[i]
|
|
|
+ ?.toString(); // Use toString() to ensure it's a String or null
|
|
|
+ } else {
|
|
|
+ // If there's no corresponding data, set it as null
|
|
|
+ map[headers[i]] = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add the map to the result list
|
|
|
+ result.add(map);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+List<List<String?>> csv2list(String text,
|
|
|
{bool nulling = true, bool quotes = true, bool trim = true}) {
|
|
|
- List<List<dynamic>> out = [];
|
|
|
+ List<List<String?>> out = [];
|
|
|
final lines = text.split("\n");
|
|
|
for (var line in lines) {
|
|
|
final cols = line.split(",").map((String? e) {
|
|
|
@@ -1079,3 +1222,138 @@ extension StringExtensions on String {
|
|
|
isUtc: true)
|
|
|
: null;
|
|
|
}
|
|
|
+
|
|
|
+class FilesAsData {
|
|
|
+ String? filename;
|
|
|
+ String? updatedAt;
|
|
|
+ String data;
|
|
|
+ FilesAsData({
|
|
|
+ this.filename,
|
|
|
+ this.updatedAt,
|
|
|
+ required this.data,
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+processCsvData(File tempfile, SupabaseClient supabase) async {
|
|
|
+ List<FilesAsData> csvData = [];
|
|
|
+ final filename = tempfile.path.split('/').last;
|
|
|
+ final bytes = await tempfile.readAsBytes();
|
|
|
+ // Check if file is a zip archive
|
|
|
+ String? csvcontent;
|
|
|
+ if (filename.toLowerCase().endsWith('.zip')) {
|
|
|
+ final archive = ZipDecoder().decodeBytes(bytes);
|
|
|
+ for (final file in archive) {
|
|
|
+ if (!file.isFile) continue;
|
|
|
+
|
|
|
+ csvcontent = utf8.decode(file.content as List<int>);
|
|
|
+ csvData.add(FilesAsData(filename: file.name, data: csvcontent));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // For non-zip files, store in extracted folder
|
|
|
+ csvcontent = utf8.decode(bytes);
|
|
|
+ csvData.add(FilesAsData(filename: filename, data: csvcontent));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (final FilesAsData data in csvData) {
|
|
|
+ //inserting data
|
|
|
+ if (tables.keys.contains(data.filename)) {
|
|
|
+ final mapsToInsert =
|
|
|
+ createListOfMaps(headers[data.filename] ?? [], csv2list(data.data));
|
|
|
+ final scopeName = scopes[data.filename!]!;
|
|
|
+ final scopeInNew = mapsToInsert
|
|
|
+ .fold(<String>{}, (t, e) => t..add(e[scopeName] ?? "")).toList();
|
|
|
+
|
|
|
+ final old = await supabase
|
|
|
+ .from(tables[data.filename]!)
|
|
|
+ .select()
|
|
|
+ .inFilter(scopeName, scopeInNew)
|
|
|
+ .limit(100000);
|
|
|
+ // Replace with your actual table name
|
|
|
+ final oldComparable = old
|
|
|
+ .map((e) => filterMapByKeys(e, headers[data.filename] ?? []))
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ List<int> indexToRemove = [];
|
|
|
+ List<int> indexToMaintain = [];
|
|
|
+ for (int i = 0; i < oldComparable.length; i++) {
|
|
|
+ final item = oldComparable[i];
|
|
|
+ final index = findIndex(mapsToInsert, item);
|
|
|
+ if (index != -1) {
|
|
|
+ indexToMaintain.add(i);
|
|
|
+ mapsToInsert.removeAt(index);
|
|
|
+ } else {
|
|
|
+ indexToRemove.add(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ print(
|
|
|
+ " indexToRemove: ${indexToRemove.length} , indexToMaintain: ${indexToMaintain.length}");
|
|
|
+ print("delete from db");
|
|
|
+
|
|
|
+ splitList(indexToRemove.map((e) => old[e]['id']).toList(), 50).forEach(
|
|
|
+ (e) async => await supabase
|
|
|
+ .from(
|
|
|
+ tables[data.filename]!) // Replace with your actual table name
|
|
|
+ .delete()
|
|
|
+ .inFilter('id', e));
|
|
|
+ print("insert in db");
|
|
|
+
|
|
|
+ splitList(mapsToInsert, 50).forEach((e) async => await supabase
|
|
|
+ .from(tables[data.filename]!) // Replace with your actual table name
|
|
|
+ .insert(e));
|
|
|
+ print("end");
|
|
|
+
|
|
|
+ // print(createListOfMaps(headers[data.filename] ?? [], csv2list(data.data)));
|
|
|
+ } else {
|
|
|
+ print("filename: ${data.filename} unknown, not inserted.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool mapEquals(Map<String, dynamic> map1, Map<String, dynamic> map2) {
|
|
|
+ //if (map1.length != map2.length) return false;
|
|
|
+ for (var key in map1.keys) {
|
|
|
+ if (map1[key] != map2[key]) return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+int findIndex(List<dynamic> list, dynamic element) {
|
|
|
+ for (int i = 0; i < list.length; i++) {
|
|
|
+ if (mapEquals(list[i], element)) {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1; // Return -1 if the element is not found
|
|
|
+}
|
|
|
+
|
|
|
+Map<String, dynamic> filterMapByKeys(
|
|
|
+ Map<String, dynamic> originalMap, List<String> keysToInclude) {
|
|
|
+ // Create a new map to hold the filtered results
|
|
|
+ Map<String, dynamic> filteredMap = {};
|
|
|
+
|
|
|
+ // Iterate through the list of keys to include
|
|
|
+ for (String key in keysToInclude) {
|
|
|
+ // Check if the key exists in the original map
|
|
|
+ if (originalMap.containsKey(key)) {
|
|
|
+ filteredMap[key] = originalMap[key]; // Add to the new map
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return filteredMap;
|
|
|
+}
|
|
|
+
|
|
|
+List<List<T>> splitList<T>(List<T> originalList, int maxSize) {
|
|
|
+ List<List<T>> sublists = [];
|
|
|
+
|
|
|
+ for (int i = 0; i < originalList.length; i += maxSize) {
|
|
|
+ // Create a sublist for the current chunk
|
|
|
+ List<T> sublist = originalList.sublist(
|
|
|
+ i,
|
|
|
+ (i + maxSize > originalList.length) ? originalList.length : i + maxSize,
|
|
|
+ );
|
|
|
+ sublists.add(sublist);
|
|
|
+ }
|
|
|
+
|
|
|
+ return sublists;
|
|
|
+}
|