Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Golangで作るSQL Language Server(sqls)
Search
Toshikazu Ohashi
November 13, 2021
Programming
1
590
Golangで作るSQL Language Server(sqls)
Go Conference 2021 Autumn Track A
Toshikazu Ohashi
November 13, 2021
Tweet
Share
More Decks by Toshikazu Ohashi
See All by Toshikazu Ohashi
黒画面が最高のしごと道具である3つの理由
lighttiger2505
0
130
Connect with many developers from the small plugin
lighttiger2505
0
240
作ってわかる現代のVimのAutoComplete ~そしてVimConf2019へ~
lighttiger2505
3
1.4k
自社サービスのDjangoを 1.3から1.11(LTS)に アップグレードするまでの道のり
lighttiger2505
6
3.1k
LSPがもたらしたVimプラグインの変化に思いを馳せる
lighttiger2505
2
1.2k
ターミナルアプリケーションとしてのVim
lighttiger2505
0
460
Go Language Server 使うべし
lighttiger2505
5
1.8k
Goで作るインタラクティブなCLIコマンドとそのデザイン
lighttiger2505
0
620
GUI is not fast enough!! (GUIには速さが足りないっ!!)
lighttiger2505
0
460
Other Decks in Programming
See All in Programming
品質とスピードを両立: TypeScriptの柔軟な型システムをバックエンドで活用する
kosui
8
2.2k
App Router への移行は「改善」となり得るのか?/ Can migration to App Router be an improvement
takefumiyoshii
8
2.1k
Javaエンジニアのための Nodejs/Nuxt3入門
hidekatsu_izuno
0
280
Git Lint
bkuhlmann
4
740
二郎系ラーメンのコールで学ぶ AST 解析
memory1994
PRO
7
1.6k
今の SmartHR にエンジニアで入社するとどうなるの?
daisukeshinoku
5
4.6k
0→1と1→10の狭間で Javaという技術選定を振り返る/Reflecting on the Decision to Choose Java Between Scaling from 0 to 1 and 1 to 10
jaguar_imo
2
360
Folding Cheat Sheet #3
philipschwarz
PRO
0
110
Ruby GitHub Packages
bkuhlmann
0
620
StoreKit2によるiOSのアプリ内課金のリニューアル
kangnux
0
100
甘い香りに誘われてVanilla Extractを1年間運用してみた
miyahkun
1
110
データアナリストが行うDatabricksを活用したETLの自動化事例
shinoa
0
250
Featured
See All Featured
From Idea to $5000 a Month in 5 Months
shpigford
377
45k
It's Worth the Effort
3n
180
27k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
18
1.7k
We Have a Design System, Now What?
morganepeng
42
6.7k
Stop Working from a Prison Cell
hatefulcrawdad
266
19k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
226
51k
The MySQL Ecosystem @ GitHub 2015
samlambert
242
12k
Bash Introduction
62gerente
604
210k
The Straight Up "How To Draw Better" Workshop
denniskardys
227
130k
The World Runs on Bad Software
bkeepers
PRO
61
6.7k
Design by the Numbers
sachag
274
18k
Become a Pro
speakerdeck
PRO
10
4.5k
Transcript
GolangͰ࡞Δ SQL Language Server(sqls) Go Conference 2021 Autumn Track A
lighttiger2505@גࣜձࣾMobility Technologies
ࣗݾհ lighttiger2505 / Toshikazu Ohashi • גࣜձࣾMobility Technologiesॴଐ • αʔόʔαΠυΤϯδχΞ
• ͖ͳΤσΟλVim/NeoVim
ΠϯτϩμΫγϣϯ
sqls An implementation of the Language Server Protocol for SQL.
sqlsͱ • Language Server Protocol(ҎԼ LSP)Λ༻͍ͯΤσΟλͱ௨৴͢ΔSQL ͷLanguage Server(ҎԼ ݴޠαʔόʔ) •
LSPͱϓϩάϥϜݴޠͷ։ൃࢧԉػೳ(ҎԼ ΠϯςϦηϯε)ΛΤ σΟλʹఏڙ͢Δαʔόɺ͓Αͼͦͷ௨৴༰Λنఆͨ͠ϓϩτί ϧɻMicrosoft࡞
HPQMT(PMBOH DMBOHE$MBOH TRMT42- -BOHVBHF4FSWFS1SPUPDPM MTQ LSΫϥΠΞϯτ͕͋ΔΤσΟλͰ͋ΕͲͷΤσΟλͰ ݴޠͷΠϯςϦηϯεͷԸܙΛड͚Δ͜ͱ͕Ͱ͖Δ
ࣗಈิ
αϒΫΤϦࣗಈิ
ఆٛࢀর
Πϯαʔτೖྗิॿ
ΫΤϦ࣮ߦ
ຊͷΰʔϧ GoݴޠͰ࡞Γํ͕Α͘Θ͔Βͳ͍ͷΛ࡞Δํ๏Λڞ༗͢Δ ⊗ ࣅͨΑ͏ͳ͜ͱΛࣗͰͰ͖ΔͱࢥͬͯΒ͏ ⊗ GoͰ࡞ΒΕͨศརπʔϧ͕ੈքʹ૿͑Δ
ΞδΣϯμ લఏ • ᶃͳͥͭ͘Δͷ͔ɻͦͷಈػ • ᶄͲ͏ͭ͘Δͷ͔ɻͦͷํ ࣮ફฤ • ᶅΤσΟλͱLSPͰ௨৴͢ΔͨΊʹͲ͏ͨ͠Β •
ᶆSQLΛͲ͏ͬͯղੳ͢Ε͍͍͔ • ᶇෳͷσʔλϕʔεʹͲ͏ରԠ͢Ε͍͍͔ ·ͱΊ
ᶃͳͥͭ͘Δͷ͔ɻͦͷಈػ
ੈͷதʹSQLͷΠϯςϦηϯε͕গͳ͍ • SQLΛૢ࡞͢Δͱ͖ࣗಈิఆٛࢀরͰ͖ͳ͍ͷ͕ෆຬ • ิͰ͖͍ͯ • ਖ਼֬͡Όͳ͍ • SELECT Exprิͯ͠ଞͰิ͠ͳ͍
• DBπʔϧਾ͚͑ͷΤσΟλ্Ͱ͔͠ΠϯςϦηϯε͕ಈ࡞͠ͳ͍
dbcli͚͕ͩٹ͍ͩͬͨ • DBeaver, DataGripͱൺֱͯ͠ิ ͕ਖ਼͔֬ͭߴ • λʔϛφϧ͔Βଈ࣌ىಈ • ීஈࣄͰ͏Α͏ͳDBαϙʔτ •
DBଓཧ͕໘ • ࣗͰπʔϧΛ࡞ͬͨ
Ұ΄ͲdbcliΛͬͨ݁Ռͷෆຬ • 1ϥΠϯΤσΟλͳͷͰෳߦͷΫΤϦฤूͮ͠Β͍ • αϒΫΤϦͳͲͷෳࡶͳΫΤϦͷิͰ͖ͳ͍ • ΧϥϜͷৄࡉςʔϒϧͷৄࡉΛࢀর͢Δͱ͖ɺςʔϒϧৄࡉΛௐ ΔผΟϯυΛ։͍ͯࢀর͢Δඞཁ͕͋Δ
ݴޠαʔόʔͱLSP • ࣌(2018ͷౙࠒ)gopls͕։ൃ͞ΕɺGoͷࣗಈิݴޠαʔόʔ Λ͏ͷ͕ྑ͍ͱ͍͏ঢ়گʹ • ΤσΟλʔ͕ΠϯςϦηϯεΛಘΔͱ͖ݴޠαʔόʔ͕ୈҰީิʹͳ Δͱ͍͏ྲྀΕ • SQLͷݴޠαʔόʔ͕͋Εɺͯ͢ͷͯ͢ղܾ͢ΔͷͰ ͱ͍͏ண
ᶄͲ͏ͭ͘Δͷ͔ɻͦͷํ
࠷খཁ݅Λ·ͱΊΔ • LSPʹ४ڌͨ͠ϦΫΤετ/ϨεϙϯεΛฦͤΔ • SQLͷจ຺ΛཧղͰ͖Δ • ͦΕʹΑͬͯࣗಈิ͕Ͱ͖Δ • ෳछྨͷσʔλϕʔεʹରԠ͢Δ͜ͱ͕Ͱ͖Δ •
ॳظஈ֊ͰMySQLͷΈ
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
ղܾ͠ͳ͚Ε͍͚ͳ͍՝͕̏ͭ TRMEBUBCBTF SQLϑΝΠϧ
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
ΤσΟλͱLSPͰ௨৴͢ΔͨΊʹͲ͏ͨ͠Β͍͍͔ TRMEBUBCBTF SQLϑΝΠϧ
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
TRMEBUBCBTF SQLΛղੳ͢ΔʹͲ͏͢Ε͍͍͔ SQLϑΝΠϧ
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
TRMEBUBCBTF ෳͷσʔλϕʔεʹͲ͏ରԠ͢Ε͍͍͔ SQLϑΝΠϧ
Θ͔ΒΜ͚Ͳ ͱΓ͋͑ͣ ࡞Ζ͏
ҠಈͰਓΛͤʹɻ ϞϏϦςΟςΫϊϩδʔζ ఏɹɹڙ ϓϩϞʔγϣϯΛؚΈ·͢
ʮҠಈͰਓΛͤʹɻʯΛϛογϣϯʹ No.1*λΫγʔΞϓϦʮGOʯAIυϥϨ ίαʔϏεʮDRIVE CHARTʯͳͲΛ։ൃ ͍ͯ͠·͢ *App AnnieௐʛλΫγʔंؔ࿈ΞϓϦʹ͓͚Δຊࠃμϯϩʔυ(iOS/ Google Play߹ࢉ) ௐࠪظؒɿ202010݄1ʙ20219݄30
ϓϩϞʔγϣϯΛؚΈ·͢
GoΤϯδχΞ ΛઈࢍืूதͰ͢ ϓϩϞʔγϣϯΛؚΈ·͢
ᶅΤσΟλͱLSPͰ ௨৴͢ΔͨΊʹͲ͏ͨ͠Β͍͍͔
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
ΤσΟλͱLSPͰ௨৴͢ΔͨΊʹͲ͏ͨ͠Β͍͍͔ TRMEBUBCBTF SQLϑΝΠϧ
LSPʹΑΔΤσΟλͱͷ௨৴ • ΤσΟλͱݴޠαʔόʔJSON-RPC 2.0Ͱ௨৴͢Δ • RPC(Remote Procedure Callͷུ)ݺͼग़͠ݩͱผͷϓϩάϥϜ ͷϝιουΛݺͼग़͢ •
JSON-RPCϝιουͷίʔϧͱϨεϙϯεΛJSONͰߦ͏ • ݴޠαʔόʔͱݴ͏͕ΤσΟλͱಉ͡PC্ʹ্ཱͪ͛ͯιέοτܦ ༝Ͱ௨৴͢Δͷ͕ओ
JSON-RPCͷ௨৴ྫ(ఆٛݩδϟϯϓ) { "jsonrpc": "2.0" , "id" : 1 , "method":
"textDocument/definition" , "params": { "textDocument": { "uri": "file:///cpp/use.cpp " } , "position": { "line": 3 , "character": 1 2 } } } { "jsonrpc": "2.0" , "id": 1 , "result": { "uri": "file:///cpp/provide.cpp" , "range": { "start": { "line": 0 , "character": 4 } , "end": { "line": 0 , "character": 1 1 } } } } ΤσΟλ ϦΫΤετ ݴޠαʔόʔ Ϩεϙϯε
GolangͰͷJSON-RPCͷ࣮ํ๏ • Goͷ͍͍ͱ͜ΖࣅͨΑ͏ͳιϑτΣΞ͕͏͢Ͱʹ͋Δ ݴޠαʔόʔ ղઆ HPQMT (Pͷ։ൃνʔϜ͕։ൃ͍ͯ͠Δ(PMBOHެࣜͷݴޠαʔόʔ CJOHP TBJCJOHࢯ͕։ൃɻHPQMTҎલ͔Β͋Δ(PMBOHͷݴޠαʔόʔɻݱࡏHPQMTʹ ౷߹ɻHPQMTΑΓػೳ͕গͳ͘γϯϓϧɻ࣮ॳظͬͪ͜Λࢀߟʹͨ͠
FGNMBOHTFSWFS NBUUOࢯ͕։ൃɻMJOUFSͷ࣮ߦ݁ՌΛύʔεͯ͠MTQܗࣜͷMJOU݁Ռ EJBHOPTUJDT ͱ͍͏ ʹม͠+40/31$ܗࣜͰ͢൚༻ݴޠαʔόʔ
JSON-RPCߏஙͷஈऔΓ • ͲͷαʔόʔJSON-RPC2ͷ࣮ʹsourcegraph/jsonrpc2Λ͍ͬͯΔ • efm-langserver͔Βݴޠαʔόʔͱͯ͠࠷ݶΓཱͭίʔυΛҾ༻ • ࠷γϯϓϧͳ࡞ΓͩͬͨͨΊ • sourcegraph/jsonrpc2ͱbingo͔ΒJSON-RPC2ͷςετίʔυΛҾ༻ͯ͠ ୯ମςετߏங
• ࣮ࡍʹLSΫϥΠΞϯτͱૄ௨ͯ͠ਖ਼ৗಈ࡞͢Δ͜ͱΛ֬ೝ
ᶆSQLΛղੳ͢Δʹ Ͳ͏͢Ε͍͍͔
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
TRMEBUBCBTF SQLΛղੳ͢ΔʹͲ͏͢Ε͍͍͔ SQLϑΝΠϧ
SQLΛղੳ͢Δʹ • Golangͷgo/astύοέʔδͷΑ͏ͳղੳϥΠϒϥϦ͕ඞཁ • ϥΠϒϥϦΛ୳͢ͱҎԼͷΑ͏ͳͷ͕ݟ͔ͭΔ ύʔαʔ ղઆ YXC TRMQBSTFS 7JUFTTͱ͍͏.Z42-ͷΫϥελΛߏங͢ΔγεςϜͰར༻͞Ε͍ͯΔύʔαʔ
ΛϥΠϒϥϦԽͨ͠ͷ BLJUP YTRMQBSTFS 3VTUͷBOEZHSPWFTRMQBSTFSSTΛࢀߟʹ࡞ΒΕͨύʔαʔɻTRMTͰ ͍ͬͯͳ͍͕MFYFS΄΅͜ΕΛࢀߟʹ͍ͯ͠Δ
ͲͷΑ͏ͳಈ͖Λ͢Δ͔ݕূ͢Δ • SQLΛύʔεͯ͠ߏମΛprint͢Δ͚ͩͷ؆қCLIΛ࡞ͬͯݕূ package mai n import ( "fmt "
"os " "github.com/k0kubun/pp " "github.com/xwb1989/sqlparser " ) func main() { stmt, err := sqlparser.Parse(os.Args[0] ) if err != nil { fmt.Println("parse error:", err ) retur n } pp.Print(stmt ) }
͜ͷͱ͖͜͏ࢥ͍ͬͯ·ͨ͠ ͳΜͩ؆୯͡Όͳ͍͔ɻ ͜ΕͳΒࣗಈิ͙ͩͧ͢ɻ
ݕূͷ݁Ռࣗಈิʹ͑ͳ͍͜ͱ͕Θ͔Δ • ݕূͨ݁͠Ռɺsqls༻్Ͱطଘύʔαʔ͑ͳ͍͜ͱ͕Θ͔Δ SELECT id, | FROM city INSERT INTO
city (id, |) UPDATE city SET CountryCode='USA', |
GOͷߏจ package mai n import "fmt " func main() {
msg := "hello world " fmt.Sprintln(| } SELECT `ID` , | FROM `city ` WHERE `CountryCode` = 'USA ' ORDER BY `District` SQLͷߏจ
GOͷߏจ package mai n import "fmt " func main() {
msg := "hello world " fmt.Sprintln(| } SELECT `ID` , | FROM `city ` WHERE `CountryCode` = 'USA ' ORDER BY `District` SQLͷߏจ • ߏจͷ্ؔɺ1Statement͕͍ • 1Statementͷதʹ(ςʔϒϧ)ఆٛใؚ͕·Ε͍ͯΔ
GOͷߏจ package mai n import "fmt " func main() {
msg := "hello world " fmt.Sprintln(| } SELECT `ID` , | FROM `city ` WHERE `CountryCode` = 'USA ' ORDER BY `District` SQLͷߏจ • ߏจͷ্ؔɺ1Statement͕͍ • 1Statementͷதʹ(ςʔϒϧ)ఆٛใؚ͕·Ε͍ͯΔ
GOͷߏจ package mai n import "fmt " func main() {
msg := "hello world " fmt.Println(| } SELECT `ID` , | FROM `city ` WHERE `CountryCode` = 'USA ' ORDER BY `District` SQLͷߏจ • ଞݴޠͳΒύʔεࣦഊͨ͠1StatementΛಡΈඈͯ͠ऴΘΓ • SQL1StatementதͷΤϥʔΛׂͯ͠ղऍ͢Δඞཁ͕͋Δ
ݱࡏSQLͷࣗಈิ͕Ͱ͖͍ͯΔOSS • dbcliγϦʔζɻPythonɻ֤DBͷCLIίϚϯυͷΘΓʹ͏͜ͱͰ CLI্ͰΫΤϦͷࣗಈิ͕Ͱ͖Δ ίϚϯυ ղઆ QHDMJ QPTUHSF42-ͷ$-*ίϚϯυସ NZDMJ .Z42-ͷ$-*ίϚϯυସ
MJUFDMJ 42-JUFͷ$-*ίϚϯυସ NTTRMDMJ .JDSPTPGU42-4FSWFSͷ$-*ίϚϯυସ
dbcliγϦʔζ͕ར༻͍ͯ͠ΔSQLύʔαʔ • andialbrecht/sqlparse • ͍Θ͘sqlparse is a non-validating SQL parser
for Python. • Goͷύʔαʔͷͱ͖ͱಉ༷ʹSQLͷύʔε݁ՌΛඳը͢Δ͚ͩͷCLI ίϚϯυΛ࡞ͬͯࢼ͢ • ΤϥʔΛಡΈඈͤΔఔ·Ͱจ຺ͷղੳΛεΩοϓ͍ͯͨ͠
طଘͷSQLύʔε
non-validatingͳSQLύʔε
di f
di f จ຺ΛऔΒͳ͍ɻSelectͰදࣔ͢ΔΧϥϜͱ͔ςʔϒϧͷఆٛ
ϝϦσϝ • ϝϦοτ • ଟগͷΤϥʔ͕͋ͬͯͳ͘ύʔεͰ͖Δ • σϝϦοτ • From۟Ͱఆٛ͞ΕͨςʔϒϧΛҾ͖ग़͢ͳͲͷॲཧ͕໘ •
lintͷ࣮ͱ͔ΊΜͲ͍͘͞(ͳͷͰ͍ͬͯͳ͍) • αϒΫΤϦཧԋࢉࢠͳͲ࠶ؼతͳॲཧ͕͍͠ • αϒΫΤϦղੳͷίʔυࠓͰݟͨ͘ͳ͍
ཧ۶Θ͔͕ͬͨɺશʹࣗݾྲྀͰ࣮͢Δͷා ͍ͷͰɺύʔαʔͮ͘ΓͷษڧΛ͢Δ͜ͱʹͨ͠ ͓͢͢Ίʂʂʂ
̍ϲ݄ษڧͯ͠Θ͔ͬͨ͜ͱ • ߏจΛղੳ͢ΔͨΊʹࣈ۟ղੳث(Lexer),ߏจղੳث(Parser)͕ඞཁ • ύʔαʔΛ࡞ΔͨΊʹύʔαʔδΣωϨʔλͳΔศརπʔϧ͕͋Δ • DSLΛఆٛͯ͠ಡΈࠐΉͱύʔαʔ(߹ʹΑͬͯϨΩαʔ)Λ ੜ ࣈ۟ղੳث -FYFS
ߏจղੳث 1BSTFS τʔΫϯྻ AST ιʔείʔυ
sqlsͷΞϓϩʔν • ύʔαʔδΣωϨʔλʔ vs ࣗ࡞ύʔαʔ • ͲͷδΣωϨʔλʔͳΒnon-validatingͳύʔαʔ͕࡞ΕΔ͔ෆ໌ • ࣗ࡞ͰύʔαʔͳΒࣗ࡞ͳͷͰͳΜͰͰ͖Δ •
ࠓࢥ͑tree-sitterͱ͔͋ͬͨɻษڧෆ • ࣗ࡞ύʔαʔͷ࡞Λܾҙ • ϨΩαʔxsqlparserΛࢀߟʹ͢ΕͦΜͳʹ࿑ྗͳ͘࡞Εͦ͏
ύʔαʔ࡞Γํߨ࠲(ͦͷ̍) • andialbrecht/sqlparse͔ΒύʔεͷςετίʔυΛݟ͚ͭΔ • ҎԼΛsqlparseͱಉͷ݁Ռ͕ಘΒΕΔ·Ͱ܁Γฦ͢ 1. ύʔε͢ΔରΛܾΊΔ(ΧϥϜྻͱ͔) 2. ରΛύʔε͢ΔςετίʔυΛsqlsʹҠ২ 3.
ςετίʔυͷظΛຬͨ͢
ύʔαʔ࡞Γํߨ࠲(ͦͷ̎) • ςετ͠·͢ • ςετ͠·͢ • ςετ͠·͢ • ςετ͠·͢ •
ςετ͠·͢ • ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠· ͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠ ·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢ςετ͠·͢…
ॳΊͯsqlsͰࣗಈิΛ͍ͯ͠Δ༷ࢠ
ᶇෳͷσʔλϕʔεʹ Ͳ͏ରԠ͢Ε͍͍͔
TRMT .Z42- 1PTUHSF 42- TRMJUF MTQ MTQ MTQ TRMEBUBCBTF TRMEBUBCBTF
TRMEBUBCBTF ෳͷσʔλϕʔεʹͲ͏ରԠ͢Ε͍͍͔ SQLϑΝΠϧ
੍ͱϧʔϧΛઃ͚Δ • sqls͋͘·ͰࣗͷͨΊͷπʔϧ • ༗ঈͷDBʹରԠ͠ͳ͍ • ։ൃऀ͍ͩ͠Ͱଓݕূ͕Ͱ͖ͳ͘ͳΔ • BigQuery •
Snow fl ake • database/sqlʹޓͷ͋ΔDriver͕ͳ͍ͷʹରԠ͠ͳ͍
ΠϯλϑΣʔεΛ༻ҙ type DBRepository interface { Driver() dialect.DatabaseDrive r CurrentDatabase(ctx context.Context)
(string, error ) Databases(ctx context.Context) ([]string, error ) CurrentSchema(ctx context.Context) (string, error ) Schemas(ctx context.Context) ([]string, error ) SchemaTables(ctx context.Context) (map[string][]string, error ) DescribeDatabaseTable(ctx context.Context) ([]*ColumnDesc, error ) DescribeDatabaseTableBySchema(ctx context.Context, schemaName string) ([]*ColumnDesc, error ) Exec(ctx context.Context, query string) (sql.Result, error ) Query(ctx context.Context, query string) (*sql.Rows, error ) }
ͳͥΠϯλϑΣʔε͕ඞཁ͔ • υϥΠόՃʹඞཁͳ߲Λ໌ࣔ • ςʔϒϧͳͲͷϝλใͷऔಘํ๏͕DB͝ͱʹҧ͏ • mysql, postgresqlͳΒinformation_schema • sqlite3ͳΒsqlite_master
ΠϯλϑΣʔεΘ͚ͨ͠Ռ • ࣗͰ࣮ͨ͠ͷDBଓMySQL͚ͩ • PostgreSQLͱSQLite3mattn͞Μ • Microsoft SQL Serveralexhokl͞Μ •
༗ঈͷDBΛՃͨ͠PullRequest͕དྷΔ͕Ϛʔδ͠ͳ͍
·ͱΊ • ڧ͍ಈػ(VimͰSQLͷิ͕͍ͨ͠)͕͋ΕؤுΕΔ • ࡞Γํ͕Θ͔Βͳ͍ͱ͖ɺࣅͨ՝Λղܾ͢Δπʔϧ୳ͤ͋Δ • طଘπʔϧ/ϥΠϒϥϦ͕՝ʹϑΟοτ͠ͳ͚Εࣗ࡞ࢹʹೖΕΔ • ΜͰ͍Δؒʹॻ͚ͨΓ͢Δ͠ɺବͰ৽͍͠՝͕ݟ͑Δ •
෦ద༻Ͱ͖Δͷ͋ΔͷͰίʔυΛಡΉ͜ͱΛڪΕͳ͍ • ॳظείʔϓͰ͖Δ͚ͩখ͘͢͞Δ
See you again όΠόΠ