Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit 197d5a8

Browse files
authored
added &! operator
1 parent 13e7d7e commit 197d5a8

File tree

6 files changed

+630
-437
lines changed

6 files changed

+630
-437
lines changed

meme2sql.java

Lines changed: 141 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,205 +1,203 @@
11
import java.sql.*;
2-
import java.util.*;
3-
import java.util.regex.Matcher;
4-
import java.util.regex.Pattern;
5-
import java.util.stream.Collectors;
2+
import java.util.ArrayList;
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
66

77
public class MemeLangQueryProcessor {
88

99
// Database configuration constants
10-
private static final String DB_TYPE = "sqlite3"; // Default to 'sqlite3'. Options: 'sqlite3', 'mysql', 'postgres'
11-
private static final String DB_PATH = "data.sqlite"; // Default path for SQLite3
12-
private static final String DB_HOST = "localhost"; // Host for MySQL/Postgres
13-
private static final String DB_USER = "username"; // Username for MySQL/Postgres
14-
private static final String DB_PASSWORD = "password"; // Password for MySQL/Postgres
15-
private static final String DB_NAME = "database_name"; // Database name for MySQL/Postgres
16-
private static final String DB_TABLE = "meme"; // Default table name for queries
10+
private static final String DB_TYPE = System.getenv().getOrDefault("DB_TYPE", "sqlite3"); // Options: 'sqlite3', 'mysql', 'postgres'
11+
private static final String DB_PATH = System.getenv().getOrDefault("DB_PATH", "data.sqlite"); // Path for SQLite3
12+
private static final String DB_HOST = System.getenv().getOrDefault("DB_HOST", "localhost"); // Host for MySQL/Postgres
13+
private static final String DB_USER = System.getenv().getOrDefault("DB_USER", "username"); // Username for MySQL/Postgres
14+
private static final String DB_PASSWORD = System.getenv().getOrDefault("DB_PASSWORD", "password"); // Password for MySQL/Postgres
15+
private static final String DB_NAME = System.getenv().getOrDefault("DB_NAME", "database_name"); // Database name for MySQL/Postgres
16+
private static final String DB_TABLE = System.getenv().getOrDefault("DB_TABLE", "meme"); // Default table name for queries
1717

18-
public static void main(String[] args) {
19-
String memelangQuery = ".admire & .explore & :amsterdam | .letter:ord < 2 & :bangkok";
20-
List<Map<String, Object>> results = memeQuery(memelangQuery);
21-
System.out.println(memeOut(results));
22-
}
18+
private static Connection connection = null;
2319

2420
// Main function to process memelang query and return results
25-
public static List<Map<String, Object>> memeQuery(String memelangQuery) {
26-
// Remove all whitespace from the input
27-
memelangQuery = memelangQuery.replaceAll("\\s+", "");
28-
29-
try {
30-
// Translate memelang to SQL
31-
String sqlQuery = memeSQL(memelangQuery);
32-
33-
// Call the appropriate database function based on DB_TYPE constant
34-
switch (DB_TYPE) {
35-
case "sqlite3":
36-
return memeSQLite3(sqlQuery);
37-
case "mysql":
38-
return memeMySQL(sqlQuery);
39-
case "postgres":
40-
return memePostgres(sqlQuery);
41-
default:
42-
throw new IllegalArgumentException("Unsupported database type: " + DB_TYPE);
43-
}
44-
} catch (Exception e) {
45-
Map<String, Object> error = new HashMap<>();
46-
error.put("error", e.getMessage());
47-
return Collections.singletonList(error);
48-
}
21+
public static List<Map<String, Object>> memeQuery(String memelangQuery) throws SQLException {
22+
String sqlQuery = memeSQL(memelangQuery);
23+
return executeQuery(sqlQuery);
4924
}
5025

51-
// Function to handle AND, OR conditions and translate to SQL
26+
// Generate SQL from the memelang query
5227
public static String memeSQL(String query) {
53-
// If there are multiple OR clauses, separate each one with a UNION and wrap each in a SELECT statement
54-
if (query.contains("|")) {
55-
String[] clauses = query.split("\\|");
56-
List<String> sqlClauses = Arrays.stream(clauses)
57-
.map(clause -> "SELECT m.* FROM " + DB_TABLE + " m " + memeJunction(clause.trim()))
58-
.collect(Collectors.toList());
59-
return String.join(" UNION ", sqlClauses);
28+
query = query.replaceAll("\\s+", ""); // Remove all whitespace
29+
30+
// Split the query by | for OR conditions
31+
String[] orClauses = query.split("\\|");
32+
StringBuilder sqlClauses = new StringBuilder();
33+
for (String clause : orClauses) {
34+
if (sqlClauses.length() > 0) sqlClauses.append(" UNION ");
35+
sqlClauses.append(memeClause(clause.trim()));
6036
}
37+
return sqlClauses.toString();
38+
}
6139

62-
// If no OR, treat it as a single SELECT query
63-
return "SELECT m.* FROM " + DB_TABLE + " m " + memeJunction(query);
40+
private static String memeClause(String clause) {
41+
// Check for & in the clause for AND conditions
42+
if (clause.contains("&")) {
43+
return "SELECT m.* FROM " + DB_TABLE + " m " + memeJunction(clause);
44+
} else {
45+
// Handle simple clause with no &
46+
ParsedClause result = memeParse(clause);
47+
return "SELECT * FROM " + DB_TABLE + " WHERE " + result.clause;
48+
}
6449
}
6550

66-
// Handle single clause logic for both AND (&) conditions and basic WHERE filtering
67-
public static String memeJunction(String query) {
51+
private static String memeJunction(String query) {
6852
List<String> filters = new ArrayList<>();
53+
List<String> havingConditions = new ArrayList<>();
6954

70-
// Handle AND conditions
71-
if (query.contains("&")) {
72-
String[] clauses = query.split("&");
73-
List<String> havingConditions = new ArrayList<>();
55+
// Split the query by '&' and process each clause
56+
String[] clauses = query.split("&");
57+
for (String clause : clauses) {
58+
clause = clause.trim();
59+
boolean isAndNotCondition = clause.startsWith("!");
60+
if (isAndNotCondition) clause = clause.substring(1);
7461

75-
for (String clause : clauses) {
76-
Map<String, String> result = memeParse(clause.trim());
77-
havingConditions.add("SUM(CASE WHEN " + result.get("clause") + " THEN 1 ELSE 0 END) > 0");
78-
if (!result.get("filter").isEmpty()) {
79-
filters.add("(" + result.get("filter") + ")");
80-
}
81-
}
62+
ParsedClause result = memeParse(clause);
63+
havingConditions.add("SUM(CASE WHEN " + result.clause + " THEN 1 ELSE 0 END) " +
64+
(isAndNotCondition ? "= 0" : "> 0"));
8265

83-
return "JOIN (SELECT aid FROM " + DB_TABLE + " GROUP BY aid HAVING " +
84-
String.join(" AND ", havingConditions) + ") AS aids ON m.aid = aids.aid" +
85-
(!filters.isEmpty() ? " WHERE " + String.join(" OR ", memeFilterGroup(filters)) : "");
66+
if (result.filter != null && !result.filter.isEmpty()) {
67+
filters.add("(" + result.filter + ")");
68+
}
8669
}
8770

88-
// No AND, so it's a single WHERE condition
89-
Map<String, String> result = memeParse(query);
90-
if (!result.get("filter").isEmpty()) {
91-
filters.add("(" + result.get("filter") + ")");
92-
}
93-
return "WHERE " + result.get("clause") +
94-
(!filters.isEmpty() ? " AND " + String.join(" OR ", memeFilterGroup(filters)) : "");
71+
return "JOIN (SELECT aid FROM " + DB_TABLE + " GROUP BY aid HAVING " +
72+
String.join(" AND ", havingConditions) + ") AS aids ON m.aid = aids.aid" +
73+
(filters.isEmpty() ? "" : " WHERE " + String.join(" OR ", memeFilterGroup(filters)));
9574
}
9675

97-
// Function to parse individual components of the memelang query
98-
public static Map<String, String> memeParse(String query) {
99-
String pattern = "^([A-Za-z0-9]*)\\.?([A-Za-z0-9]*):?([A-Za-z0-9]*)?([<>=#]*)?(-?\\d*\\.?\\d*)$";
100-
Pattern regex = Pattern.compile(pattern);
101-
Matcher matcher = regex.matcher(query);
102-
103-
if (matcher.find()) {
104-
String aid = matcher.group(1) != null ? matcher.group(1) : "";
105-
String rid = matcher.group(2) != null ? matcher.group(2) : "";
106-
String bid = matcher.group(3) != null ? matcher.group(3) : "";
107-
String operator = matcher.group(4) != null ? matcher.group(4).replace("#=", "=") : "=";
108-
String qnt = !matcher.group(5).isEmpty() ? matcher.group(5) : "1";
76+
private static ParsedClause memeParse(String query) {
77+
String pattern = "^([A-Za-z0-9]*)\\.([A-Za-z0-9]*):?([A-Za-z0-9]*)?([<>=#]*)?(-?\\d*\\.?\\d*)$";
78+
if (query.matches(pattern)) {
79+
String[] parts = query.split("[:.#]");
80+
String aid = parts.length > 0 ? parts[0] : null;
81+
String rid = parts.length > 1 ? parts[1] : null;
82+
String bid = parts.length > 2 ? parts[2] : null;
83+
String operator = parts.length > 3 ? parts[3].replace("#=", "=") : "=";
84+
String qnt = parts.length > 4 && !parts[4].isEmpty() ? parts[4] : "1";
10985

11086
List<String> conditions = new ArrayList<>();
111-
if (!aid.isEmpty()) conditions.add("aid='" + aid + "'");
112-
if (!rid.isEmpty()) conditions.add("rid='" + rid + "'");
113-
if (!bid.isEmpty()) conditions.add("bid='" + bid + "'");
87+
if (aid != null) conditions.add("aid='" + aid + "'");
88+
if (rid != null) conditions.add("rid='" + rid + "'");
89+
if (bid != null) conditions.add("bid='" + bid + "'");
11490
conditions.add("qnt" + operator + qnt);
11591

11692
List<String> filterConditions = new ArrayList<>();
117-
if (!rid.isEmpty()) filterConditions.add("rid='" + rid + "'");
118-
if (!bid.isEmpty()) filterConditions.add("bid='" + bid + "'");
93+
if (rid != null) filterConditions.add("rid='" + rid + "'");
94+
if (bid != null) filterConditions.add("bid='" + bid + "'");
11995

120-
Map<String, String> result = new HashMap<>();
121-
result.put("clause", "(" + String.join(" AND ", conditions) + ")");
122-
result.put("filter", String.join(" AND ", filterConditions));
123-
return result;
96+
return new ParsedClause(String.join(" AND ", conditions), String.join(" AND ", filterConditions));
12497
} else {
12598
throw new IllegalArgumentException("Invalid memelang format: " + query);
12699
}
127100
}
128101

129-
// Group filters to reduce SQL complexity
130-
public static List<String> memeFilterGroup(List<String> filters) {
102+
private static List<String> memeFilterGroup(List<String> filters) {
103+
List<String> grouped = new ArrayList<>();
131104
List<String> ridValues = new ArrayList<>();
132105
List<String> bidValues = new ArrayList<>();
133106
List<String> complexFilters = new ArrayList<>();
134107

135108
for (String filter : filters) {
136-
Matcher ridMatcher = Pattern.compile("^\\(rid='([A-Za-z0-9]+)'\\)$").matcher(filter);
137-
Matcher bidMatcher = Pattern.compile("^\\(bid='([A-Za-z0-9]+)'\\)$").matcher(filter);
138-
139-
if (ridMatcher.find()) {
140-
ridValues.add(ridMatcher.group(1));
141-
} else if (bidMatcher.find()) {
142-
bidValues.add(bidMatcher.group(1));
109+
if (filter.matches("\\(rid='([A-Za-z0-9]+)'\\)")) {
110+
ridValues.add(filter.split("=")[1].replace("'", "").replace(")", ""));
111+
} else if (filter.matches("\\(bid='([A-Za-z0-9]+)'\\)")) {
112+
bidValues.add(filter.split("=")[1].replace("'", "").replace(")", ""));
143113
} else {
144114
complexFilters.add(filter);
145115
}
146116
}
147117

148-
List<String> grouped = new ArrayList<>();
149-
if (!ridValues.isEmpty()) {
150-
grouped.add("m.rid IN ('" + String.join("','", ridValues) + "')");
151-
}
152-
if (!bidValues.isEmpty()) {
153-
grouped.add("m.bid IN ('" + String.join("','", bidValues) + "')");
154-
}
118+
if (!ridValues.isEmpty()) grouped.add("m.rid IN ('" + String.join("','", ridValues) + "')");
119+
if (!bidValues.isEmpty()) grouped.add("m.bid IN ('" + String.join("','", bidValues) + "')");
155120

156121
grouped.addAll(complexFilters);
157122
return grouped;
158123
}
159124

160-
// SQLite3 database query function
161-
public static List<Map<String, Object>> memeSQLite3(String sqlQuery) throws SQLException {
162-
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
163-
Statement stmt = conn.createStatement();
164-
ResultSet rs = stmt.executeQuery(sqlQuery)) {
125+
private static Connection getConnection() throws SQLException {
126+
if (connection == null || connection.isClosed()) {
127+
switch (DB_TYPE) {
128+
case "sqlite3":
129+
connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
130+
break;
131+
case "mysql":
132+
connection = DriverManager.getConnection("jdbc:mysql://" + DB_HOST + "/" + DB_NAME, DB_USER, DB_PASSWORD);
133+
break;
134+
case "postgres":
135+
connection = DriverManager.getConnection("jdbc:postgresql://" + DB_HOST + "/" + DB_NAME, DB_USER, DB_PASSWORD);
136+
break;
137+
default:
138+
throw new SQLException("Unsupported database type: " + DB_TYPE);
139+
}
140+
}
141+
return connection;
142+
}
143+
144+
private static List<Map<String, Object>> executeQuery(String sqlQuery) throws SQLException {
145+
List<Map<String, Object>> results = new ArrayList<>();
146+
try (Connection conn = getConnection(); PreparedStatement stmt = conn.prepareStatement(sqlQuery); ResultSet rs = stmt.executeQuery()) {
147+
ResultSetMetaData metaData = rs.getMetaData();
148+
int columnCount = metaData.getColumnCount();
165149

166-
List<Map<String, Object>> results = new ArrayList<>();
167150
while (rs.next()) {
168-
ResultSetMetaData md = rs.getMetaData();
169-
int columns = md.getColumnCount();
170-
Map<String, Object> row = new HashMap<>(columns);
171-
for (int i = 1; i <= columns; i++) {
172-
row.put(md.getColumnName(i), rs.getObject(i));
151+
Map<String, Object> row = new HashMap<>();
152+
for (int i = 1; i <= columnCount; i++) {
153+
row.put(metaData.getColumnName(i), rs.getObject(i));
173154
}
174155
results.add(row);
175156
}
176-
return results;
177157
}
158+
return results;
178159
}
179160

180-
// MySQL database query function
181-
public static List<Map<String, Object>> memeMySQL(String sqlQuery) throws SQLException {
182-
try (Connection conn = DriverManager.getConnection("jdbc:mysql://" + DB_HOST + "/" + DB_NAME, DB_USER, DB_PASSWORD);
183-
Statement stmt = conn.createStatement();
184-
ResultSet rs = stmt.executeQuery(sqlQuery)) {
161+
// Class to hold parsed clauses
162+
private static class ParsedClause {
163+
String clause;
164+
String filter;
185165

186-
List<Map<String, Object>> results = new ArrayList<>();
187-
while (rs.next()) {
188-
ResultSetMetaData md = rs.getMetaData();
189-
int columns = md.getColumnCount();
190-
Map<String, Object> row = new HashMap<>(columns);
191-
for (int i = 1; i <= columns; i++) {
192-
row.put(md.getColumnName(i), rs.getObject(i));
193-
}
194-
results.add(row);
166+
ParsedClause(String clause, String filter) {
167+
this.clause = clause;
168+
this.filter = filter;
169+
}
170+
}
171+
172+
// Test function
173+
public static void main(String[] args) {
174+
List<String> queries = List.of(
175+
"ant.admire:amsterdam #= 0",
176+
"ant.believe:cairo",
177+
".admire | .believe"
178+
// Add other test cases as needed
179+
);
180+
181+
for (String query : queries) {
182+
try {
183+
System.out.println("Memelang Query: " + query);
184+
String sqlQuery = memeSQL(query);
185+
System.out.println("Generated SQL: " + sqlQuery);
186+
List<Map<String, Object>> results = memeQuery(query);
187+
System.out.println("Results in Memelang Format:\n" + memeOut(results) + "\n");
188+
} catch (Exception e) {
189+
System.err.println("Error: " + e.getMessage());
195190
}
196-
return results;
197191
}
198192
}
199193

200-
// PostgreSQL database query function
201-
public static List<Map<String, Object>> memePostgres(String sqlQuery) throws SQLException {
202-
String url = "jdbc:postgresql://" + DB_HOST + "/" + DB_NAME;
203-
try (Connection conn = DriverManager.getConnection(url, DB_USER, DB_PASSWORD);
204-
Statement stmt = conn.createStatement();
205-
ResultSet rs =
194+
// Format results to Memelang format
195+
public static String memeOut(List<Map<String, Object>> results) {
196+
StringBuilder output = new StringBuilder();
197+
for (Map<String, Object> row : results) {
198+
output.append(row.get("aid")).append(".").append(row.get("rid")).append(":").append(row.get("bid"))
199+
.append("=").append(row.get("qnt")).append(";\n");
200+
}
201+
return output.toString();
202+
}
203+
}

0 commit comments

Comments
 (0)