1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2024 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Implementation of the 'convert' subcommand.
10 from typing import Set, Any, Union, Optional, Sequence
13 from pathlib import Path
15 from ..errors import UsageError
16 from .args import NominatimArgs
19 class WithAction(argparse.Action):
20 """ Special action that saves a list of flags, given on the command-line
21 as `--with-foo` or `--without-foo`.
23 def __init__(self, option_strings: Sequence[str], dest: Any,
24 default: bool = True, **kwargs: Any) -> None:
26 raise ValueError("nargs not allowed.")
27 if option_strings is None:
28 raise ValueError("Positional parameter not allowed.")
30 self.dest_set = kwargs.pop('dest_set')
31 full_option_strings = []
32 for opt in option_strings:
33 if not opt.startswith('--'):
34 raise ValueError("short-form options not allowed")
36 self.dest_set.add(opt[2:])
37 full_option_strings.append(f"--with-{opt[2:]}")
38 full_option_strings.append(f"--without-{opt[2:]}")
40 super().__init__(full_option_strings, argparse.SUPPRESS, nargs=0, **kwargs)
42 def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
43 values: Union[str, Sequence[Any], None],
44 option_string: Optional[str] = None) -> None:
46 if option_string.startswith('--with-'):
47 self.dest_set.add(option_string[7:])
48 if option_string.startswith('--without-'):
49 self.dest_set.discard(option_string[10:])
53 """ Convert an existing database into a different format. (EXPERIMENTAL)
55 Dump a read-only version of the database in a different format.
56 At the moment only a SQLite database suitable for reverse lookup
60 def __init__(self) -> None:
61 self.options: Set[str] = set()
63 def add_args(self, parser: argparse.ArgumentParser) -> None:
64 parser.add_argument('--format', default='sqlite',
66 help='Format of the output database (must be sqlite currently)')
67 parser.add_argument('--output', '-o', required=True, type=Path,
68 help='File to write the database to.')
69 group = parser.add_argument_group('Switches to define database layout'
70 '(currently no effect)')
71 group.add_argument('--reverse', action=WithAction, dest_set=self.options, default=True,
72 help='Enable/disable support for reverse and lookup API'
73 ' (default: enabled)')
74 group.add_argument('--search', action=WithAction, dest_set=self.options, default=True,
75 help='Enable/disable support for search API (default: disabled)')
76 group.add_argument('--details', action=WithAction, dest_set=self.options, default=True,
77 help='Enable/disable support for details API (default: enabled)')
79 def run(self, args: NominatimArgs) -> int:
80 if args.output.exists():
81 raise UsageError(f"File '{args.output}' already exists. Refusing to overwrite.")
83 if args.format == 'sqlite':
84 from ..tools import convert_sqlite
86 asyncio.run(convert_sqlite.convert(args.project_dir, args.output, self.options))