diff --git a/README.md b/README.md
index 8639ac37741a..08d16048effc 100644
--- a/README.md
+++ b/README.md
@@ -1139,6 +1139,7 @@ Here is a list of template creators:
* GraphQL: @wing328 [:heart:](https://www.patreon.com/wing328)
* Ktorm: @Luiz-Monad
* MySQL: [@ybelenko](https://github.com/ybelenko)
+ * PostgreSQL: [@iri](https://github.com/iri)
* Postman Collection: @gcatanese
* Protocol Buffer: @wing328
* WSDL: @adessoDpd
diff --git a/bin/configs/postgresql-schema-petstore.yaml b/bin/configs/postgresql-schema-petstore.yaml
new file mode 100644
index 000000000000..2ab2773849ba
--- /dev/null
+++ b/bin/configs/postgresql-schema-petstore.yaml
@@ -0,0 +1,5 @@
+generatorName: postgresql-schema
+outputDir: samples/schema/petstore/postgresql
+inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/postgresql-schema
+
diff --git a/bin/utils/openapi-generator-cli.sh b/bin/utils/openapi-generator-cli.sh
old mode 100644
new mode 100755
diff --git a/docs/generators.md b/docs/generators.md
index f3ed0d410525..2d29254e2d49 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -168,6 +168,7 @@ The following generators are available:
* [graphql-schema](generators/graphql-schema.md)
* [ktorm-schema (beta)](generators/ktorm-schema.md)
* [mysql-schema](generators/mysql-schema.md)
+* [postgresql-schema (beta)](generators/postgresql-schema.md)
* [postman-collection (beta)](generators/postman-collection.md)
* [protobuf-schema (beta)](generators/protobuf-schema.md)
* [wsdl-schema (beta)](generators/wsdl-schema.md)
diff --git a/docs/generators/postgresql-schema.md b/docs/generators/postgresql-schema.md
new file mode 100644
index 000000000000..b4959234ae6e
--- /dev/null
+++ b/docs/generators/postgresql-schema.md
@@ -0,0 +1,1031 @@
+---
+title: Documentation for the postgresql-schema Generator
+---
+
+## METADATA
+
+| Property | Value | Notes |
+| -------- | ----- | ----- |
+| generator name | postgresql-schema | pass this to the generate command after -g |
+| generator stability | BETA | |
+| generator type | SCHEMA | |
+| generator language | Postgresql | |
+| generator default templating engine | mustache | |
+| helpTxt | Generates a PostgreSQL schema based on the schema defined in the OpenAPI specification (v2, v3) | |
+
+## CONFIG OPTIONS
+These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|defaultDatabaseName|Database name that will be used for all generated PostgreSQL DDL and DML statements.| ||
+|idAutoIncEnabled|If `true`, generates autoincrement PostgreSQL types `SERIAL` and `BIGSERIAL` for `int32` and `int64` respectively for integer fields with name 'id'.| |false|
+|identifierNamingConvention|Naming convention of PostgreSQL idebntifiers (table names and column names).|
**snake_case**
Transform named to 'snake_case'.
**original**
Leave original names as in `YAML` file.
|snake_case|
+|jsonDataType|Use of PostgreSQL data types for complex model properties.|
**json**
Generate `JSON` fields. Value is stored in `JSON` data type field as human-readable text. Value compliance with JSON standard is checked.
**jsonb**
Generate `JSONB` fields. Value is stored in `JSONB` data type field in binary format. `JSONB` data type is generally nore efficient than `JSON` but it is not human-readable. Value compliance with JSON standard is checked.
**off**
Generate `TEXT` fields. Just store the value as plain text. Value compliance with JSON standard is not checked.
|json|
+|namedParametersEnabled|Generates query examples with named variables in value placeholders (eg.`:name`,`:quantity`) if `true`. Otherwise, generates question marks `?` in value placeholders.| |false|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+
+
+## LANGUAGE PRIMITIVES
+
+
+
BigDecimal
+
ByteArray
+
Date
+
DateTime
+
URI
+
UUID
+
bool
+
boolean
+
byte
+
char
+
date
+
double
+
file
+
float
+
int
+
integer
+
long
+
mixed
+
number
+
short
+
string
+
void
+
+
+## RESERVED WORDS
+
+
+
a
+
abort
+
abs
+
absent
+
absolute
+
access
+
according
+
acos
+
action
+
ada
+
add
+
admin
+
after
+
aggregate
+
all
+
allocate
+
also
+
alter
+
always
+
analyse
+
analyze
+
and
+
any
+
any_value
+
are
+
array
+
array_agg
+
array_max_cardinality
+
as
+
asc
+
asensitive
+
asin
+
assertion
+
assignment
+
asymmetric
+
at
+
atan
+
atomic
+
attach
+
attribute
+
attributes
+
authorization
+
avg
+
backward
+
base64
+
before
+
begin
+
begin_frame
+
begin_partition
+
bernoulli
+
between
+
bigint
+
binary
+
bit
+
bit_length
+
blob
+
blocked
+
bom
+
boolean
+
both
+
breadth
+
btrim
+
by
+
c
+
cache
+
call
+
called
+
cardinality
+
cascade
+
cascaded
+
case
+
cast
+
catalog
+
catalog_name
+
ceil
+
ceiling
+
chain
+
chaining
+
char
+
char_length
+
character
+
character_length
+
character_set_catalog
+
character_set_name
+
character_set_schema
+
characteristics
+
characters
+
check
+
checkpoint
+
class
+
class_origin
+
classifier
+
clob
+
close
+
cluster
+
coalesce
+
cobol
+
collate
+
collation
+
collation_catalog
+
collation_name
+
collation_schema
+
collect
+
column
+
column_name
+
columns
+
command_function
+
command_function_code
+
comment
+
comments
+
commit
+
committed
+
compression
+
concurrently
+
condition
+
condition_number
+
conditional
+
configuration
+
conflict
+
connect
+
connection
+
connection_name
+
constraint
+
constraint_catalog
+
constraint_name
+
constraint_schema
+
constraints
+
constructor
+
contains
+
content
+
continue
+
control
+
conversion
+
convert
+
copartition
+
copy
+
corr
+
corresponding
+
cos
+
cosh
+
cost
+
count
+
covar_pop
+
covar_samp
+
create
+
cross
+
csv
+
cube
+
cume_dist
+
current
+
current_catalog
+
current_date
+
current_default_transform_group
+
current_path
+
current_role
+
current_row
+
current_schema
+
current_time
+
current_timestamp
+
current_transform_group_for_type
+
current_user
+
cursor
+
cursor_name
+
cycle
+
data
+
database
+
datalink
+
date
+
datetime_interval_code
+
datetime_interval_precision
+
day
+
db
+
deallocate
+
dec
+
decfloat
+
decimal
+
declare
+
default
+
defaults
+
deferrable
+
deferred
+
define
+
defined
+
definer
+
degree
+
delete
+
delimiter
+
delimiters
+
dense_rank
+
depends
+
depth
+
deref
+
derived
+
desc
+
describe
+
descriptor
+
detach
+
deterministic
+
diagnostics
+
dictionary
+
disable
+
discard
+
disconnect
+
dispatch
+
distinct
+
dlnewcopy
+
dlpreviouscopy
+
dlurlcomplete
+
dlurlcompleteonly
+
dlurlcompletewrite
+
dlurlpath
+
dlurlpathonly
+
dlurlpathwrite
+
dlurlscheme
+
dlurlserver
+
dlvalue
+
do
+
document
+
domain
+
double
+
drop
+
dynamic
+
dynamic_function
+
dynamic_function_code
+
each
+
element
+
else
+
empty
+
enable
+
encoding
+
encrypted
+
end
+
end-exec
+
end_frame
+
end_partition
+
enforced
+
enum
+
equals
+
error
+
escape
+
event
+
every
+
except
+
exception
+
exclude
+
excluding
+
exclusive
+
exec
+
execute
+
exists
+
exp
+
explain
+
expression
+
extension
+
external
+
extract
+
false
+
family
+
fetch
+
file
+
filter
+
final
+
finalize
+
finish
+
first
+
first_value
+
flag
+
float
+
floor
+
following
+
for
+
force
+
foreign
+
format
+
fortran
+
forward
+
found
+
frame_row
+
free
+
freeze
+
from
+
fs
+
fulfill
+
full
+
function
+
functions
+
fusion
+
g
+
general
+
generated
+
get
+
global
+
go
+
goto
+
grant
+
granted
+
greatest
+
group
+
grouping
+
groups
+
handler
+
having
+
header
+
hex
+
hierarchy
+
hold
+
hour
+
id
+
identity
+
if
+
ignore
+
ilike
+
immediate
+
immediately
+
immutable
+
implementation
+
implicit
+
import
+
in
+
include
+
including
+
increment
+
indent
+
index
+
indexes
+
indicator
+
inherit
+
inherits
+
initial
+
initially
+
inline
+
inner
+
inout
+
input
+
insensitive
+
insert
+
instance
+
instantiable
+
instead
+
int
+
integer
+
integrity
+
intersect
+
intersection
+
interval
+
into
+
invoker
+
is
+
isnull
+
isolation
+
join
+
json
+
json_array
+
json_arrayagg
+
json_exists
+
json_object
+
json_objectagg
+
json_query
+
json_scalar
+
json_serialize
+
json_table
+
json_table_primitive
+
json_value
+
k
+
keep
+
key
+
key_member
+
key_type
+
keys
+
label
+
lag
+
language
+
large
+
last
+
last_value
+
lateral
+
lead
+
leading
+
leakproof
+
least
+
left
+
length
+
level
+
library
+
like
+
like_regex
+
limit
+
link
+
listagg
+
listen
+
ln
+
load
+
local
+
localtime
+
localtimestamp
+
location
+
locator
+
lock
+
locked
+
log
+
log10
+
logged
+
lower
+
lpad
+
ltrim
+
m
+
map
+
mapping
+
match
+
match_number
+
match_recognize
+
matched
+
matches
+
materialized
+
max
+
maxvalue
+
measures
+
member
+
merge
+
merge_action
+
message_length
+
message_octet_length
+
message_text
+
method
+
min
+
minute
+
minvalue
+
mod
+
mode
+
modifies
+
module
+
month
+
more
+
move
+
multiset
+
mumps
+
name
+
names
+
namespace
+
national
+
natural
+
nchar
+
nclob
+
nested
+
nesting
+
new
+
next
+
nfc
+
nfd
+
nfkc
+
nfkd
+
nil
+
no
+
none
+
normalize
+
normalized
+
not
+
nothing
+
notify
+
notnull
+
nowait
+
nth_value
+
ntile
+
null
+
null_ordering
+
nullable
+
nullif
+
nulls
+
number
+
numeric
+
object
+
occurrence
+
occurrences_regex
+
octet_length
+
octets
+
of
+
off
+
offset
+
oids
+
old
+
omit
+
on
+
one
+
only
+
open
+
operator
+
option
+
options
+
or
+
order
+
ordering
+
ordinality
+
others
+
out
+
outer
+
output
+
over
+
overflow
+
overlaps
+
overlay
+
overriding
+
owned
+
owner
+
p
+
pad
+
parallel
+
parameter
+
parameter_mode
+
parameter_name
+
parameter_ordinal_position
+
parameter_specific_catalog
+
parameter_specific_name
+
parameter_specific_schema
+
parser
+
partial
+
partition
+
pascal
+
pass
+
passing
+
passthrough
+
password
+
past
+
path
+
pattern
+
per
+
percent
+
percent_rank
+
percentile_cont
+
percentile_disc
+
period
+
permission
+
permute
+
pipe
+
placing
+
plan
+
plans
+
pli
+
policy
+
portion
+
position
+
position_regex
+
power
+
precedes
+
preceding
+
precision
+
prepare
+
prepared
+
preserve
+
prev
+
primary
+
prior
+
private
+
privileges
+
procedural
+
procedure
+
procedures
+
program
+
prune
+
ptf
+
public
+
publication
+
quote
+
quotes
+
range
+
rank
+
read
+
reads
+
real
+
reassign
+
recheck
+
recovery
+
recursive
+
ref
+
references
+
referencing
+
refresh
+
regr_avgx
+
regr_avgy
+
regr_count
+
regr_intercept
+
regr_r2
+
regr_slope
+
regr_sxx
+
regr_sxy
+
regr_syy
+
reindex
+
relative
+
release
+
rename
+
repeatable
+
replace
+
replica
+
requiring
+
reset
+
respect
+
restart
+
restore
+
restrict
+
result
+
return
+
returned_cardinality
+
returned_length
+
returned_octet_length
+
returned_sqlstate
+
returning
+
returns
+
revoke
+
right
+
role
+
rollback
+
rollup
+
routine
+
routine_catalog
+
routine_name
+
routine_schema
+
routines
+
row
+
row_count
+
row_number
+
rows
+
rpad
+
rtrim
+
rule
+
running
+
savepoint
+
scalar
+
scale
+
schema
+
schema_name
+
schemas
+
scope
+
scope_catalog
+
scope_name
+
scope_schema
+
scroll
+
search
+
second
+
section
+
security
+
seek
+
select
+
selective
+
self
+
semantics
+
sensitive
+
sequence
+
sequences
+
serializable
+
server
+
server_name
+
session
+
session_user
+
set
+
setof
+
sets
+
share
+
show
+
similar
+
simple
+
sin
+
sinh
+
size
+
skip
+
smallint
+
snapshot
+
some
+
sort_direction
+
source
+
space
+
specific
+
specific_name
+
specifictype
+
sql
+
sqlcode
+
sqlerror
+
sqlexception
+
sqlstate
+
sqlwarning
+
sqrt
+
stable
+
standalone
+
start
+
state
+
statement
+
static
+
statistics
+
stddev_pop
+
stddev_samp
+
stdin
+
stdout
+
storage
+
stored
+
strict
+
string
+
strip
+
structure
+
style
+
subclass_origin
+
submultiset
+
subscription
+
subset
+
substring
+
substring_regex
+
succeeds
+
sum
+
support
+
symmetric
+
sysid
+
system
+
system_time
+
system_user
+
t
+
table
+
table_name
+
tables
+
tablesample
+
tablespace
+
tan
+
tanh
+
target
+
temp
+
template
+
temporary
+
text
+
then
+
through
+
ties
+
time
+
timestamp
+
timezone_hour
+
timezone_minute
+
to
+
token
+
top_level_count
+
trailing
+
transaction
+
transaction_active
+
transactions_committed
+
transactions_rolled_back
+
transform
+
transforms
+
translate
+
translate_regex
+
translation
+
treat
+
trigger
+
trigger_catalog
+
trigger_name
+
trigger_schema
+
trim
+
trim_array
+
true
+
truncate
+
trusted
+
type
+
types
+
uescape
+
unbounded
+
uncommitted
+
unconditional
+
under
+
unencrypted
+
union
+
unique
+
unknown
+
unlink
+
unlisten
+
unlogged
+
unmatched
+
unnamed
+
unnest
+
until
+
untyped
+
update
+
upper
+
uri
+
usage
+
user
+
user_defined_type_catalog
+
user_defined_type_code
+
user_defined_type_name
+
user_defined_type_schema
+
using
+
utf16
+
utf32
+
utf8
+
vacuum
+
valid
+
validate
+
validator
+
value
+
value_of
+
values
+
var_pop
+
var_samp
+
varbinary
+
varchar
+
variadic
+
varying
+
verbose
+
version
+
versioning
+
view
+
views
+
volatile
+
when
+
whenever
+
where
+
whitespace
+
width_bucket
+
window
+
with
+
within
+
without
+
work
+
wrapper
+
write
+
xml
+
xmlagg
+
xmlattributes
+
xmlbinary
+
xmlcast
+
xmlcomment
+
xmlconcat
+
xmldeclaration
+
xmldocument
+
xmlelement
+
xmlexists
+
xmlforest
+
xmliterate
+
xmlnamespaces
+
xmlparse
+
xmlpi
+
xmlquery
+
xmlroot
+
xmlschema
+
xmlserialize
+
xmltable
+
xmltext
+
xmlvalidate
+
year
+
yes
+
zone
+
+
+## FEATURE SET
+
+
+### Client Modification Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasePath|✗|ToolingExtension
+|Authorizations|✗|ToolingExtension
+|UserAgent|✗|ToolingExtension
+|MockServer|✗|ToolingExtension
+
+### Data Type Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Custom|✗|OAS2,OAS3
+|Int32|✓|OAS2,OAS3
+|Int64|✓|OAS2,OAS3
+|Float|✓|OAS2,OAS3
+|Double|✓|OAS2,OAS3
+|Decimal|✓|ToolingExtension
+|String|✓|OAS2,OAS3
+|Byte|✓|OAS2,OAS3
+|Binary|✓|OAS2,OAS3
+|Boolean|✓|OAS2,OAS3
+|Date|✓|OAS2,OAS3
+|DateTime|✓|OAS2,OAS3
+|Password|✓|OAS2,OAS3
+|File|✓|OAS2
+|Uuid|✗|
+|Array|✓|OAS2,OAS3
+|Null|✗|OAS3
+|AnyType|✗|OAS2,OAS3
+|Object|✓|OAS2,OAS3
+|Maps|✓|ToolingExtension
+|CollectionFormat|✓|OAS2
+|CollectionFormatMulti|✓|OAS2
+|Enum|✓|OAS2,OAS3
+|ArrayOfEnum|✓|ToolingExtension
+|ArrayOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
+|ArrayOfCollectionOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfEnum|✓|ToolingExtension
+|MapOfEnum|✓|ToolingExtension
+|MapOfModel|✓|ToolingExtension
+|MapOfCollectionOfPrimitives|✓|ToolingExtension
+|MapOfCollectionOfModel|✓|ToolingExtension
+|MapOfCollectionOfEnum|✓|ToolingExtension
+
+### Documentation Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Readme|✓|ToolingExtension
+|Model|✓|ToolingExtension
+|Api|✓|ToolingExtension
+
+### Global Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Host|✓|OAS2,OAS3
+|BasePath|✓|OAS2,OAS3
+|Info|✓|OAS2,OAS3
+|Schemes|✗|OAS2,OAS3
+|PartialSchemes|✓|OAS2,OAS3
+|Consumes|✓|OAS2
+|Produces|✓|OAS2
+|ExternalDocumentation|✓|OAS2,OAS3
+|Examples|✓|OAS2,OAS3
+|XMLStructureDefinitions|✗|OAS2,OAS3
+|MultiServer|✗|OAS3
+|ParameterizedServer|✗|OAS3
+|ParameterStyling|✗|OAS3
+|Callbacks|✗|OAS3
+|LinkObjects|✗|OAS3
+
+### Parameter Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Path|✓|OAS2,OAS3
+|Query|✓|OAS2,OAS3
+|Header|✓|OAS2,OAS3
+|Body|✓|OAS2
+|FormUnencoded|✓|OAS2
+|FormMultipart|✓|OAS2
+|Cookie|✓|OAS3
+
+### Schema Support Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Simple|✓|OAS2,OAS3
+|Composite|✓|OAS2,OAS3
+|Polymorphism|✗|OAS2,OAS3
+|Union|✗|OAS3
+|allOf|✗|OAS2,OAS3
+|anyOf|✗|OAS3
+|oneOf|✗|OAS3
+|not|✗|OAS3
+
+### Security Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasicAuth|✗|OAS2,OAS3
+|ApiKey|✗|OAS2,OAS3
+|OpenIDConnect|✗|OAS3
+|BearerToken|✗|OAS3
+|OAuth2_Implicit|✗|OAS2,OAS3
+|OAuth2_Password|✗|OAS2,OAS3
+|OAuth2_ClientCredentials|✗|OAS2,OAS3
+|OAuth2_AuthorizationCode|✗|OAS2,OAS3
+|SignatureAuth|✗|OAS3
+|AWSV4Signature|✗|ToolingExtension
+
+### Wire Format Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|JSON|✗|OAS2,OAS3
+|XML|✗|OAS2,OAS3
+|PROTOBUF|✗|ToolingExtension
+|Custom|✗|OAS2,OAS3
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/GeneratorLanguage.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/GeneratorLanguage.java
index a75901cd54e9..bbbd8fe1b725 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/GeneratorLanguage.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/GeneratorLanguage.java
@@ -30,7 +30,7 @@ public enum GeneratorLanguage {
JAVASCRIPT("Javascript"), GRAPH_QL("GraphQL"), GROOVY("Groovy"),
HASKELL("Haskell"), HTTP("Jetbrains HTTP Client (HTTP/REST)"), TYPESCRIPT("Typescript"), K_SIX("k6"), KOTLIN("Kotlin"),
KTORM("Ktorm"), LUA("Lua"), MYSQL("Mysql"), NIM("Nim"),
- OBJECTIVE_C("Objective-C"), OCAML("OCaml"), PERL("Perl"), PHP("PHP"),
+ OBJECTIVE_C("Objective-C"), OCAML("OCaml"), PERL("Perl"), PHP("PHP"), POSTGRESQL("Postgresql"),
POWERSHELL("PowerShell"), PROTOBUF("Protocol Buffers (Protobuf)"), PYTHON("Python"),
R("R"), RUBY("Ruby"), RUST("Rust"), SCALA("Scala"), SWIFT("Swift"),
WSDL("Web Services Description Language (WSDL)"), JULIA("Julia"), XOJO("Xojo");
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostgresqlSchemaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostgresqlSchemaCodegen.java
new file mode 100644
index 000000000000..5910be7699ab
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PostgresqlSchemaCodegen.java
@@ -0,0 +1,1473 @@
+/*
+ * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.model.ModelMap;
+import org.openapitools.codegen.model.ModelsMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.io.File;
+
+import static org.openapitools.codegen.utils.StringUtils.underscore;
+
+@SuppressWarnings("unchecked")
+public class PostgresqlSchemaCodegen extends DefaultCodegen {
+ private final Logger LOGGER = LoggerFactory.getLogger(PostgresqlSchemaCodegen.class);
+
+ public static final String VENDOR_EXTENSION_POSTGRESQL_SCHEMA = "x-postgresql-schema";
+ public static final String DEFAULT_DATABASE_NAME = "defaultDatabaseName";
+ public static final String JSON_DATA_TYPE = "jsonDataType";
+ public static final String IDENTIFIER_NAMING_CONVENTION = "identifierNamingConvention";
+ public static final String NAMED_PARAMETERS_ENABLED = "namedParametersEnabled";
+ public static final String ID_AUTOINC_ENABLED = "idAutoIncEnabled";
+ public static final Integer ENUM_MAX_ELEMENTS = 65535;
+ public static final Integer IDENTIFIER_MAX_LENGTH = 63;
+
+ protected Vector postgresqlNumericTypes = new Vector<>(Arrays.asList(
+ "SMALLINT", "INTEGER", "INT", "BIGINT", "DECIMAL", "NUMERIC", "REAL", "DOUBLE PRECISION", "SMALLSERIAL",
+ "SERIAL",
+ "BIGSERIAL"));
+
+ protected Vector postgresqlDateAndTimeTypes = new Vector<>(Arrays.asList(
+ "DATE", "TIME", "TIME WITH TIME ZONE", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "INTERVAL"));
+
+ protected Vector postgresqlStringTypes = new Vector<>(Arrays.asList(
+ "CHAR", "VARCHAR", "TEXT"));
+
+ protected Vector postgresqlSpatialTypes = new Vector<>(Arrays.asList(
+ "POINT", "LINE", "LSEG", "BOX", "PATH", "POLYGON", "CIRCLE"));
+
+ /**
+ * Returns default database name for all PostgreSQL queries
+ * This value must be used with backticks only, e.g. `database_name`
+ */
+ @Getter
+ protected String defaultDatabaseName = "", databaseNamePrefix = "", databaseNameSuffix = "_db";
+ protected String tableNamePrefix = "tbl_", tableNameSuffix = "";
+ protected String columnNamePrefix = "col_", columnNameSuffix = "";
+ /**
+ * Which type of JSON data types will be used.
+ * JSON data type requires PostgreSQL version 9.4 or newer
+ */
+ @Getter
+ @Setter
+ protected String jsonDataType = "json";
+ /**
+ * Whether named parameters enabled or disabled in prepared SQLs
+ */
+ @Getter
+ @Setter
+ protected Boolean namedParametersEnabled = false;
+ /**
+ * Returns identifier naming convention for table names and column names.
+ */
+ @Getter
+ protected String identifierNamingConvention = "snake_case";
+ /**
+ * Whether autoincrement feature enabled for integer 'id' fields
+ */
+ @Getter
+ @Setter
+ protected Boolean idAutoIncEnabled = false;
+
+ public PostgresqlSchemaCodegen() {
+ super();
+
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
+ .stability(Stability.BETA)
+ .build();
+
+ modifyFeatureSet(features -> features
+ .includeDocumentationFeatures(DocumentationFeature.Readme)
+ .wireFormatFeatures(EnumSet.noneOf(WireFormatFeature.class))
+ .securityFeatures(EnumSet.noneOf(SecurityFeature.class))
+ .excludeGlobalFeatures(
+ GlobalFeature.XMLStructureDefinitions,
+ GlobalFeature.Callbacks,
+ GlobalFeature.LinkObjects,
+ GlobalFeature.ParameterStyling)
+ .excludeSchemaSupportFeatures(
+ SchemaSupportFeature.Polymorphism)
+ .clientModificationFeatures(EnumSet.noneOf(ClientModificationFeature.class)));
+ // clear import mapping (from default generator) as postgresql does not use
+ // import directives
+ importMapping.clear();
+
+ setModelPackage("Model");
+ modelTemplateFiles.put("query_examples.mustache", ".sql");
+
+ // https://www.postgresql.org/docs/17/sql-keywords-appendix.html
+ setReservedWordsLowerCase(
+ Arrays.asList(
+ // SQL reserved words
+ "A", "ABORT", "ABS", "ABSENT", "ABSOLUTE", "ACCESS", "ACCORDING", "ACOS", "ACTION", "ADA",
+ "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALL", "ALLOCATE", "ALSO", "ALTER", "ALWAYS", "ANALYSE",
+ "ANALYZE", "AND", "ANY", "ANY_VALUE", "ARE", "ARRAY", "ARRAY_AGG", "ARRAY_MAX_CARDINALITY",
+ "AS", "ASC", "ASENSITIVE", "ASIN", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATAN",
+ "ATOMIC", "ATTACH", "ATTRIBUTE", "ATTRIBUTES", "AUTHORIZATION", "AVG", "BACKWARD", "BASE64",
+ "BEFORE", "BEGIN", "BEGIN_FRAME", "BEGIN_PARTITION", "BERNOULLI", "BETWEEN", "BIGINT", "BINARY",
+ "BIT", "BIT_LENGTH", "BLOB", "BLOCKED", "BOM", "BOOLEAN", "BOTH", "BREADTH", "BTRIM", "BY", "C",
+ "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG",
+ "CATALOG_NAME", "CEIL", "CEILING", "CHAIN", "CHAINING", "CHAR", "CHARACTER", "CHARACTERISTICS",
+ "CHARACTERS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME",
+ "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", "CHECK", "CHECKPOINT", "CLASS", "CLASSIFIER",
+ "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION",
+ "COLLATION_CATALOG", "COLLATION_NAME", "COLLATION_SCHEMA", "COLLECT", "COLUMN", "COLUMNS",
+ "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMENTS", "COMMIT",
+ "COMMITTED", "COMPRESSION", "CONCURRENTLY", "CONDITION", "CONDITIONAL", "CONDITION_NUMBER",
+ "CONFIGURATION", "CONFLICT", "CONNECT", "CONNECTION", "CONNECTION_NAME", "CONSTRAINT",
+ "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR",
+ "CONTAINS", "CONTENT", "CONTINUE", "CONTROL", "CONVERSION", "CONVERT", "COPARTITION", "COPY",
+ "CORR", "CORRESPONDING", "COS", "COSH", "COST", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE",
+ "CROSS", "CSV", "CUBE", "CUME_DIST", "CURRENT", "CURRENT_CATALOG", "CURRENT_DATE",
+ "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_ROW",
+ "CURRENT_SCHEMA", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_TRANSFORM_GROUP_FOR_TYPE",
+ "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATA", "DATABASE", "DATALINK", "DATE",
+ "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DB", "DEALLOCATE", "DEC",
+ "DECFLOAT", "DECIMAL", "DECLARE", "DEFAULT", "DEFAULTS", "DEFERRABLE", "DEFERRED", "DEFINE",
+ "DEFINED", "DEFINER", "DEGREE", "DELETE", "DELIMITER", "DELIMITERS", "DENSE_RANK", "DEPENDS",
+ "DEPTH", "DEREF", "DERIVED", "DESC", "DESCRIBE", "DESCRIPTOR", "DETACH", "DETERMINISTIC",
+ "DIAGNOSTICS", "DICTIONARY", "DISABLE", "DISCARD", "DISCONNECT", "DISPATCH", "DISTINCT",
+ "DLNEWCOPY", "DLPREVIOUSCOPY", "DLURLCOMPLETE", "DLURLCOMPLETEONLY", "DLURLCOMPLETEWRITE",
+ "DLURLPATH", "DLURLPATHONLY", "DLURLPATHWRITE", "DLURLSCHEME", "DLURLSERVER", "DLVALUE", "DO",
+ "DOCUMENT", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", "DYNAMIC_FUNCTION_CODE",
+ "EACH", "ELEMENT", "ELSE", "EMPTY", "ENABLE", "ENCODING", "ENCRYPTED", "END", "END-EXEC",
+ "END_FRAME", "END_PARTITION", "ENFORCED", "ENUM", "EQUALS", "ERROR", "ESCAPE", "EVENT", "EVERY",
+ "EXCEPT", "EXCEPTION", "EXCLUDE", "EXCLUDING", "EXCLUSIVE", "EXEC", "EXECUTE", "EXISTS", "EXP",
+ "EXPLAIN", "EXPRESSION", "EXTENSION", "EXTERNAL", "EXTRACT", "FALSE", "FAMILY", "FETCH", "FILE",
+ "FILTER", "FINAL", "FINALIZE", "FINISH", "FIRST", "FIRST_VALUE", "FLAG", "FLOAT", "FLOOR",
+ "FOLLOWING", "FOR", "FORCE", "FOREIGN", "FORMAT", "FORTRAN", "FORWARD", "FOUND", "FRAME_ROW",
+ "FREE", "FREEZE", "FROM", "FS", "FULFILL", "FULL", "FUNCTION", "FUNCTIONS", "FUSION", "G",
+ "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GREATEST", "GROUP",
+ "GROUPING", "GROUPS", "HANDLER", "HAVING", "HEADER", "HEX", "HIERARCHY", "HOLD", "HOUR", "ID",
+ "IDENTITY", "IF", "IGNORE", "ILIKE", "IMMEDIATE", "IMMEDIATELY", "IMMUTABLE", "IMPLEMENTATION",
+ "IMPLICIT", "IMPORT", "IN", "INCLUDE", "INCLUDING", "INCREMENT", "INDENT", "INDEX", "INDEXES",
+ "INDICATOR", "INHERIT", "INHERITS", "INITIAL", "INITIALLY", "INLINE", "INNER", "INOUT", "INPUT",
+ "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTEGRITY",
+ "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "INVOKER", "IS", "ISNULL", "ISOLATION", "JOIN",
+ "JSON", "JSON_ARRAY", "JSON_ARRAYAGG", "JSON_EXISTS", "JSON_OBJECT", "JSON_OBJECTAGG",
+ "JSON_QUERY", "JSON_SCALAR", "JSON_SERIALIZE", "JSON_TABLE", "JSON_TABLE_PRIMITIVE",
+ "JSON_VALUE", "K", "KEEP", "KEY", "KEYS", "KEY_MEMBER", "KEY_TYPE", "LABEL", "LAG", "LANGUAGE",
+ "LARGE", "LAST", "LAST_VALUE", "LATERAL", "LEAD", "LEADING", "LEAKPROOF", "LEAST", "LEFT",
+ "LENGTH", "LEVEL", "LIBRARY", "LIKE", "LIKE_REGEX", "LIMIT", "LINK", "LISTAGG", "LISTEN", "LN",
+ "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATION", "LOCATOR", "LOCK", "LOCKED", "LOG",
+ "LOG10", "LOGGED", "LOWER", "LPAD", "LTRIM", "M", "MAP", "MAPPING", "MATCH", "MATCHED",
+ "MATCHES", "MATCH_NUMBER", "MATCH_RECOGNIZE", "MATERIALIZED", "MAX", "MAXVALUE", "MEASURES",
+ "MEMBER", "MERGE", "MERGE_ACTION", "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT",
+ "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODULE", "MONTH", "MORE",
+ "MOVE", "MULTISET", "MUMPS", "NAME", "NAMES", "NAMESPACE", "NATIONAL", "NATURAL", "NCHAR",
+ "NCLOB", "NESTED", "NESTING", "NEW", "NEXT", "NFC", "NFD", "NFKC", "NFKD", "NIL", "NO", "NONE",
+ "NORMALIZE", "NORMALIZED", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NOWAIT", "NTH_VALUE",
+ "NTILE", "NULL", "NULLABLE", "NULLIF", "NULLS", "NULL_ORDERING", "NUMBER", "NUMERIC", "OBJECT",
+ "OCCURRENCE", "OCCURRENCES_REGEX", "OCTETS", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS",
+ "OLD", "OMIT", "ON", "ONE", "ONLY", "OPEN", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER",
+ "ORDERING", "ORDINALITY", "OTHERS", "OUT", "OUTER", "OUTPUT", "OVER", "OVERFLOW", "OVERLAPS",
+ "OVERLAY", "OVERRIDING", "OWNED", "OWNER", "P", "PAD", "PARALLEL", "PARAMETER",
+ "PARAMETER_MODE", "PARAMETER_NAME", "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG",
+ "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARSER", "PARTIAL", "PARTITION",
+ "PASCAL", "PASS", "PASSING", "PASSTHROUGH", "PASSWORD", "PAST", "PATH", "PATTERN", "PER",
+ "PERCENT", "PERCENTILE_CONT", "PERCENTILE_DISC", "PERCENT_RANK", "PERIOD", "PERMISSION",
+ "PERMUTE", "PIPE", "PLACING", "PLAN", "PLANS", "PLI", "POLICY", "PORTION", "POSITION",
+ "POSITION_REGEX", "POWER", "PRECEDES", "PRECEDING", "PRECISION", "PREPARE", "PREPARED",
+ "PRESERVE", "PREV", "PRIMARY", "PRIOR", "PRIVATE", "PRIVILEGES", "PROCEDURAL", "PROCEDURE",
+ "PROCEDURES", "PROGRAM", "PRUNE", "PTF", "PUBLIC", "PUBLICATION", "QUOTE", "QUOTES", "RANGE",
+ "RANK", "READ", "READS", "REAL", "REASSIGN", "RECHECK", "RECOVERY", "RECURSIVE", "REF",
+ "REFERENCES", "REFERENCING", "REFRESH", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT",
+ "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", "REINDEX",
+ "RELATIVE", "RELEASE", "RENAME", "REPEATABLE", "REPLACE", "REPLICA", "REQUIRING", "RESET",
+ "RESPECT", "RESTART", "RESTORE", "RESTRICT", "RESULT", "RETURN", "RETURNED_CARDINALITY",
+ "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNING", "RETURNS",
+ "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINES", "ROUTINE_CATALOG",
+ "ROUTINE_NAME", "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "ROW_NUMBER", "RPAD", "RTRIM",
+ "RULE", "RUNNING", "SAVEPOINT", "SCALAR", "SCALE", "SCHEMA", "SCHEMAS", "SCHEMA_NAME", "SCOPE",
+ "SCOPE_CATALOG", "SCOPE_NAME", "SCOPE_SCHEMA", "SCROLL", "SEARCH", "SECOND", "SECTION",
+ "SECURITY", "SEEK", "SELECT", "SELECTIVE", "SELF", "SEMANTICS", "SENSITIVE", "SEQUENCE",
+ "SEQUENCES", "SERIALIZABLE", "SERVER", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF",
+ "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIN", "SINH", "SIZE", "SKIP", "SMALLINT",
+ "SNAPSHOT", "SOME", "SORT_DIRECTION", "SOURCE", "SPACE", "SPECIFIC", "SPECIFICTYPE",
+ "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQRT",
+ "STABLE", "STANDALONE", "START", "STATE", "STATEMENT", "STATIC", "STATISTICS", "STDDEV_POP",
+ "STDDEV_SAMP", "STDIN", "STDOUT", "STORAGE", "STORED", "STRICT", "STRING", "STRIP", "STRUCTURE",
+ "STYLE", "SUBCLASS_ORIGIN", "SUBMULTISET", "SUBSCRIPTION", "SUBSET", "SUBSTRING",
+ "SUBSTRING_REGEX", "SUCCEEDS", "SUM", "SUPPORT", "SYMMETRIC", "SYSID", "SYSTEM", "SYSTEM_TIME",
+ "SYSTEM_USER", "T", "TABLE", "TABLES", "TABLESAMPLE", "TABLESPACE", "TABLE_NAME", "TAN", "TANH",
+ "TARGET", "TEMP", "TEMPLATE", "TEMPORARY", "TEXT", "THEN", "THROUGH", "TIES", "TIME",
+ "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TOKEN", "TOP_LEVEL_COUNT", "TRAILING",
+ "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE",
+ "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATE_REGEX", "TRANSLATION", "TREAT", "TRIGGER",
+ "TRIGGER_CATALOG", "TRIGGER_NAME", "TRIGGER_SCHEMA", "TRIM", "TRIM_ARRAY", "TRUE", "TRUNCATE",
+ "TRUSTED", "TYPE", "TYPES", "UESCAPE", "UNBOUNDED", "UNCOMMITTED", "UNCONDITIONAL", "UNDER",
+ "UNENCRYPTED", "UNION", "UNIQUE", "UNKNOWN", "UNLINK", "UNLISTEN", "UNLOGGED", "UNMATCHED",
+ "UNNAMED", "UNNEST", "UNTIL", "UNTYPED", "UPDATE", "UPPER", "URI", "USAGE", "USER",
+ "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_CODE", "USER_DEFINED_TYPE_NAME",
+ "USER_DEFINED_TYPE_SCHEMA", "USING", "UTF16", "UTF32", "UTF8", "VACUUM", "VALID", "VALIDATE",
+ "VALIDATOR", "VALUE", "VALUES", "VALUE_OF", "VARBINARY", "VARCHAR", "VARIADIC", "VARYING",
+ "VAR_POP", "VAR_SAMP", "VERBOSE", "VERSION", "VERSIONING", "VIEW", "VIEWS", "VOLATILE", "WHEN",
+ "WHENEVER", "WHERE", "WHITESPACE", "WIDTH_BUCKET", "WINDOW", "WITH", "WITHIN", "WITHOUT",
+ "WORK", "WRAPPER", "WRITE", "XML", "XMLAGG", "XMLATTRIBUTES", "XMLBINARY", "XMLCAST",
+ "XMLCOMMENT", "XMLCONCAT", "XMLDECLARATION", "XMLDOCUMENT", "XMLELEMENT", "XMLEXISTS",
+ "XMLFOREST", "XMLITERATE", "XMLNAMESPACES", "XMLPARSE", "XMLPI", "XMLQUERY", "XMLROOT",
+ "XMLSCHEMA", "XMLSERIALIZE", "XMLTABLE", "XMLTEXT", "XMLVALIDATE", "YEAR", "YES", "ZONE"));
+
+ // primitive data types
+ languageSpecificPrimitives = new HashSet<>(
+ Arrays.asList(
+ "bool",
+ "boolean",
+ "int",
+ "integer",
+ "double",
+ "float",
+ "string",
+ "date",
+ "Date",
+ "DateTime",
+ "long",
+ "short",
+ "char",
+ "ByteArray",
+ "file",
+ "UUID",
+ "URI",
+ "BigDecimal",
+ "mixed",
+ "number",
+ "void",
+ "byte"));
+
+ // https://www.postgresql.org/docs/17/datatype.html
+ typeMapping.put("array", "JSON");
+ typeMapping.put("set", "JSON");
+ typeMapping.put("map", "JSON");
+ typeMapping.put("List", "JSON");
+ typeMapping.put("boolean", "BOOLEAN");
+ typeMapping.put("string", "TEXT");
+ typeMapping.put("int", "INTEGER");
+ typeMapping.put("byte", "TEXT");
+ typeMapping.put("float", "DECIMAL");
+ typeMapping.put("number", "DECIMAL");
+ typeMapping.put("date", "DATE");
+ typeMapping.put("DateTime", "TIMESTAMP");
+ typeMapping.put("long", "BIGINT");
+ typeMapping.put("short", "SMALLINT");
+ typeMapping.put("char", "TEXT");
+ typeMapping.put("double", "DECIMAL");
+ typeMapping.put("object", "JSON");
+ typeMapping.put("integer", "INTEGER");
+ typeMapping.put("ByteArray", "BYTEA");
+ typeMapping.put("file", "BYTEA");
+ typeMapping.put("UUID", "TEXT");
+ typeMapping.put("URI", "TEXT");
+ typeMapping.put("BigDecimal", "DECIMAL");
+
+ embeddedTemplateDir = templateDir = "postgresql-schema";
+
+ // it seems that cli options from DefaultCodegen are useless here
+ cliOptions.clear();
+
+ addOption(DEFAULT_DATABASE_NAME,
+ "Database name that will be used for all generated PostgreSQL DDL and DML statements.", defaultDatabaseName);
+
+ addSwitch(NAMED_PARAMETERS_ENABLED,
+ "Generates query examples with named variables in value placeholders (eg.`:name`,`:quantity`) if `true`. Otherwise, generates question marks `?` in value placeholders.",
+ namedParametersEnabled);
+
+ addSwitch(ID_AUTOINC_ENABLED,
+ "If `true`, generates autoincrement PostgreSQL types `SERIAL` and `BIGSERIAL` for `int32` and `int64` respectively for integer fields with name 'id'.",
+ idAutoIncEnabled);
+
+ // we used to snake_case table/column names, let's add this option
+ CliOption identifierNamingOpt = new CliOption(IDENTIFIER_NAMING_CONVENTION,
+ "Naming convention of PostgreSQL idebntifiers (table names and column names).");
+ identifierNamingOpt.addEnum("snake_case", "Transform named to 'snake_case'.")
+ .addEnum("original", "Leave original names as in `YAML` file.")
+ .setDefault("snake_case");
+ cliOptions.add(identifierNamingOpt);
+
+ CliOption jsonDataTypeOpt = new CliOption(JSON_DATA_TYPE,
+ "Use of PostgreSQL data types for complex model properties.");
+ jsonDataTypeOpt.addEnum("json", "Generate `JSON` fields. Value is stored in `JSON` data type field as human-readable text. Value compliance with JSON standard is checked.")
+ .addEnum("jsonb",
+ "Generate `JSONB` fields. Value is stored in `JSONB` data type field in binary format. `JSONB` data type is generally nore efficient than `JSON` but it is not human-readable. Value compliance with JSON standard is checked.")
+ .addEnum("off", "Generate `TEXT` fields. Just store the value as plain text. Value compliance with JSON standard is not checked.")
+ .setDefault("json");
+ cliOptions.add(jsonDataTypeOpt);
+ }
+
+ @Override
+ public CodegenType getTag() {
+ return CodegenType.SCHEMA;
+ }
+
+ @Override
+ public String getName() {
+ return "postgresql-schema";
+ }
+
+ @Override
+ public String getHelp() {
+ return "Generates a PostgreSQL schema based on the schema defined in the OpenAPI specification (v2, v3)";
+ }
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+
+ if (additionalProperties.containsKey(DEFAULT_DATABASE_NAME)) {
+ if (additionalProperties.get(DEFAULT_DATABASE_NAME).equals("")) {
+ additionalProperties.remove(DEFAULT_DATABASE_NAME);
+ } else {
+ this.setDefaultDatabaseName((String) additionalProperties.get(DEFAULT_DATABASE_NAME));
+ // default database name may be escaped, need to overwrite additional prop
+ additionalProperties.put(DEFAULT_DATABASE_NAME, getDefaultDatabaseName());
+ }
+ }
+
+ if (additionalProperties.containsKey(NAMED_PARAMETERS_ENABLED)) {
+ this.setNamedParametersEnabled(
+ Boolean.valueOf(additionalProperties.get(NAMED_PARAMETERS_ENABLED).toString()));
+ }
+ additionalProperties.put(NAMED_PARAMETERS_ENABLED, getNamedParametersEnabled());
+
+ if (additionalProperties.containsKey(ID_AUTOINC_ENABLED)) {
+ this.setIdAutoIncEnabled(
+ Boolean.valueOf(additionalProperties.get(ID_AUTOINC_ENABLED).toString()));
+ }
+ additionalProperties.put(ID_AUTOINC_ENABLED, getIdAutoIncEnabled());
+
+ if (additionalProperties.containsKey(IDENTIFIER_NAMING_CONVENTION)) {
+ this.setIdentifierNamingConvention((String) additionalProperties.get(IDENTIFIER_NAMING_CONVENTION));
+ }
+
+ if (additionalProperties.containsKey(JSON_DATA_TYPE)) {
+ this.setJsonDataType((String) additionalProperties.get(JSON_DATA_TYPE));
+ }
+
+ // make model src path available in mustache template
+ additionalProperties.put("modelSrcPath", "./" + toSrcPath(modelPackage));
+
+ supportingFiles.add(new SupportingFile(
+ "README.mustache", "", "README.md"));
+ supportingFiles.add(new SupportingFile(
+ "postgresql_schema.mustache", "", "postgresql_schema.sql"));
+ supportingFiles.add(new SupportingFile(
+ "postgresql_schema_oauth2.mustache", "", "postgresql_schema_oauth2.sql"));
+ }
+
+ @Override
+ public ModelsMap postProcessModels(ModelsMap objs) {
+ objs = super.postProcessModels(objs);
+
+ for (ModelMap mo : objs.getModels()) {
+ CodegenModel model = mo.getModel();
+ String modelName = model.getName();
+ String tableName = this.toTableName(modelName);
+ String modelDescription = model.getDescription();
+ Map modelVendorExtensions = model.getVendorExtensions();
+ Map postgresqlSchema = new HashMap<>();
+ Map tableDefinition = new HashMap<>();
+
+ if (this.getIdentifierNamingConvention().equals("snake_case") && !modelName.equals(tableName)) {
+ // add original name in table comment
+ String commentExtra = "Original model name - " + modelName + ".";
+ modelDescription = (modelDescription == null || modelDescription.isEmpty()) ? commentExtra
+ : modelDescription + ". " + commentExtra;
+ }
+
+ if (modelVendorExtensions.containsKey(VENDOR_EXTENSION_POSTGRESQL_SCHEMA)) {
+ // user already specified schema values
+ LOGGER.info("Found vendor extension in '{}' model, autogeneration skipped", modelName);
+ } else {
+ modelVendorExtensions.put(VENDOR_EXTENSION_POSTGRESQL_SCHEMA, postgresqlSchema);
+ postgresqlSchema.put("tableDefinition", tableDefinition);
+ tableDefinition.put("tblName", tableName);
+ tableDefinition.put("tblComment", modelDescription);
+ if (isReservedWord(tableName)) { // Output table name in double quotes if it is a reserved word
+ tableDefinition.put("tblNameQuoted", true);
+ }
+ }
+ }
+ return objs;
+ }
+
+ @Override
+ public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
+ switch (property.getDataType().toUpperCase(Locale.ROOT)) {
+ case "BOOLEAN":
+ processBooleanTypeProperty(model, property);
+ break;
+ case "SMALLINT":
+ case "INTEGER":
+ case "BIGINT":
+ processIntegerTypeProperty(model, property);
+ break;
+ case "DECIMAL":
+ processDecimalTypeProperty(model, property);
+ break;
+ case "TEXT":
+ case "BYTEA":
+ processStringTypeProperty(model, property);
+ break;
+ case "DATE":
+ case "TIMESTAMP":
+ processDateTypeProperty(model, property);
+ break;
+ case "JSON":
+ case "JSONB":
+ processJsonTypeProperty(model, property);
+ break;
+ default:
+ processUnknownTypeProperty(model, property);
+ }
+ }
+
+ /**
+ * Processes each model's property mapped to integer type and adds related
+ * vendor extensions
+ *
+ * @param model model
+ * @param property model's property
+ */
+ public void processIntegerTypeProperty(CodegenModel model, CodegenProperty property) {
+ Map vendorExtensions = property.getVendorExtensions();
+ Map postgresqlSchema = new HashMap<>();
+ Map columnDefinition = new HashMap<>();
+ Map typeDefinition = new HashMap<>();
+ ArrayList columnDataTypeArguments = new ArrayList();
+ String baseName = property.getBaseName();
+ String colName = this.toColumnName(baseName);
+ String dataType = property.getDataType();
+ String dataFormat = property.getDataFormat();
+ String description = property.getDescription();
+ String minimum = property.getMinimum();
+ String maximum = property.getMaximum();
+ boolean exclusiveMinimum = property.getExclusiveMinimum();
+ boolean exclusiveMaximum = property.getIExclusiveMaximum();
+ String defaultValue = property.getDefaultValue();
+ Boolean required = property.getRequired();
+ Boolean isUuid = property.isUuid;
+ Boolean isEnum = property.isEnum;
+ String tableName = this.toTableName(model.getName());
+
+ if (vendorExtensions.containsKey(VENDOR_EXTENSION_POSTGRESQL_SCHEMA)) {
+ // user already specified schema values
+ LOGGER.info("Found vendor extension in '{}' property, autogeneration skipped", baseName);
+ return;
+ }
+
+ if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
+ // add original name in column comment
+ String commentExtra = "Original param name - " + baseName + ".";
+ description = (description == null || description.isEmpty()) ? commentExtra
+ : description + ". " + commentExtra;
+ }
+
+ vendorExtensions.put(VENDOR_EXTENSION_POSTGRESQL_SCHEMA, postgresqlSchema);
+ postgresqlSchema.put("columnDefinition", columnDefinition);
+ columnDefinition.put("colName", colName);
+ if (isReservedWord(colName)) { // Output column name in double quotes if it is a reserved word
+ columnDefinition.put("colNameQuoted", true);
+ } else {
+ columnDefinition.put("colNameQuoted", false);
+ }
+ columnDefinition.put("tblName", tableName);
+ if (isReservedWord(model.getName())) { // Output table name (for column comment) in double quotes if it is a
+ // reserved word
+ columnDefinition.put("tblNameQuoted", true);
+ } else {
+ columnDefinition.put("tblNameQuoted", false);
+ }
+
+ if (Boolean.TRUE.equals(isEnum)) {
+ Map allowableValues = property.getAllowableValues();
+ List