diff --git a/address_finder/api.py b/address_finder/api.py
index b69a4c4..57015ff 100644
--- a/address_finder/api.py
+++ b/address_finder/api.py
@@ -28,28 +28,38 @@ class AddressFinder:
self.dbPath = db_addresses_sqlite_path
print("DB addresses Path : " + self.dbPath)
- def getCommunesFromNameOrZip(self, communeNameOrZip: str) -> list[Commune]:
+ def getCommunesFromNameOrZip(self, communeNameOrZip: str, limit: int = None) -> list[Commune]:
con = sqlite3.connect(self.dbPath)
con.row_factory = sqlite3.Row
cur = con.cursor()
- communes: list[Commune] = []
+
+ # Check if a search limit is specified, make sure it is an integer
+ select_limit = ""
+ if limit is not None:
+ try:
+ select_limit = f"LIMIT {int(limit)}"
+ except ValueError:
+ print("Error, limit arg not a valid int: ", limit)
try:
+ # If no search parameter, select all
if communeNameOrZip is None:
- cur.execute(f"SELECT * from \"{DB_TABLE_INSEE_NAME}\"")
+ cur.execute(
+ f"SELECT * from \"{DB_TABLE_INSEE_NAME}\" {select_limit}")
else:
communeSearch = communeNameOrZip
zipSearch = communeNameOrZip
searchOpertor = "OR"
- regexCommuneAndZip = r"[0-9]{5} .+" # For example: '33000 BO'
+ # Allow search zip and commune at the same time, in the format "29530 PLO"
+ regexCommuneAndZip = r"[0-9]{5} .+"
if re.match(regexCommuneAndZip, communeNameOrZip):
splitSearch = communeNameOrZip.split(' ')
zipSearch = splitSearch[0]
communeSearch = ' '.join(splitSearch[1:])
searchOpertor = "AND"
cur.execute(
- f"SELECT * from \"{DB_TABLE_INSEE_NAME}\" WHERE {DB_COL_COMMUNE_NAME} LIKE \"%{communeSearch}%\" COLLATE nocase {searchOpertor} {DB_COL_COMMUNE_POSTE} LIKE \"{zipSearch}%\"")
+ f"SELECT * from \"{DB_TABLE_INSEE_NAME}\" WHERE {DB_COL_COMMUNE_NAME} LIKE \"%{communeSearch}%\" COLLATE nocase {searchOpertor} {DB_COL_COMMUNE_POSTE} LIKE \"{zipSearch}%\" {select_limit}")
except sqlite3.OperationalError as err:
print("Error querying DB : {0}".format(err), file=sys.stderr)
return []
@@ -61,13 +71,13 @@ class AddressFinder:
codeInsee=row_obj[DB_COL_COMMUNE_INSEE],
nom=row_obj[DB_COL_COMMUNE_NAME],
codeZip=row_obj[DB_COL_COMMUNE_POSTE])
- # This way we avoid duplicates
+ # This way we avoid duplicates in DB
communesMap[commune["codeInsee"]] = commune
con.close()
return list(communesMap.values())
- def getCommuneFantoirVoies(self, communeInseeCode: str, voieSearch: str = None) -> list[FantoirVoie]:
+ def getCommuneFantoirVoies(self, communeInseeCode: str, voieSearch: str = None, limit: int = None) -> list[FantoirVoie]:
# Extract data from DB
con = sqlite3.connect(self.dbPath)
@@ -84,6 +94,13 @@ class AddressFinder:
# Get JSON payload
+ # Check if a search limit is specified, make sure it is an integer
+ if limit is not None:
+ try:
+ limit = int(limit)
+ except ValueError:
+ print("Error, limit arg not a valid int: ", limit)
+
fantoir_dict = []
# Check if data where found
if data_raw is not None:
@@ -92,19 +109,28 @@ class AddressFinder:
data_dict = json.loads(data.get("value"))
# In extracted JSON data, the interesting payload is behind "value" key
fantoir_dict = data_dict.get("value")
+
+ # Apply search filter if any
if voieSearch is not None:
+ # Can match multiple words, for example "avenue noe" matches "avenue de noes"
regexSearch = r".*"
for expr in voieSearch.split(' '):
regexSearch += r"(?=" + expr + r").*"
regexSearch += r".*"
fantoir_voies_filtered = []
+ nb_match = 0
for voie in fantoir_dict:
for libelle in voie['libelle']:
if re.search(regexSearch, libelle, re.IGNORECASE):
fantoir_voies_filtered.append(voie)
+ nb_match += 1
break
- fantoir_dict = fantoir_voies_filtered
-
+ if limit is not None and nb_match >= limit:
+ break
+ fantoir_dict = fantoir_voies_filtered
+ else:
+ # Apply search limit if any
+ fantoir_dict = fantoir_dict[:limit]
else:
print("Did not found any data matching Insee code " +
str(communeInseeCode))
diff --git a/templates/landing_form.html b/templates/landing_form.html
index 04699ea..c69641d 100644
--- a/templates/landing_form.html
+++ b/templates/landing_form.html
@@ -85,9 +85,9 @@
var voies=[]
var voie=""
function fillCommunes(search='') {
- var api="addresses/communes";
+ var api="addresses/communes?limit=15";
if (search != '') {
- api+="?s="+search;
+ api+="&s="+search;
}
$.ajax({
type: 'GET',
@@ -97,13 +97,10 @@
if (JSON.stringify(data) !== JSON.stringify(communes)){
$("#communes").empty();
communes=data
- for (let i = 0; i < 20; i++) {
- if (! communes[i]) {
- break;
- }
- $("#communes").append("");
- }
+ communes.forEach(commune => {
+ $("#communes").append("");
+ });
}
if (communes.length == 1) {
codeInsee=communes[0].codeInsee;
@@ -119,9 +116,9 @@
var voies=[]
function fillVoies(codeInsee,search='') {
- var api="addresses/fantoirvoies/" + codeInsee;
+ var api="addresses/fantoirvoies/" + codeInsee + '?limit=15';
if (search != '') {
- api+="?s="+search;
+ api+="&s="+search;
}
$.ajax({
type: 'GET',
@@ -131,13 +128,10 @@
if (JSON.stringify(data) !== JSON.stringify(voies)){
$("#voies").empty();
voies=data
- for (let i = 0; i < 20; i++) {
- if (! voies[i]) {
- break;
- }
- $("#voies").append("");
- }
+ voies.forEach(voie => {
+ $("#voies").append("");
+ });
if (voies.length == 1) {
$('#btnTestAdresse').collapse('show');
voie=voies[0].libelle[0]
diff --git a/webapp.py b/webapp.py
index 288be63..3a5ecdf 100644
--- a/webapp.py
+++ b/webapp.py
@@ -33,7 +33,8 @@ def get_form():
@app.route("/addresses/communes", methods=['GET'])
def get_communes():
to_search=request.args.get('s')
- communes=addressFinder.getCommunesFromNameOrZip(to_search)
+ limit=request.args.get('limit')
+ communes=addressFinder.getCommunesFromNameOrZip(to_search,limit)
response = app.response_class(
response=json.dumps(communes),
mimetype='application/json'
@@ -43,7 +44,8 @@ def get_communes():
@app.route("/addresses/fantoirvoies/", methods=['GET'])
def get_fantoir_voies(codeInsee):
to_search=request.args.get('s')
- fantoirVoies=addressFinder.getCommuneFantoirVoies(codeInsee,to_search)
+ limit=request.args.get('limit')
+ fantoirVoies=addressFinder.getCommuneFantoirVoies(codeInsee,to_search,limit)
response = app.response_class(
response=json.dumps(fantoirVoies),
mimetype='application/json'