Skip to content

parsesql re-rendering foreign constrains incorrectly #3

@mjsir911

Description

@mjsir911

Nim Version

Nim Compiler Version 2.2.4 [Linux: amd64]
Compiled at 2025-08-13
Copyright (c) 2006-2025 by Andreas Rumpf

active boot switches: -d:release -d:nimUseLinenoise

Description

Given the round trip:

FOREIGN KEY (artist_id_artist) REFERENCES artist(artist_id)
SqlNode(
  kind: nkForeignKey,
  sons: @[
    SqlNode(
      kind: nkIdent,
      strVal: "artist_id_artist"
    ),
    SqlNode(
      kind: nkReferences,
      sons: @[
      SqlNode(
        kind: nkCall,
        sons: @[
          SqlNode(
            kind: nkIdent,
            strVal: "artist"),
          SqlNode(
            kind: nkIdent,
            strVal: "artist_id"
          )]
      )]
    )
  ]
)

I'm then re-creating this with this code:

newNode(nkForeignKey, @[
  newNode(nkIdent, fk.columnName),
  newNode(nkReferences, @[
    newNode(nkCall, @[
      newNode(nkIdent, fk.referencedTable),
      newNode(nkIdent, fk.referencedColumn)
    ])
  ])
])

and I'm getting a (syntactically) incorrect:

FOREIGN KEY (artist_id_artist , REFERENCES artist(artist_id) )

(notice the extra comma)

here's the full code
import std/parsesql


let start = """
CREATE TABLE content(
  artist_id_artist integer,
  FOREIGN KEY (artist_id_artist) REFERENCES artist(artist_id)
)
"""

let ast = parseSql(start)

echo ast.treeRepr


# nkStmtList
#   nkCreateTable
#     nkIdent content
#     nkColumnDef
#       nkIdent artist_id_artist
#       nkIdent integer
#     nkForeignKey
#       nkIdent artist_id_artist
#       nkReferences
#         nkCall
#           nkIdent artist
#           nkIdent artist_id

let createdAst = 
  newNode(nkForeignKey, @[
    newNode(nkIdent, "artist_id_artist"),
    newNode(nkReferences, @[
      newNode(nkCall, @[
        newNode(nkIdent, "artist"),
        newNode(nkIdent, "artist_id")
      ])
    ])
  ])

let roundtrip = ast.renderSql(upperCase=true)
echo roundtrip
# CREATE TABLE content(artist_id_artist  integer , FOREIGN KEY (artist_id_artist , REFERENCES artist(artist_id) ) );;


let ending = createdAst.renderSql(upperCase=true)
echo ending
# FOREIGN KEY (artist_id_artist , REFERENCES artist(artist_id) )

Current Output

nkStmtList
  nkCreateTable
    nkIdent content
    nkColumnDef
      nkIdent artist_id_artist
      nkIdent integer
    nkForeignKey
      nkIdent artist_id_artist
      nkReferences
        nkCall
          nkIdent artist
          nkIdent artist_id
CREATE TABLE content(artist_id_artist  integer , FOREIGN KEY (artist_id_artist , REFERENCES artist(artist_id) ) );;
FOREIGN KEY (artist_id_artist , REFERENCES artist(artist_id) )

Expected Output

CREATE TABLE content(artist_id_artist  integer , FOREIGN KEY (artist_id_artist)  REFERENCES artist(artist_id) ) );;
FOREIGN KEY (artist_id_artist) REFERENCES artist(artist_id) )

Known Workarounds

unsure. I'm trying to figure out if this is valid sql or what. sqlite3 definitely doesn't take it, documented as much here: https://www.sqlite.org/syntax/table-constraint.html

let createdAst = 
  newNode(nkColumnDef, @[
    newNode(nkForeignKey),
    newNode(nkIdent, "artist_id_artist"),
    newNode(nkReferences, @[
      newNode(nkCall, @[
        newNode(nkIdent, "artist"),
        newNode(nkIdent, "artist_id")
      ])
    ])
  ])

using nkColumnDef (that I found from here)

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions