{"id":15653099,"url":"https://github.com/qnighy/bqpb","last_synced_at":"2026-03-08T23:33:55.756Z","repository":{"id":205405717,"uuid":"713891173","full_name":"qnighy/bqpb","owner":"qnighy","description":"BigQuery UDF to parse protobuf messages","archived":false,"fork":false,"pushed_at":"2025-05-25T00:46:26.000Z","size":240,"stargazers_count":42,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-14T05:21:24.222Z","etag":null,"topics":["bigquery","javascript","protobuf","protocol-buffers"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qnighy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-11-03T13:07:57.000Z","updated_at":"2025-10-31T09:40:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"b7d44d0c-fce1-4e06-aa87-c5f1ef8c492f","html_url":"https://github.com/qnighy/bqpb","commit_stats":null,"previous_names":["qnighy/bqpb"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/qnighy/bqpb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qnighy%2Fbqpb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qnighy%2Fbqpb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qnighy%2Fbqpb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qnighy%2Fbqpb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qnighy","download_url":"https://codeload.github.com/qnighy/bqpb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qnighy%2Fbqpb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30277012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bigquery","javascript","protobuf","protocol-buffers"],"created_at":"2024-10-03T12:44:41.309Z","updated_at":"2026-03-08T23:33:55.741Z","avatar_url":"https://github.com/qnighy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Protobuf parser for BigQuery\n\nbqpb is a **self-contained, yet feature-complete** parser for the\n[Protocol Buffers](https://protobuf.dev/) format, which is intended for use on\n[BigQuery](https://cloud.google.com/bigquery/) as a\n[JavaScript UDF](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions#javascript-udfs).\n\n### Supported features\n\n- [x] Protobuf input\n- [x] JSON output\n- [x] JSON output conformance -- see\n      [JSON Mapping](https://protobuf.dev/programming-guides/proto3/#json)\n      defined in the spec.\n- Schema support\n  - [x] Rough inspection of the message without a schema\n  - [x] Precise parsing and serialization of the message with a schema\n- Supported types\n  - [x] All integer types -- `uint32`, `int32`, `sint32`, `uint64`, `int64`,\n        `sint64`, `fixed32`, `sfixed32`, `fixed64`, `sfixed64`\n  - [x] `float` and `double`\n  - [x] `bool`\n  - [x] `bytes` and `string`\n  - [x] `map`\n  - [x] Enums\n  - [x] Messages\n- Supported field types\n  - [x] optional\n  - [x] repeated\n    - [x] packed representation\n  - [x] oneof (partially supported)\n  - [x] group in proto2\n- Supported special JSON serialization rules\n  - [x] Any\n  - [x] Generic JSON Values -- Value, Struct, ListValue, and NullValue\n  - [x] Timestamp and Duration\n  - [x] FieldMask\n  - [x] Wrapper types -- `UInt32Value`, `Int32Value`, `UInt64Value`,\n        `Int64Value`, `FloatValue`, `DoubleValue`, `BoolValue`, `StringValue`,\n        `BytesValue`\n\n### Usage\n\n```sql\nCREATE TEMP FUNCTION parseProtobuf(input BYTES, messageType STRING, typedefs JSON)\nRETURNS JSON DETERMINISTIC\nLANGUAGE js\nAS r\"\"\"\n// bqpb v0.1.0\n// (c) 2023, Masaki Hara. Licensed under the MIT License.\n\"use strict\";function t(t){\nconst n=(t+\"=\").indexOf(\"=\"),e=new Uint8Array(.75*n|0);for(let r=0;n\u003er;r++){\nconst n=t.charCodeAt(r),o=.75*r+.75|0,i=n-(96\u003en?64\u003en?48\u003en?47\u003en?-19:-16:-4:65:71)\u003c\u003c2+r%4*2\n;e[o-1]|=i\u003e\u003e8,e[o]|=i}return e}function n(t){\nconst n=new Array(4*((t.length+2)/3|0)),e=(4*t.length+2)/3|0\n;for(let r=0;e\u003er;r++){const e=.75*r+.75|0,o=(t[e-1]\u003c\u003c8|t[e])\u003e\u003e2+r%4*2\u002663\n;n[r]=o+(26\u003eo?65:52\u003eo?71:62\u003eo?-4:63\u003eo?-19:-16)}\nfor(let t=e;t\u003cn.length;t++)n[t]=61\n;return n.map((t=\u003eString.fromCharCode(t))).join(\"\")}function e(t){try{\nreturn decodeURIComponent(Array.from(t).map((t=\u003e`%${t.toString(16).padStart(2,\"0\")}`)).join(\"\"))\n}catch(t){throw new Error(\"Invalid UTF-8 sequence\")}}function r(t){\nif(t.p\u003e=t.b.length)throw new Error(\"Unexpected EOF\");return t.b[t.p++]}\nfunction o(t){let n=0n,e=0n;for(;;){const o=r(t)\n;if(n|=BigInt(127\u0026o)\u003c\u003ce,128\u003eo)break;e+=7n}return n}function i(t,n){let e=0n\n;for(let o=0;n\u003eo;o++){const n=r(t);e|=BigInt(n)\u003c\u003cBigInt(8*o)}return e}\nfunction u(t,n){const e=[];for(;;){const r=f(t,n);if(null==r)break;e.push(r)}\nreturn e}function f(t,n){if(null==n\u0026\u0026t.p\u003e=t.b.length)return null\n;const e=o(t),r=Number(7n\u0026e),f=e\u003e\u003e3n;switch(r){case 0:return{f:f,w:r,v:o(t)}\n;case 1:case 5:return{f:f,w:r,v:i(t,1===r?8:4)};case 2:{const n=Number(o(t))\n;if(t.p+n\u003et.b.length)throw new Error(\"Unexpected EOF\")\n;const e=t.b.subarray(t.p,t.p+n);return t.p+=n,{f:f,w:r,v:e}}case 3:return{f:f,\nw:r,v:u(t,f)};case 4:if(f===n)return null;throw new Error(\"Invalid group\")\n;default:throw new Error(\"Unexpected wire type\")}}function s(t){return u({b:t,\np:0})}function c(t,n,e){return a(s(t),n,e)}function a(t,n,e){const r=_(t,n,e)\n;return void 0!==r?r:l(t,n,e)}function l(t,r,u){const f={}\n;for(const n of t)(f[n.f]??=[]).push(n);const s={},l=u[`message ${r}`]\n;if(l)for(const[t,n]of Object.entries(l)){const e=f[n.id]??[];delete f[n.id]\n;const r=z(n.type,u,n.messageEncoding),c=null!=n.oneofGroup?\"explicit\":n.fieldPresence??\"explicit\"\n;let a,l;if(r===O){const t=e.map((t=\u003eG(t,r,n.type,u))).filter((t=\u003enull!=t))\n;a=Object.fromEntries(t),l=!0}else if(n.repeated){let t=e;if(B\u003er){t=[]\n;for(const u of e){if(2!==u.w){t.push(u);continue}const e={b:u.v,p:0}\n;for(;e.p\u003cu.v.length;)j\u003er?t.push({f:BigInt(n.id),w:0,v:o(e)}):t.push({\nf:BigInt(n.id),w:k\u003er?5:1,v:i(e,k\u003er?4:8)})}}a=t.map((t=\u003eG(t,r,n.type,u))),l=!0\n}else\"explicit\"===c?(a=e.length\u003e0?G(e[e.length-1],r,n.type,u):null,\nl=e.length\u003e0):(a=e.length\u003e0?G(e[e.length-1],r,n.type,u):W(r,n.type,u),l=!0)\n;l\u0026\u0026(s[t]=a)}for(const t of Object.values(f)){const r=t[0].f,o=t.map((t=\u003e{\nif(2===t.w){try{const n=e(t.v)\n;if(!/[\\0-\\x08\\x0b-\\x1F\\x7F]/.test(n))return`unknown:string:${n}`}catch(t){}\ntry{return c(t.v,\"\",u)}catch(t){}return`unknown:bytes:${n(t.v)}`}\nif(3===t.w)return a(t.v,\"\",u);{\nconst n=1===t.w?\"double\":5===t.w?\"float\":0x100000000n\u003et.v?\"int32\":\"int64\"\n;return`unknown:${n}:${G(t,z(n,u),n,u)}`}}));s[`#${r}`]=1===o.length?o[0]:o}\nreturn s}\nconst p=0,w=1,g=8,d=9,b=11,h=12,v=13,m=15,y=16,F=17,x=19,$=20,E=21,S=23,I=24,O=25,L=26,U=27,A=28,j=16,k=20,B=24,N=28\n;function V(t){return!(3\u0026~t)}function C(t){return!(1\u0026~t)}function T(t){\nreturn!(4\u0026~t)}function D(t){return t\u003e=w\u0026\u0026E\u003e=t\u0026\u0026t!=x||t===U}function W(t,n,e){\nif(t===p){const t=e[`enum ${n}`];return Object.entries(t)[0][0]??0}return Z[t]}\nconst Z={[w]:!1,[g]:0,[d]:0,[b]:0,[h]:\"0\",[v]:\"0\",[m]:\"0\",[y]:0,[F]:0,[x]:0,\n[$]:\"0\",[E]:\"0\",[S]:0,[I]:null,[L]:\"\",[U]:\"\"},q={bool:w,uint32:g,int32:d,\nsint32:b,uint64:h,int64:v,sint64:m,fixed32:y,sfixed32:F,float:x,fixed64:$,\nsfixed64:E,double:S,bytes:L,string:U};function z(t,n,e){\nreturn t in q?q[t]:t.startsWith(\"map\u003c\")?O:`enum ${t}`in n?p:\"delimited\"===e?A:I\n}function G(t,r,o,i){if(B\u003er){const n=j\u003er?0:k\u003er?5:1\n;if(t.w!==n)throw new Error(`Expected wire type ${n}, got ${t.w}`)\n;if(r===w)return!!t.v;if(r===p){const n=i[`enum ${o}`]\n;for(const[e,r]of Object.entries(n))if(r===Number(t.v))return e\n;return Number(t.v)}if(r===x)return J(P(t.v));if(r===S)return J(M(t.v))\n;const e=V(r)?t.v\u003e\u003e1n^-(1n\u0026t.v):C(r)?T(r)?(0xFFFFFFFFFFFFFFFFn\u0026t.v)-((t.v\u003e\u003e63n\u00261n)\u003c\u003c64n):(0xFFFFFFFFn\u0026t.v)-((t.v\u003e\u003e31n\u00261n)\u003c\u003c32n):t.v\n;return T(r)?String(e):Number(e)}if(N\u003er){\nif(2!==t.w)throw new Error(`Expected wire type 2, got ${t.w}`)\n;if(r===L)return n(t.v);if(r===U)return e(t.v);if(r===O){\nconst n=o.indexOf(\",\"),e=o.lastIndexOf(\"\u003e\"),r=o.slice(4,n).trim(),u=o.slice(n+1,e).trim(),f=z(r,i),c=z(u,i)\n;if(!D(f)||c===O)throw new Error(\"Invalid map type\")\n;const a=s(t.v),l=a.findLast((t=\u003e1n===t.f)),p=a.findLast((t=\u003e2n===t.f))\n;if(!l)return null;const w=G(l,f,r,i);if(!p){return[w,W(c,u,i)]}\nreturn[w,G(p,c,u,i)]}return c(t.v,o,i)}\nif(3!==t.w)throw new Error(`Expected wire type 3, got ${t.w}`)\n;return a(t.v,o,i)}function J(t){return 1/t==0||t!=t?`${t}`:t}function M(t){\nreturn new Float64Array(BigUint64Array.of(t).buffer)[0]}function P(t){\nreturn new Float32Array(Uint32Array.of(Number(t)).buffer)[0]}function R(n,e,r){\nreturn c(t(n),e,r)}function _(t,n,e){\nif(!n.startsWith(\"google.protobuf.\"))return;const r=n.slice(16)\n;if(/^(U?Int(32|64)|Double|Float|Bool|String|Bytes)Value$/.test(r)){\nconst n=r.slice(0,-5).toLowerCase(),o=z(n,e),i=t.findLast((t=\u003e1n===t.f))\n;return i?G(i,o,n,e):W(o,n,e)}switch(r){case\"Any\":{\nconst n=t.findLast((t=\u003e1n===t.f)),r=t.findLast((t=\u003e2n===t.f)),o=n?G(n,U,\"string\",e):\"\"\n;if(r\u0026\u00262!==r.w)throw new Error(`Expected wire type 2, got ${r.w}`)\n;const i=r?.v??new Uint8Array;if(o.startsWith(\"type.googleapis.com/\")){\nconst t=o.slice(20),n=s(i),r=_(n,t,e);return void 0!==r?{\"@type\":o,value:r}:{\n\"@type\":o,...l(n,t,e)}}break}case\"Value\":{\nconst n=t.findLast((t=\u003et.f\u003e=1n\u0026\u00267n\u003e=t.f))\n;if(!n)throw new Error(\"Invalid JSON Value\");switch(n.f){case 1n:\nreturn G(n,g,\"uint32\",e),null;case 2n:return G(n,S,\"bool\",e);case 3n:\nreturn G(n,U,\"string\",e);case 4n:return G(n,w,\"bool\",e);case 5n:\nreturn G(n,I,\"google.protobuf.Struct\",e);case 6n:\nreturn G(n,I,\"google.protobuf.ListValue\",e)}break}case\"Struct\":{\nconst n=t.filter((t=\u003e1n===t.f)).map((t=\u003eG(t,O,\"map\u003cstring,google.protobuf.Value\u003e\",e)))\n;return Object.fromEntries(n)}case\"ListValue\":\nreturn t.filter((t=\u003e1n===t.f)).map((t=\u003eG(t,I,\"google.protobuf.Value\",e)))\n;case\"FieldMask\":\nreturn t.filter((t=\u003e1n===t.f)).map((t=\u003eG(t,U,\"string\",e))).map((t=\u003et.replace(/_([a-z])/g,((t,n)=\u003en.toUpperCase())))).join(\",\")\n;case\"Timestamp\":case\"Duration\":{\nconst n=t.findLast((t=\u003e1n===t.f)),o=t.findLast((t=\u003e2n===t.f)),i=n?Number(G(n,v,\"\",e)):0,u=o?G(o,d,\"\",e):0\n;if(\"Timestamp\"===r){\nreturn new Date(1e3*i+u/1e6).toISOString().replace(/Z$/,`${(u%1e6).toString().padStart(6,\"0\")}Z`)\n}\nreturn 0\u003ei?`-${-i}.${(-u).toString().padStart(9,\"0\")}s`:`${i}.${u.toString().padStart(9,\"0\")}s`\n}}}return R(input,messageType,typedefs);\n\"\"\";\n\nSELECT parseProtobuf(b'\\x08\\x01', 'Main', JSON\"\"\"{\n  \"message Main\": {\n    \"field1\": { \"type\": \"uint32\", \"id\": 1 }\n  }\n}\"\"\")\n```\n\n### API Reference\n\nSee [parse-protobuf.md](docs/parse-protobuf.md).\n\n### License\n\nMIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqnighy%2Fbqpb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqnighy%2Fbqpb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqnighy%2Fbqpb/lists"}