├── .gitignore
├── CMakeLists.txt
├── Chinese.md
├── LICENSE
├── README.md
├── docker
├── Dockerfile
├── example.proto
└── google
│ └── protobuf
│ ├── any.proto
│ ├── duration.proto
│ ├── empty.proto
│ ├── struct.proto
│ ├── timestamp.proto
│ └── wrappers.proto
├── src
└── sw
│ └── redis-protobuf
│ ├── append_command.cpp
│ ├── append_command.h
│ ├── clear_command.cpp
│ ├── clear_command.h
│ ├── commands.cpp
│ ├── commands.h
│ ├── del_command.cpp
│ ├── del_command.h
│ ├── errors.h
│ ├── field_ref.h
│ ├── get_command.cpp
│ ├── get_command.h
│ ├── import_command.cpp
│ ├── import_command.h
│ ├── last_import_command.cpp
│ ├── last_import_command.h
│ ├── len_command.cpp
│ ├── len_command.h
│ ├── merge_command.cpp
│ ├── merge_command.h
│ ├── module_api.cpp
│ ├── module_api.h
│ ├── module_entry.cpp
│ ├── module_entry.h
│ ├── options.cpp
│ ├── options.h
│ ├── path.cpp
│ ├── path.h
│ ├── proto_factory.cpp
│ ├── proto_factory.h
│ ├── redis_protobuf.cpp
│ ├── redis_protobuf.h
│ ├── redismodule.cpp
│ ├── redismodule.h
│ ├── schema_command.cpp
│ ├── schema_command.h
│ ├── set_command.cpp
│ ├── set_command.h
│ ├── type_command.cpp
│ ├── type_command.h
│ ├── utils.cpp
│ └── utils.h
└── test
└── src
└── sw
└── redis-protobuf
├── append_test.cpp
├── append_test.h
├── clear_test.cpp
├── clear_test.h
├── del_test.cpp
├── del_test.h
├── import_test.cpp
├── import_test.h
├── len_test.cpp
├── len_test.h
├── merge_test.cpp
├── merge_test.h
├── proto_test.cpp
├── proto_test.h
├── schema_test.cpp
├── schema_test.h
├── set_get_test.cpp
├── set_get_test.h
├── test_main.cpp
├── type_test.cpp
├── type_test.h
└── utils.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1)
2 |
3 | set(REDIS_PROTOBUF_VERSION "0.1.0")
4 | message(STATUS "redis-protobuf version: ${REDIS_PROTOBUF_VERSION}")
5 |
6 | project(redis-protobuf LANGUAGES CXX VERSION ${REDIS_PROTOBUF_VERSION})
7 |
8 | set(REDIS_PROTOBUF_DEFAULT_BUILD_TYPE "Release")
9 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
10 | set(CMAKE_BUILD_TYPE ${REDIS_PROTOBUF_DEFAULT_BUILD_TYPE} CACHE STRING "Set build type" FORCE)
11 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo" "MinSizeRel")
12 | endif()
13 | message(STATUS "redis-protobuf build type: ${CMAKE_BUILD_TYPE}")
14 |
15 | set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Werror -fPIC -Wno-unused-parameter")
16 |
17 | set(PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/sw/redis-protobuf)
18 |
19 | file(GLOB PROJECT_SOURCE_FILES "${PROJECT_SOURCE_DIR}/*.cpp" "${PROJECT_SOURCE_DIR}/*.cc")
20 |
21 | set(SHARED_LIB shared)
22 |
23 | add_library(${SHARED_LIB} SHARED ${PROJECT_SOURCE_FILES})
24 |
25 | # protobuf dependency
26 | find_path(PROTOBUF_HEADER google)
27 | target_include_directories(${SHARED_LIB} PUBLIC ${PROTOBUF_HEADER})
28 |
29 | find_library(PROTOBUF_LIB libprotobuf.a)
30 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
31 | target_link_libraries(${SHARED_LIB} -Wl,-force_load ${PROTOBUF_LIB})
32 | target_link_libraries(${SHARED_LIB} z)
33 | else()
34 | target_link_libraries(${SHARED_LIB} -Wl,--whole-archive ${PROTOBUF_LIB} -Wl,--no-whole-archive)
35 | endif()
36 |
37 | set_target_properties(${SHARED_LIB} PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
38 |
39 | set_target_properties(${SHARED_LIB} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
40 |
41 | include(GNUInstallDirs)
42 |
43 | # Install shared lib.
44 | install(TARGETS ${SHARED_LIB}
45 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
46 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
47 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
48 | INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
49 |
--------------------------------------------------------------------------------
/Chinese.md:
--------------------------------------------------------------------------------
1 | 欢迎加入redis-protobuf微信交流群
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | From redis:latest
2 |
3 | ENV LIBDIR /usr/lib/redis/modules
4 | ENV DEPS "make g++ curl cmake unzip"
5 |
6 | # Install dependencies
7 | RUN set -ex;\
8 | deps="$DEPS";\
9 | apt-get update;\
10 | apt-get install -y --no-install-recommends $deps;
11 |
12 | # Install protobuf
13 | RUN set -ex;\
14 | mkdir -p /usr/src;\
15 | cd /usr/src;\
16 | curl -L -k https://github.com/sewenew/redis-protobuf/releases/download/0.0.1/protobuf-3.8.0-map-reflection.tar.gz -o protobuf-3.8.0-map-reflection.tar.gz;\
17 | tar xfz protobuf-3.8.0-map-reflection.tar.gz;\
18 | cd protobuf-3.8.0-map-reflection;\
19 | ./configure "CFLAGS=-fPIC" "CXXFLAGS=-fPIC" --prefix=/usr;\
20 | make -j 4;\
21 | make install;
22 |
23 | # Build redis-protobuf
24 | RUN set -ex;\
25 | cd /usr/src;\
26 | curl -L -k 'https://github.com/sewenew/redis-protobuf/archive/master.zip' -o redis-protobuf.zip;\
27 | unzip redis-protobuf.zip;\
28 | cd redis-protobuf-master;\
29 | mkdir compile;\
30 | cd compile;\
31 | cmake -DCMAKE_BUILD_TYPE=Release ..;\
32 | make;
33 |
34 | # Load redis-protobuf
35 | ENV REDISDIR /usr/lib/redis
36 | RUN set -ex;\
37 | mkdir -p "$REDISDIR/proto/google/protobuf" "$REDISDIR/proto/google/protobuf/util" "$REDISDIR/proto/google/protobuf/compiler" "$REDISDIR/modules" "$REDISDIR/conf";\
38 | cp /usr/src/redis-protobuf-master/docker/example.proto "$REDISDIR/proto";\
39 | cp /usr/src/protobuf-3.8.0-map-reflection/src/google/protobuf/*.proto "$REDISDIR/proto/google/protobuf";\
40 | cp /usr/src/redis-protobuf-master/compile/libredis-protobuf.so "$REDISDIR/modules";\
41 | echo 'loadmodule /usr/lib/redis/modules/libredis-protobuf.so --dir /usr/lib/redis/proto' > "$REDISDIR/conf/redis.conf";
42 |
43 | # Cleanup
44 | RUN set -ex;\
45 | deps="$DEPS";\
46 | apt-get purge -y --auto-remove $deps;\
47 | rm -rf /usr/src/*;
48 |
49 | CMD ["redis-server", "/usr/lib/redis/conf/redis.conf"]
50 |
--------------------------------------------------------------------------------
/docker/example.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | //package sw.redis.pb;
4 |
5 | message SubMsg {
6 | string s = 1;
7 | int32 i = 2;
8 | }
9 |
10 | message Msg {
11 | int32 i = 1;
12 | SubMsg sub = 2;
13 | repeated int32 arr = 3;
14 | map m = 4;
15 | }
16 |
--------------------------------------------------------------------------------
/docker/google/protobuf/any.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option go_package = "github.com/golang/protobuf/ptypes/any";
37 | option java_package = "com.google.protobuf";
38 | option java_outer_classname = "AnyProto";
39 | option java_multiple_files = true;
40 | option objc_class_prefix = "GPB";
41 |
42 | // `Any` contains an arbitrary serialized protocol buffer message along with a
43 | // URL that describes the type of the serialized message.
44 | //
45 | // Protobuf library provides support to pack/unpack Any values in the form
46 | // of utility functions or additional generated methods of the Any type.
47 | //
48 | // Example 1: Pack and unpack a message in C++.
49 | //
50 | // Foo foo = ...;
51 | // Any any;
52 | // any.PackFrom(foo);
53 | // ...
54 | // if (any.UnpackTo(&foo)) {
55 | // ...
56 | // }
57 | //
58 | // Example 2: Pack and unpack a message in Java.
59 | //
60 | // Foo foo = ...;
61 | // Any any = Any.pack(foo);
62 | // ...
63 | // if (any.is(Foo.class)) {
64 | // foo = any.unpack(Foo.class);
65 | // }
66 | //
67 | // Example 3: Pack and unpack a message in Python.
68 | //
69 | // foo = Foo(...)
70 | // any = Any()
71 | // any.Pack(foo)
72 | // ...
73 | // if any.Is(Foo.DESCRIPTOR):
74 | // any.Unpack(foo)
75 | // ...
76 | //
77 | // Example 4: Pack and unpack a message in Go
78 | //
79 | // foo := &pb.Foo{...}
80 | // any, err := ptypes.MarshalAny(foo)
81 | // ...
82 | // foo := &pb.Foo{}
83 | // if err := ptypes.UnmarshalAny(any, foo); err != nil {
84 | // ...
85 | // }
86 | //
87 | // The pack methods provided by protobuf library will by default use
88 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack
89 | // methods only use the fully qualified type name after the last '/'
90 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type
91 | // name "y.z".
92 | //
93 | //
94 | // JSON
95 | // ====
96 | // The JSON representation of an `Any` value uses the regular
97 | // representation of the deserialized, embedded message, with an
98 | // additional field `@type` which contains the type URL. Example:
99 | //
100 | // package google.profile;
101 | // message Person {
102 | // string first_name = 1;
103 | // string last_name = 2;
104 | // }
105 | //
106 | // {
107 | // "@type": "type.googleapis.com/google.profile.Person",
108 | // "firstName": ,
109 | // "lastName":
110 | // }
111 | //
112 | // If the embedded message type is well-known and has a custom JSON
113 | // representation, that representation will be embedded adding a field
114 | // `value` which holds the custom JSON in addition to the `@type`
115 | // field. Example (for message [google.protobuf.Duration][]):
116 | //
117 | // {
118 | // "@type": "type.googleapis.com/google.protobuf.Duration",
119 | // "value": "1.212s"
120 | // }
121 | //
122 | message Any {
123 | // A URL/resource name that uniquely identifies the type of the serialized
124 | // protocol buffer message. This string must contain at least
125 | // one "/" character. The last segment of the URL's path must represent
126 | // the fully qualified name of the type (as in
127 | // `path/google.protobuf.Duration`). The name should be in a canonical form
128 | // (e.g., leading "." is not accepted).
129 | //
130 | // In practice, teams usually precompile into the binary all types that they
131 | // expect it to use in the context of Any. However, for URLs which use the
132 | // scheme `http`, `https`, or no scheme, one can optionally set up a type
133 | // server that maps type URLs to message definitions as follows:
134 | //
135 | // * If no scheme is provided, `https` is assumed.
136 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
137 | // value in binary format, or produce an error.
138 | // * Applications are allowed to cache lookup results based on the
139 | // URL, or have them precompiled into a binary to avoid any
140 | // lookup. Therefore, binary compatibility needs to be preserved
141 | // on changes to types. (Use versioned type names to manage
142 | // breaking changes.)
143 | //
144 | // Note: this functionality is not currently available in the official
145 | // protobuf release, and it is not used for type URLs beginning with
146 | // type.googleapis.com.
147 | //
148 | // Schemes other than `http`, `https` (or the empty scheme) might be
149 | // used with implementation specific semantics.
150 | //
151 | string type_url = 1;
152 |
153 | // Must be a valid serialized protocol buffer of the above specified type.
154 | bytes value = 2;
155 | }
156 |
--------------------------------------------------------------------------------
/docker/google/protobuf/duration.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "github.com/golang/protobuf/ptypes/duration";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "DurationProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // A Duration represents a signed, fixed-length span of time represented
44 | // as a count of seconds and fractions of seconds at nanosecond
45 | // resolution. It is independent of any calendar and concepts like "day"
46 | // or "month". It is related to Timestamp in that the difference between
47 | // two Timestamp values is a Duration and it can be added or subtracted
48 | // from a Timestamp. Range is approximately +-10,000 years.
49 | //
50 | // # Examples
51 | //
52 | // Example 1: Compute Duration from two Timestamps in pseudo code.
53 | //
54 | // Timestamp start = ...;
55 | // Timestamp end = ...;
56 | // Duration duration = ...;
57 | //
58 | // duration.seconds = end.seconds - start.seconds;
59 | // duration.nanos = end.nanos - start.nanos;
60 | //
61 | // if (duration.seconds < 0 && duration.nanos > 0) {
62 | // duration.seconds += 1;
63 | // duration.nanos -= 1000000000;
64 | // } else if (durations.seconds > 0 && duration.nanos < 0) {
65 | // duration.seconds -= 1;
66 | // duration.nanos += 1000000000;
67 | // }
68 | //
69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
70 | //
71 | // Timestamp start = ...;
72 | // Duration duration = ...;
73 | // Timestamp end = ...;
74 | //
75 | // end.seconds = start.seconds + duration.seconds;
76 | // end.nanos = start.nanos + duration.nanos;
77 | //
78 | // if (end.nanos < 0) {
79 | // end.seconds -= 1;
80 | // end.nanos += 1000000000;
81 | // } else if (end.nanos >= 1000000000) {
82 | // end.seconds += 1;
83 | // end.nanos -= 1000000000;
84 | // }
85 | //
86 | // Example 3: Compute Duration from datetime.timedelta in Python.
87 | //
88 | // td = datetime.timedelta(days=3, minutes=10)
89 | // duration = Duration()
90 | // duration.FromTimedelta(td)
91 | //
92 | // # JSON Mapping
93 | //
94 | // In JSON format, the Duration type is encoded as a string rather than an
95 | // object, where the string ends in the suffix "s" (indicating seconds) and
96 | // is preceded by the number of seconds, with nanoseconds expressed as
97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be
98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1
100 | // microsecond should be expressed in JSON format as "3.000001s".
101 | //
102 | //
103 | message Duration {
104 | // Signed seconds of the span of time. Must be from -315,576,000,000
105 | // to +315,576,000,000 inclusive. Note: these bounds are computed from:
106 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
107 | int64 seconds = 1;
108 |
109 | // Signed fractions of a second at nanosecond resolution of the span
110 | // of time. Durations less than one second are represented with a 0
111 | // `seconds` field and a positive or negative `nanos` field. For durations
112 | // of one second or more, a non-zero value for the `nanos` field must be
113 | // of the same sign as the `seconds` field. Must be from -999,999,999
114 | // to +999,999,999 inclusive.
115 | int32 nanos = 2;
116 | }
117 |
--------------------------------------------------------------------------------
/docker/google/protobuf/empty.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option go_package = "github.com/golang/protobuf/ptypes/empty";
37 | option java_package = "com.google.protobuf";
38 | option java_outer_classname = "EmptyProto";
39 | option java_multiple_files = true;
40 | option objc_class_prefix = "GPB";
41 | option cc_enable_arenas = true;
42 |
43 | // A generic empty message that you can re-use to avoid defining duplicated
44 | // empty messages in your APIs. A typical example is to use it as the request
45 | // or the response type of an API method. For instance:
46 | //
47 | // service Foo {
48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
49 | // }
50 | //
51 | // The JSON representation for `Empty` is empty JSON object `{}`.
52 | message Empty {}
53 |
--------------------------------------------------------------------------------
/docker/google/protobuf/struct.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "github.com/golang/protobuf/ptypes/struct;structpb";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "StructProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // `Struct` represents a structured data value, consisting of fields
44 | // which map to dynamically typed values. In some languages, `Struct`
45 | // might be supported by a native representation. For example, in
46 | // scripting languages like JS a struct is represented as an
47 | // object. The details of that representation are described together
48 | // with the proto support for the language.
49 | //
50 | // The JSON representation for `Struct` is JSON object.
51 | message Struct {
52 | // Unordered map of dynamically typed values.
53 | map fields = 1;
54 | }
55 |
56 | // `Value` represents a dynamically typed value which can be either
57 | // null, a number, a string, a boolean, a recursive struct value, or a
58 | // list of values. A producer of value is expected to set one of that
59 | // variants, absence of any variant indicates an error.
60 | //
61 | // The JSON representation for `Value` is JSON value.
62 | message Value {
63 | // The kind of value.
64 | oneof kind {
65 | // Represents a null value.
66 | NullValue null_value = 1;
67 | // Represents a double value.
68 | double number_value = 2;
69 | // Represents a string value.
70 | string string_value = 3;
71 | // Represents a boolean value.
72 | bool bool_value = 4;
73 | // Represents a structured value.
74 | Struct struct_value = 5;
75 | // Represents a repeated `Value`.
76 | ListValue list_value = 6;
77 | }
78 | }
79 |
80 | // `NullValue` is a singleton enumeration to represent the null value for the
81 | // `Value` type union.
82 | //
83 | // The JSON representation for `NullValue` is JSON `null`.
84 | enum NullValue {
85 | // Null value.
86 | NULL_VALUE = 0;
87 | }
88 |
89 | // `ListValue` is a wrapper around a repeated field of values.
90 | //
91 | // The JSON representation for `ListValue` is JSON array.
92 | message ListValue {
93 | // Repeated field of dynamically typed values.
94 | repeated Value values = 1;
95 | }
96 |
--------------------------------------------------------------------------------
/docker/google/protobuf/timestamp.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | syntax = "proto3";
32 |
33 | package google.protobuf;
34 |
35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
36 | option cc_enable_arenas = true;
37 | option go_package = "github.com/golang/protobuf/ptypes/timestamp";
38 | option java_package = "com.google.protobuf";
39 | option java_outer_classname = "TimestampProto";
40 | option java_multiple_files = true;
41 | option objc_class_prefix = "GPB";
42 |
43 | // A Timestamp represents a point in time independent of any time zone or local
44 | // calendar, encoded as a count of seconds and fractions of seconds at
45 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on
46 | // January 1, 1970, in the proleptic Gregorian calendar which extends the
47 | // Gregorian calendar backwards to year one.
48 | //
49 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
50 | // second table is needed for interpretation, using a [24-hour linear
51 | // smear](https://developers.google.com/time/smear).
52 | //
53 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
54 | // restricting to that range, we ensure that we can convert to and from [RFC
55 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
56 | //
57 | // # Examples
58 | //
59 | // Example 1: Compute Timestamp from POSIX `time()`.
60 | //
61 | // Timestamp timestamp;
62 | // timestamp.set_seconds(time(NULL));
63 | // timestamp.set_nanos(0);
64 | //
65 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`.
66 | //
67 | // struct timeval tv;
68 | // gettimeofday(&tv, NULL);
69 | //
70 | // Timestamp timestamp;
71 | // timestamp.set_seconds(tv.tv_sec);
72 | // timestamp.set_nanos(tv.tv_usec * 1000);
73 | //
74 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
75 | //
76 | // FILETIME ft;
77 | // GetSystemTimeAsFileTime(&ft);
78 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
79 | //
80 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
81 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
82 | // Timestamp timestamp;
83 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
84 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
85 | //
86 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
87 | //
88 | // long millis = System.currentTimeMillis();
89 | //
90 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
91 | // .setNanos((int) ((millis % 1000) * 1000000)).build();
92 | //
93 | //
94 | // Example 5: Compute Timestamp from current time in Python.
95 | //
96 | // timestamp = Timestamp()
97 | // timestamp.GetCurrentTime()
98 | //
99 | // # JSON Mapping
100 | //
101 | // In JSON format, the Timestamp type is encoded as a string in the
102 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
103 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
104 | // where {year} is always expressed using four digits while {month}, {day},
105 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
106 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
107 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
108 | // is required. A proto3 JSON serializer should always use UTC (as indicated by
109 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be
110 | // able to accept both UTC and other timezones (as indicated by an offset).
111 | //
112 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
113 | // 01:30 UTC on January 15, 2017.
114 | //
115 | // In JavaScript, one can convert a Date object to this format using the
116 | // standard
117 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
118 | // method. In Python, a standard `datetime.datetime` object can be converted
119 | // to this format using
120 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
121 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
122 | // the Joda Time's [`ISODateTimeFormat.dateTime()`](
123 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
124 | // ) to obtain a formatter capable of generating timestamps in this format.
125 | //
126 | //
127 | message Timestamp {
128 | // Represents seconds of UTC time since Unix epoch
129 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
130 | // 9999-12-31T23:59:59Z inclusive.
131 | int64 seconds = 1;
132 |
133 | // Non-negative fractions of a second at nanosecond resolution. Negative
134 | // second values with fractions must still have non-negative nanos values
135 | // that count forward in time. Must be from 0 to 999,999,999
136 | // inclusive.
137 | int32 nanos = 2;
138 | }
139 |
--------------------------------------------------------------------------------
/docker/google/protobuf/wrappers.proto:
--------------------------------------------------------------------------------
1 | // Protocol Buffers - Google's data interchange format
2 | // Copyright 2008 Google Inc. All rights reserved.
3 | // https://developers.google.com/protocol-buffers/
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are
7 | // met:
8 | //
9 | // * Redistributions of source code must retain the above copyright
10 | // notice, this list of conditions and the following disclaimer.
11 | // * Redistributions in binary form must reproduce the above
12 | // copyright notice, this list of conditions and the following disclaimer
13 | // in the documentation and/or other materials provided with the
14 | // distribution.
15 | // * Neither the name of Google Inc. nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | // Wrappers for primitive (non-message) types. These types are useful
32 | // for embedding primitives in the `google.protobuf.Any` type and for places
33 | // where we need to distinguish between the absence of a primitive
34 | // typed field and its default value.
35 | //
36 | // These wrappers have no meaningful use within repeated fields as they lack
37 | // the ability to detect presence on individual elements.
38 | // These wrappers have no meaningful use within a map or a oneof since
39 | // individual entries of a map or fields of a oneof can already detect presence.
40 |
41 | syntax = "proto3";
42 |
43 | package google.protobuf;
44 |
45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes";
46 | option cc_enable_arenas = true;
47 | option go_package = "github.com/golang/protobuf/ptypes/wrappers";
48 | option java_package = "com.google.protobuf";
49 | option java_outer_classname = "WrappersProto";
50 | option java_multiple_files = true;
51 | option objc_class_prefix = "GPB";
52 |
53 | // Wrapper message for `double`.
54 | //
55 | // The JSON representation for `DoubleValue` is JSON number.
56 | message DoubleValue {
57 | // The double value.
58 | double value = 1;
59 | }
60 |
61 | // Wrapper message for `float`.
62 | //
63 | // The JSON representation for `FloatValue` is JSON number.
64 | message FloatValue {
65 | // The float value.
66 | float value = 1;
67 | }
68 |
69 | // Wrapper message for `int64`.
70 | //
71 | // The JSON representation for `Int64Value` is JSON string.
72 | message Int64Value {
73 | // The int64 value.
74 | int64 value = 1;
75 | }
76 |
77 | // Wrapper message for `uint64`.
78 | //
79 | // The JSON representation for `UInt64Value` is JSON string.
80 | message UInt64Value {
81 | // The uint64 value.
82 | uint64 value = 1;
83 | }
84 |
85 | // Wrapper message for `int32`.
86 | //
87 | // The JSON representation for `Int32Value` is JSON number.
88 | message Int32Value {
89 | // The int32 value.
90 | int32 value = 1;
91 | }
92 |
93 | // Wrapper message for `uint32`.
94 | //
95 | // The JSON representation for `UInt32Value` is JSON number.
96 | message UInt32Value {
97 | // The uint32 value.
98 | uint32 value = 1;
99 | }
100 |
101 | // Wrapper message for `bool`.
102 | //
103 | // The JSON representation for `BoolValue` is JSON `true` and `false`.
104 | message BoolValue {
105 | // The bool value.
106 | bool value = 1;
107 | }
108 |
109 | // Wrapper message for `string`.
110 | //
111 | // The JSON representation for `StringValue` is JSON string.
112 | message StringValue {
113 | // The string value.
114 | string value = 1;
115 | }
116 |
117 | // Wrapper message for `bytes`.
118 | //
119 | // The JSON representation for `BytesValue` is JSON string.
120 | message BytesValue {
121 | // The bytes value.
122 | bytes value = 1;
123 | }
124 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/append_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "append_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 |
21 | namespace sw {
22 |
23 | namespace redis {
24 |
25 | namespace pb {
26 |
27 | int AppendCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
28 | try {
29 | assert(ctx != nullptr);
30 |
31 | auto args = _parse_args(argv, argc);
32 | const auto &path = args.path;
33 | if (path.empty()) {
34 | throw Error("can only call append on array");
35 | }
36 |
37 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::WRITEONLY);
38 | assert(key);
39 |
40 | auto &m = RedisProtobuf::instance();
41 |
42 | long long len = 0;
43 | if (!api::key_exists(key.get(), m.type())) {
44 | auto msg = m.proto_factory()->create(path.type());
45 |
46 | assert(msg != nullptr);
47 | if (msg->GetTypeName() != path.type()) {
48 | throw Error("type mismatch");
49 | }
50 |
51 | MutableFieldRef field(msg.get(), path);
52 | len = _append(field, args.elements);
53 |
54 | if (RedisModule_ModuleTypeSetValue(key.get(),
55 | m.type(),
56 | msg.get()) != REDISMODULE_OK) {
57 | throw Error("failed to set message");
58 | }
59 |
60 | msg.release();
61 | } else {
62 | auto *msg = api::get_msg_by_key(key.get());
63 | assert(msg != nullptr);
64 |
65 | MutableFieldRef field(msg, path);
66 | // TODO: create a new message, and append to that message, then swap to this message.
67 | len = _append(field, args.elements);
68 | }
69 |
70 | RedisModule_ReplyWithLongLong(ctx, len);
71 |
72 | RedisModule_ReplicateVerbatim(ctx);
73 |
74 | return REDISMODULE_OK;
75 | } catch (const WrongArityError &err) {
76 | return RedisModule_WrongArity(ctx);
77 | } catch (const Error &err) {
78 | return api::reply_with_error(ctx, err);
79 | }
80 |
81 | return REDISMODULE_ERR;
82 | }
83 |
84 | AppendCommand::Args AppendCommand::_parse_args(RedisModuleString **argv, int argc) const {
85 | assert(argv != nullptr);
86 |
87 | if (argc < 5) {
88 | throw WrongArityError();
89 | }
90 |
91 | Args args;
92 | args.key_name = argv[1];
93 | args.path = Path(argv[2], argv[3]);
94 | args.elements.reserve(argc - 4);
95 |
96 | for (auto idx = 4; idx != argc; ++idx) {
97 | args.elements.emplace_back(argv[idx]);
98 | }
99 |
100 | return args;
101 | }
102 |
103 | long long AppendCommand::_append(MutableFieldRef &field,
104 | const std::vector &elements) const {
105 | if (field.is_array() && !field.is_array_element()) {
106 | for (const auto &ele : elements) {
107 | _append_arr(field, ele);
108 | }
109 |
110 | return field.size();
111 | } else if (field.type() == gp::FieldDescriptor::CPPTYPE_STRING) {
112 | return _append_str(field, elements);
113 | } else {
114 | throw Error("not an array or string");
115 | }
116 | }
117 |
118 | void AppendCommand::_append_arr(MutableFieldRef &field, const StringView &val) const {
119 | assert(field.is_array() && !field.is_array_element());
120 |
121 | switch (field.type()) {
122 | case gp::FieldDescriptor::CPPTYPE_INT32:
123 | field.add_int32(util::sv_to_int32(val));
124 | break;
125 |
126 | case gp::FieldDescriptor::CPPTYPE_INT64:
127 | field.add_int64(util::sv_to_int64(val));
128 | break;
129 |
130 | case gp::FieldDescriptor::CPPTYPE_UINT32:
131 | field.add_uint32(util::sv_to_uint32(val));
132 | break;
133 |
134 | case gp::FieldDescriptor::CPPTYPE_UINT64:
135 | field.add_uint64(util::sv_to_uint64(val));
136 | break;
137 |
138 | case gp::FieldDescriptor::CPPTYPE_DOUBLE:
139 | field.add_double(util::sv_to_double(val));
140 | break;
141 |
142 | case gp::FieldDescriptor::CPPTYPE_FLOAT:
143 | field.add_float(util::sv_to_float(val));
144 | break;
145 |
146 | case gp::FieldDescriptor::CPPTYPE_BOOL:
147 | field.add_bool(util::sv_to_bool(val));
148 | break;
149 |
150 | case gp::FieldDescriptor::CPPTYPE_ENUM:
151 | field.add_enum(util::sv_to_int32(val));
152 | break;
153 |
154 | case gp::FieldDescriptor::CPPTYPE_STRING:
155 | field.add_string(util::sv_to_string(val));
156 | break;
157 |
158 | case gp::FieldDescriptor::CPPTYPE_MESSAGE:
159 | _add_msg(field, val);
160 | break;
161 |
162 | default:
163 | throw Error("unknown type");
164 | }
165 | }
166 |
167 | long long AppendCommand::_append_str(MutableFieldRef &field,
168 | const std::vector &elements) const {
169 | std::string str;
170 | for (const auto &ele : elements) {
171 | str += std::string(ele.data(), ele.size());
172 | }
173 |
174 | if (field.is_array_element()) {
175 | str = field.get_repeated_string() + str;
176 | field.set_repeated_string(str);
177 | } else {
178 | // TODO: map element
179 | str = field.get_string() + str;
180 | field.set_string(str);
181 | }
182 |
183 | return str.size();
184 | }
185 |
186 | void AppendCommand::_add_msg(MutableFieldRef &field, const StringView &val) const {
187 | auto msg = RedisProtobuf::instance().proto_factory()->create(field.msg_type(), val);
188 | assert(msg);
189 |
190 | field.add_msg(*msg);
191 | }
192 |
193 | }
194 |
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/append_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_APPEND_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_APPEND_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include "utils.h"
24 | #include "field_ref.h"
25 |
26 | namespace sw {
27 |
28 | namespace redis {
29 |
30 | namespace pb {
31 |
32 | // command: PB.APPEND key type path element [element, element...]
33 | // return: Integer reply: return the length of the array after the append operations.
34 | // Or return the length of the string after the append operations.
35 | // error: If the path doesn't exist, or the corresponding field is not an array, or
36 | // a string, return an error reply.
37 | class AppendCommand {
38 | public:
39 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
40 |
41 | private:
42 | struct Args {
43 | RedisModuleString *key_name;
44 | Path path;
45 | std::vector elements;
46 | };
47 |
48 | Args _parse_args(RedisModuleString **argv, int argc) const;
49 |
50 | long long _append(MutableFieldRef &field, const std::vector &elements) const;
51 |
52 | void _append_arr(MutableFieldRef &field, const StringView &val) const;
53 |
54 | long long _append_str(MutableFieldRef &field, const std::vector &elements) const;
55 |
56 | void _add_msg(MutableFieldRef &field, const StringView &val) const;
57 | };
58 |
59 | }
60 |
61 | }
62 |
63 | }
64 |
65 | #endif // end SEWENEW_REDISPROTOBUF_APPEND_COMMANDS_H
66 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/clear_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "clear_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 |
21 | namespace sw {
22 |
23 | namespace redis {
24 |
25 | namespace pb {
26 |
27 | int ClearCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
28 | try {
29 | assert(ctx != nullptr);
30 |
31 | auto args = _parse_args(argv, argc);
32 |
33 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::READONLY);
34 | if (!api::key_exists(key.get(), RedisProtobuf::instance().type())) {
35 | RedisModule_ReplyWithLongLong(ctx, 0);
36 | } else {
37 | auto *msg = api::get_msg_by_key(key.get());
38 | assert(msg != nullptr);
39 |
40 | if (msg->GetTypeName() != args.path.type()) {
41 | throw Error("type mismatch");
42 | }
43 |
44 | _clear(*msg, args.path);
45 |
46 | RedisModule_ReplyWithLongLong(ctx, 1);
47 | }
48 |
49 | RedisModule_ReplicateVerbatim(ctx);
50 |
51 | return REDISMODULE_OK;
52 | } catch (const WrongArityError &err) {
53 | return RedisModule_WrongArity(ctx);
54 | } catch (const Error &err) {
55 | return api::reply_with_error(ctx, err);
56 | }
57 |
58 | return REDISMODULE_ERR;
59 | }
60 |
61 | ClearCommand::Args ClearCommand::_parse_args(RedisModuleString **argv, int argc) const {
62 | assert(argv != nullptr);
63 |
64 | if (argc != 3 && argc != 4) {
65 | throw WrongArityError();
66 | }
67 |
68 | Path path;
69 | if (argc == 3) {
70 | path = Path(argv[2]);
71 | } else {
72 | path = Path(argv[2], argv[3]);
73 | }
74 | return {argv[1], std::move(path)};
75 | }
76 |
77 | void ClearCommand::_clear(gp::Message &msg, const Path &path) const {
78 | if (path.empty()) {
79 | // Clear the message.
80 | msg.Clear();
81 | } else {
82 | // Clear a field.
83 | MutableFieldRef field(&msg, path);
84 | field.clear();
85 | }
86 | }
87 |
88 | }
89 |
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/clear_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_CLEAR_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_CLEAR_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include "utils.h"
23 | #include "field_ref.h"
24 |
25 | namespace sw {
26 |
27 | namespace redis {
28 |
29 | namespace pb {
30 |
31 | // command: PB.CLEAR key type [path]
32 | // return: Integer reply: If the key exist, return 1. Otherwise, return 0.
33 | // error: If the type doesn't match the protobuf message type of the key,
34 | // or the path doesn't exist, return an error reply.
35 | class ClearCommand {
36 | public:
37 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
38 |
39 | private:
40 | struct Args {
41 | RedisModuleString *key_name;
42 | Path path;
43 | };
44 |
45 | Args _parse_args(RedisModuleString **argv, int argc) const;
46 |
47 | void _clear(gp::Message &msg, const Path &path) const;
48 | };
49 |
50 | }
51 |
52 | }
53 |
54 | }
55 |
56 | #endif // end SEWENEW_REDISPROTOBUF_CLEAR_COMMANDS_H
57 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/commands.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "commands.h"
18 | #include "set_command.h"
19 | #include "get_command.h"
20 | #include "type_command.h"
21 | #include "clear_command.h"
22 | #include "len_command.h"
23 | #include "append_command.h"
24 | #include "del_command.h"
25 | #include "schema_command.h"
26 | #include "merge_command.h"
27 | #include "import_command.h"
28 | #include "last_import_command.h"
29 |
30 | namespace sw {
31 |
32 | namespace redis {
33 |
34 | namespace pb {
35 |
36 | namespace cmd {
37 |
38 | void create_commands(RedisModuleCtx *ctx) {
39 | if (RedisModule_CreateCommand(ctx,
40 | "PB.TYPE",
41 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
42 | TypeCommand cmd;
43 | return cmd.run(ctx, argv, argc);
44 | },
45 | "readonly",
46 | 1,
47 | 1,
48 | 1) == REDISMODULE_ERR) {
49 | throw Error("failed to create PB.TYPE command");
50 | }
51 |
52 | if (RedisModule_CreateCommand(ctx,
53 | "PB.SET",
54 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
55 | SetCommand cmd;
56 | return cmd.run(ctx, argv, argc);
57 | },
58 | "write deny-oom",
59 | 1,
60 | 1,
61 | 1) == REDISMODULE_ERR) {
62 | throw Error("fail to create PB.SET command");
63 | }
64 |
65 | if (RedisModule_CreateCommand(ctx,
66 | "PB.GET",
67 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
68 | GetCommand cmd;
69 | return cmd.run(ctx, argv, argc);
70 | },
71 | "readonly",
72 | 1,
73 | 1,
74 | 1) == REDISMODULE_ERR) {
75 | throw Error("failed to create PB.GET command");
76 | }
77 |
78 | if (RedisModule_CreateCommand(ctx,
79 | "PB.CLEAR",
80 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
81 | ClearCommand cmd;
82 | return cmd.run(ctx, argv, argc);
83 | },
84 | "write deny-oom",
85 | 1,
86 | 1,
87 | 1) == REDISMODULE_ERR) {
88 | throw Error("fail to create PB.CLEAR command");
89 | }
90 |
91 | if (RedisModule_CreateCommand(ctx,
92 | "PB.LEN",
93 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
94 | LenCommand cmd;
95 | return cmd.run(ctx, argv, argc);
96 | },
97 | "readonly",
98 | 1,
99 | 1,
100 | 1) == REDISMODULE_ERR) {
101 | throw Error("failed to create PB.LEN command");
102 | }
103 |
104 | if (RedisModule_CreateCommand(ctx,
105 | "PB.APPEND",
106 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
107 | AppendCommand cmd;
108 | return cmd.run(ctx, argv, argc);
109 | },
110 | "write deny-oom",
111 | 1,
112 | 1,
113 | 1) == REDISMODULE_ERR) {
114 | throw Error("fail to create PB.APPEND command");
115 | }
116 |
117 | if (RedisModule_CreateCommand(ctx,
118 | "PB.DEL",
119 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
120 | DelCommand cmd;
121 | return cmd.run(ctx, argv, argc);
122 | },
123 | "write deny-oom",
124 | 1,
125 | 1,
126 | 1) == REDISMODULE_ERR) {
127 | throw Error("fail to create PB.DEL command");
128 | }
129 |
130 | if (RedisModule_CreateCommand(ctx,
131 | "PB.SCHEMA",
132 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
133 | SchemaCommand cmd;
134 | return cmd.run(ctx, argv, argc);
135 | },
136 | "readonly getkeys-api",
137 | 1,
138 | 1,
139 | 1) == REDISMODULE_ERR) {
140 | throw Error("failed to create PB.SCHEMA command");
141 | }
142 |
143 | if (RedisModule_CreateCommand(ctx,
144 | "PB.MERGE",
145 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
146 | MergeCommand cmd;
147 | return cmd.run(ctx, argv, argc);
148 | },
149 | "write deny-oom",
150 | 1,
151 | 1,
152 | 1) == REDISMODULE_ERR) {
153 | throw Error("fail to create PB.MERGE command");
154 | }
155 |
156 | if (RedisModule_CreateCommand(ctx,
157 | "PB.IMPORT",
158 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
159 | ImportCommand cmd;
160 | return cmd.run(ctx, argv, argc);
161 | },
162 | "write deny-oom",
163 | 1,
164 | 1,
165 | 1) == REDISMODULE_ERR) {
166 | throw Error("fail to create PB.IMPORT command");
167 | }
168 |
169 | if (RedisModule_CreateCommand(ctx,
170 | "PB.LASTIMPORT",
171 | [](RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
172 | LastImportCommand cmd;
173 | return cmd.run(ctx, argv, argc);
174 | },
175 | "readonly",
176 | 1,
177 | 1,
178 | 1) == REDISMODULE_ERR) {
179 | throw Error("failed to create PB.LASTIMPORT command");
180 | }
181 | }
182 |
183 | }
184 |
185 | }
186 |
187 | }
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/commands.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_COMMANDS_H
19 |
20 | #include "module_api.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace cmd {
29 |
30 | void create_commands(RedisModuleCtx *ctx);
31 |
32 | }
33 |
34 | }
35 |
36 | }
37 |
38 | }
39 |
40 | #endif // end SEWENEW_REDISPROTOBUF_COMMANDS_H
41 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/del_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "del_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 |
21 | namespace sw {
22 |
23 | namespace redis {
24 |
25 | namespace pb {
26 |
27 | int DelCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
28 | try {
29 | assert(ctx != nullptr);
30 |
31 | auto args = _parse_args(argv, argc);
32 |
33 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::WRITEONLY);
34 | assert(key);
35 |
36 | if (!api::key_exists(key.get(), RedisProtobuf::instance().type())) {
37 | RedisModule_ReplyWithLongLong(ctx, 0);
38 | } else {
39 | auto *msg = api::get_msg_by_key(key.get());
40 | assert(msg != nullptr);
41 |
42 | const auto &path = args.path;
43 | if (msg->GetTypeName() != path.type()) {
44 | throw Error("type mismatch");
45 | }
46 |
47 | if (path.empty()) {
48 | // Delete key.
49 | RedisModule_DeleteKey(key.get());
50 | } else {
51 | // Delete an item from array or map.
52 | _del(*msg, path);
53 | }
54 |
55 | RedisModule_ReplyWithLongLong(ctx, 1);
56 | }
57 |
58 | RedisModule_ReplicateVerbatim(ctx);
59 |
60 | return REDISMODULE_OK;
61 | } catch (const WrongArityError &err) {
62 | return RedisModule_WrongArity(ctx);
63 | } catch (const Error &err) {
64 | return api::reply_with_error(ctx, err);
65 | }
66 |
67 | return REDISMODULE_ERR;
68 | }
69 |
70 | DelCommand::Args DelCommand::_parse_args(RedisModuleString **argv, int argc) const {
71 | assert(argv != nullptr);
72 |
73 | if (argc != 3 && argc != 4) {
74 | throw WrongArityError();
75 | }
76 |
77 | Path path;
78 | if (argc == 3) {
79 | path = Path(argv[2]);
80 | } else {
81 | path = Path(argv[2], argv[3]);
82 | }
83 |
84 | return {argv[1], std::move(path)};
85 | }
86 |
87 | void DelCommand::_del(gp::Message &msg, const Path &path) const {
88 | MutableFieldRef field(&msg, path);
89 |
90 | if (!field.is_array_element()) {
91 | // TODO: support map element
92 | throw Error("not an array or map");
93 | }
94 |
95 | field.del();
96 | }
97 |
98 | }
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/del_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_DEL_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_DEL_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include "utils.h"
24 | #include "field_ref.h"
25 |
26 | namespace sw {
27 |
28 | namespace redis {
29 |
30 | namespace pb {
31 |
32 | // command: PB.DEL key type [path]
33 | // return: Integer reply: return 1, if the key exists. 0, otherwise.
34 | // error: If the path doesn't exist, or the corresponding field is not an array,
35 | // or map or the message itself, return an error reply.
36 | class DelCommand {
37 | public:
38 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
39 |
40 | private:
41 | struct Args {
42 | RedisModuleString *key_name;
43 | Path path;
44 | };
45 |
46 | Args _parse_args(RedisModuleString **argv, int argc) const;
47 |
48 | void _del(gp::Message &msg, const Path &path) const;
49 | };
50 |
51 | }
52 |
53 | }
54 |
55 | }
56 |
57 | #endif // end SEWENEW_REDISPROTOBUF_DEL_COMMANDS_H
58 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/errors.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_ERRORS_H
18 | #define SEWENEW_REDISPROTOBUF_ERRORS_H
19 |
20 | #include
21 | #include
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | class Error : public std::exception {
30 | public:
31 | explicit Error(const std::string &msg) : _msg(msg) {}
32 |
33 | Error(const Error &) = default;
34 | Error& operator=(const Error &) = default;
35 |
36 | Error(Error &&) = default;
37 | Error& operator=(Error &&) = default;
38 |
39 | virtual ~Error() = default;
40 |
41 | virtual const char* what() const noexcept {
42 | return _msg.data();
43 | }
44 |
45 | private:
46 | std::string _msg;
47 | };
48 |
49 | class WrongTypeError : public Error {
50 | public:
51 | explicit WrongTypeError(const std::string &msg) : Error(msg) {}
52 |
53 | WrongTypeError(const WrongTypeError &) = default;
54 | WrongTypeError& operator=(const WrongTypeError &) = default;
55 |
56 | WrongTypeError(WrongTypeError &&) = default;
57 | WrongTypeError& operator=(WrongTypeError &&) = default;
58 |
59 | virtual ~WrongTypeError() = default;
60 | };
61 |
62 | class WrongArityError : public Error {
63 | public:
64 | WrongArityError() : Error("WrongArity") {}
65 |
66 | WrongArityError(const WrongArityError &) = default;
67 | WrongArityError& operator=(const WrongArityError &) = default;
68 |
69 | WrongArityError(WrongArityError &&) = default;
70 | WrongArityError& operator=(WrongArityError &&) = default;
71 |
72 | virtual ~WrongArityError() = default;
73 | };
74 |
75 | class MapKeyNotFoundError : public Error {
76 | public:
77 | explicit MapKeyNotFoundError(const std::string &key) : Error("key not found: " + key) {}
78 |
79 | MapKeyNotFoundError(const MapKeyNotFoundError &) = default;
80 | MapKeyNotFoundError& operator=(const MapKeyNotFoundError &) = default;
81 |
82 | MapKeyNotFoundError(MapKeyNotFoundError &&) = default;
83 | MapKeyNotFoundError& operator=(MapKeyNotFoundError &&) = default;
84 |
85 | virtual ~MapKeyNotFoundError() = default;
86 | };
87 |
88 | }
89 |
90 | }
91 |
92 | }
93 |
94 | #endif // end SEWENEW_REDISPROTOBUF_ERRORS_H
95 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/get_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_GET_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_GET_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include "utils.h"
22 | #include "field_ref.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | // command: PB.GET key [--FORMAT BINARY|JSON] type [path]
31 | // return: If no path is specified, return the protobuf message of the key
32 | // as a bulk string reply. If path is specified, return the value
33 | // of the field specified with the path, and the reply type depends
34 | // on the definition of the protobuf. If the key doesn't exist,
35 | // return a nil reply.
36 | // error: If the path doesn't exist, or type mismatch return an error reply.
37 | class GetCommand {
38 | public:
39 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
40 |
41 | private:
42 | struct Args {
43 | RedisModuleString *key_name;
44 |
45 | enum class Format {
46 | BINARY = 0,
47 | JSON,
48 | NONE
49 | };
50 |
51 | Format format = Format::NONE;
52 |
53 | Path path;
54 | };
55 |
56 | Args _parse_args(RedisModuleString **argv, int argc) const;
57 |
58 | int _parse_opts(RedisModuleString **argv, int argc, Args &args) const;
59 |
60 | Args::Format _parse_format(const StringView &format) const;
61 |
62 | void _reply_with_nil(RedisModuleCtx *ctx) const;
63 |
64 | void _reply_with_msg(RedisModuleCtx *ctx,
65 | gp::Message &msg,
66 | const Args &args) const;
67 |
68 | void _get_scalar_field(RedisModuleCtx *ctx,
69 | const ConstFieldRef &field,
70 | Args::Format format) const;
71 |
72 | void _get_array_element(RedisModuleCtx *ctx,
73 | const ConstFieldRef &field,
74 | Args::Format format) const;
75 |
76 | void _get_array(RedisModuleCtx *ctx,
77 | const ConstFieldRef &field,
78 | Args::Format format) const;
79 |
80 | void _get_map_element(RedisModuleCtx *ctx,
81 | const ConstFieldRef &field,
82 | Args::Format format) const;
83 |
84 | void _get_map(RedisModuleCtx *ctx,
85 | const ConstFieldRef &field,
86 | Args::Format format) const;
87 |
88 | void _get_map_kv(RedisModuleCtx *ctx,
89 | const ConstFieldRef &field,
90 | Args::Format format,
91 | const gp::MapKey &key,
92 | const gp::MapValueRef &value) const;
93 |
94 | void _get_msg(RedisModuleCtx *ctx,
95 | const gp::Message &msg,
96 | Args::Format format) const;
97 |
98 | void _get_field(RedisModuleCtx *ctx,
99 | const ConstFieldRef &field,
100 | Args::Format format) const;
101 | };
102 |
103 | }
104 |
105 | }
106 |
107 | }
108 |
109 | #endif // end SEWENEW_REDISPROTOBUF_GET_COMMANDS_H
110 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/import_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "import_command.h"
18 | #include
19 | #include "utils.h"
20 | #include "errors.h"
21 | #include "redis_protobuf.h"
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | int ImportCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
30 | try {
31 | assert(ctx != nullptr);
32 |
33 | auto args = _parse_args(argv, argc);
34 |
35 | auto &m= RedisProtobuf::instance();
36 | m.proto_factory()->load(args.filename, args.content);
37 |
38 | RedisModule_ReplicateVerbatim(ctx);
39 |
40 | RedisModule_ReplyWithSimpleString(ctx, "OK");
41 |
42 | return REDISMODULE_OK;
43 | } catch (const WrongArityError &err) {
44 | return RedisModule_WrongArity(ctx);
45 | } catch (const Error &err) {
46 | return api::reply_with_error(ctx, err);
47 | }
48 |
49 | return REDISMODULE_ERR;
50 | }
51 |
52 | auto ImportCommand::_parse_args(RedisModuleString **argv, int argc) const -> Args {
53 | assert(argv != nullptr);
54 |
55 | if (argc != 3) {
56 | throw WrongArityError();
57 | }
58 |
59 | Args args;
60 | args.filename = util::sv_to_string(argv[1]);
61 | args.content = util::sv_to_string(argv[2]);
62 |
63 | return args;
64 | }
65 |
66 | }
67 |
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/import_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_IMPORT_COMMAND_H
18 | #define SEWENEW_REDISPROTOBUF_IMPORT_COMMAND_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include
24 | #include "utils.h"
25 | #include "field_ref.h"
26 |
27 | namespace sw {
28 |
29 | namespace redis {
30 |
31 | namespace pb {
32 |
33 | // command: PB.IMPORT file-path content
34 | // return: OK status reply.
35 | // error: If failing to import, return an error reply.
36 | class ImportCommand {
37 | public:
38 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
39 |
40 | private:
41 | struct Args {
42 | std::string filename;
43 | std::string content;
44 | };
45 |
46 | Args _parse_args(RedisModuleString **argv, int argc) const;
47 | };
48 |
49 | }
50 |
51 | }
52 |
53 | }
54 |
55 | #endif // end SEWENEW_REDISPROTOBUF_IMPORT_COMMAND_H
56 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/last_import_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "last_import_command.h"
18 | #include
19 | #include "utils.h"
20 | #include "errors.h"
21 | #include "redis_protobuf.h"
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | int LastImportCommand::run(RedisModuleCtx *ctx, RedisModuleString ** /*argv*/, int /*argc*/) const {
30 | try {
31 | assert(ctx != nullptr);
32 |
33 | auto &m = RedisProtobuf::instance();
34 | auto last_loaded_files = m.proto_factory()->last_loaded();
35 |
36 | RedisModule_ReplyWithArray(ctx, last_loaded_files.size());
37 |
38 | for (const auto &ele : last_loaded_files) {
39 | const auto &filename = ele.first;
40 | const auto &status = ele.second;
41 |
42 | RedisModule_ReplyWithArray(ctx, 2);
43 |
44 | RedisModule_ReplyWithStringBuffer(ctx, filename.data(), filename.size());
45 | RedisModule_ReplyWithStringBuffer(ctx, status.data(), status.size());
46 | }
47 |
48 | return REDISMODULE_OK;
49 | } catch (const WrongArityError &err) {
50 | return RedisModule_WrongArity(ctx);
51 | } catch (const Error &err) {
52 | return api::reply_with_error(ctx, err);
53 | }
54 |
55 | return REDISMODULE_ERR;
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/last_import_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_LAST_IMPORT_COMMAND_H
18 | #define SEWENEW_REDISPROTOBUF_LAST_IMPORT_COMMAND_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include
24 | #include "utils.h"
25 | #include "field_ref.h"
26 |
27 | namespace sw {
28 |
29 | namespace redis {
30 |
31 | namespace pb {
32 |
33 | // command: PB.LASTIMPORT
34 | // return: Array reply of the status of last imported proto files.
35 | // note: This command returns status of all imported proto files since last
36 | // call to this command. Once this command is called, the underlying
37 | // records will be cleared.
38 | class LastImportCommand {
39 | public:
40 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
41 | };
42 |
43 | }
44 |
45 | }
46 |
47 | }
48 |
49 | #endif // end SEWENEW_REDISPROTOBUF_LAST_IMPORT_COMMAND_H
50 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/len_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "len_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 | #include "utils.h"
21 | #include "field_ref.h"
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | int LenCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
30 | try {
31 | assert(ctx != nullptr);
32 |
33 | auto args = _parse_args(argv, argc);
34 |
35 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::READONLY);
36 | if (!api::key_exists(key.get(), RedisProtobuf::instance().type())) {
37 | RedisModule_ReplyWithLongLong(ctx, 0);
38 | } else {
39 | auto *msg = api::get_msg_by_key(key.get());
40 | assert(msg != nullptr);
41 |
42 | auto len = _len(*msg, args.path);
43 | RedisModule_ReplyWithLongLong(ctx, len);
44 | }
45 |
46 | return REDISMODULE_OK;
47 | } catch (const WrongArityError &err) {
48 | return RedisModule_WrongArity(ctx);
49 | } catch (const Error &err) {
50 | return api::reply_with_error(ctx, err);
51 | }
52 | }
53 |
54 | LenCommand::Args LenCommand::_parse_args(RedisModuleString **argv, int argc) const {
55 | assert(argv != nullptr);
56 |
57 | if (argc != 3 && argc != 4) {
58 | throw WrongArityError();
59 | }
60 |
61 | Path path;
62 | if (argc == 3) {
63 | path = Path(argv[2]);
64 | } else {
65 | path = Path(argv[2], argv[3]);
66 | }
67 |
68 | return {argv[1], std::move(path)};
69 | }
70 |
71 | long long LenCommand::_len(gp::Message &msg, const Path &path) const {
72 | if (msg.GetTypeName() != path.type()) {
73 | throw Error("type mismatch");
74 | }
75 |
76 | if (path.empty()) {
77 | // Return the length of the message.
78 | return msg.ByteSizeLong();
79 | }
80 |
81 | return _len(ConstFieldRef(&msg, path));
82 | }
83 |
84 | long long LenCommand::_len(const ConstFieldRef &field) const {
85 | if (field.is_map() || field.is_array()) {
86 | return field.size();
87 | }
88 |
89 | // Scalar type.
90 | switch (field.type()) {
91 | case gp::FieldDescriptor::CPPTYPE_MESSAGE:
92 | return field.get_msg().ByteSizeLong();
93 |
94 | case gp::FieldDescriptor::CPPTYPE_STRING:
95 | // TODO: use GetStringReference instead.
96 | return field.get_string().size();
97 |
98 | default:
99 | throw Error("cannot get length of this field");
100 | }
101 | }
102 |
103 | }
104 |
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/len_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_LEN_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_LEN_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include "utils.h"
22 | #include "field_ref.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | // command: PB.LEN key type [path]
31 | // return: Integer reply: If the specified path is a string, return the
32 | // length of the string in bytes; if the field is an array or a map,
33 | // return the size of the array or map. If the field is a message,
34 | // return the size of the message in bytes, i.e. Message::ByteSizeLong.
35 | // If the key doesn't exist, return 0.
36 | // error: If the path doesn't exist, or the corresponding field is not a
37 | // message or a string or an array or a map, return an error reply.
38 | class LenCommand {
39 | public:
40 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
41 |
42 | private:
43 | struct Args {
44 | RedisModuleString *key_name;
45 | Path path;
46 | };
47 |
48 | Args _parse_args(RedisModuleString **argv, int argc) const;
49 |
50 | long long _len(gp::Message &msg, const Path &path) const;
51 |
52 | long long _len(const ConstFieldRef &field) const;
53 | };
54 |
55 | }
56 |
57 | }
58 |
59 | }
60 |
61 | #endif // end SEWENEW_REDISPROTOBUF_LEN_COMMANDS_H
62 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/merge_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "merge_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 | #include "utils.h"
21 | #include "field_ref.h"
22 | #include "set_command.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | int MergeCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
31 | try {
32 | assert(ctx != nullptr);
33 |
34 | auto args = _parse_args(argv, argc);
35 |
36 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::WRITEONLY);
37 | if (!api::key_exists(key.get(), RedisProtobuf::instance().type())) {
38 | SetCommand set_cmd;
39 | set_cmd._run(ctx, argv, argc);
40 |
41 | return RedisModule_ReplyWithLongLong(ctx, 0);
42 | }
43 |
44 | auto *msg = api::get_msg_by_key(key.get());
45 | assert(msg != nullptr);
46 |
47 | _merge(args, *msg);
48 |
49 | RedisModule_ReplyWithLongLong(ctx, 1);
50 |
51 | RedisModule_ReplicateVerbatim(ctx);
52 |
53 | return REDISMODULE_OK;
54 | } catch (const WrongArityError &err) {
55 | return RedisModule_WrongArity(ctx);
56 | } catch (const Error &err) {
57 | return api::reply_with_error(ctx, err);
58 | }
59 |
60 | return REDISMODULE_ERR;
61 | }
62 |
63 | MergeCommand::Args MergeCommand::_parse_args(RedisModuleString **argv, int argc) const {
64 | assert(argv != nullptr);
65 |
66 | if (argc != 4 && argc != 5) {
67 | throw WrongArityError();
68 | }
69 |
70 | Path path;
71 | StringView val;
72 | if (argc == 4) {
73 | path = Path(argv[2]);
74 | val = StringView(argv[3]);
75 | } else {
76 | path = Path(argv[2], argv[3]);
77 | val = StringView(argv[4]);
78 | }
79 |
80 | return {argv[1], std::move(path), std::move(val)};
81 | }
82 |
83 | void MergeCommand::_merge(const Args &args, gp::Message &msg) const {
84 | const auto &path = args.path;
85 | if (path.empty()) {
86 | _merge_msg(path.type(), args.val, msg);
87 | } else {
88 | _merge_sub_msg(path, args.val, msg);
89 | }
90 | }
91 |
92 | void MergeCommand::_merge_msg(const std::string &type,
93 | const StringView &val,
94 | gp::Message &msg) const {
95 | if (type != msg.GetTypeName()) {
96 | throw Error("type mismatch");
97 | }
98 |
99 | auto other = RedisProtobuf::instance().proto_factory()->create(type, val);
100 | assert(other);
101 |
102 | msg.MergeFrom(*other);
103 | }
104 |
105 | void MergeCommand::_merge_sub_msg(const Path &path,
106 | const StringView &val,
107 | gp::Message &msg) const {
108 | MutableFieldRef field(&msg, path);
109 | auto sub_msg = RedisProtobuf::instance().proto_factory()->create(field.msg_type(), val);
110 | assert(sub_msg);
111 |
112 | field.merge(*sub_msg);
113 | }
114 |
115 | }
116 |
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/merge_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_MERGE_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_MERGE_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include "utils.h"
23 | #include "field_ref.h"
24 |
25 | namespace sw {
26 |
27 | namespace redis {
28 |
29 | namespace pb {
30 |
31 | // command: PB.MERGE key type [path] value
32 | // return: Integer reply: If the key exists, return 1. Otherwise, return 0.
33 | // If key doesn't exist, this command behaves as PB.SET.
34 | // error: If the type doesn't match the protobuf message type of the key,
35 | // or path doesn't exist, return an error reply.
36 | class MergeCommand {
37 | public:
38 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
39 |
40 | private:
41 | struct Args {
42 | RedisModuleString *key_name;
43 | Path path;
44 | StringView val;
45 | };
46 |
47 | Args _parse_args(RedisModuleString **argv, int argc) const;
48 |
49 | void _merge(const Args &args, gp::Message &msg) const;
50 |
51 | void _merge_msg(const std::string &type, const StringView &val, gp::Message &msg) const;
52 |
53 | void _merge_sub_msg(const Path &path, const StringView &val, gp::Message &msg) const;
54 | };
55 |
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | #endif // end SEWENEW_REDISPROTOBUF_MERGE_COMMANDS_H
63 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/module_api.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "module_api.h"
18 | #include
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace api {
27 |
28 | RedisKey open_key(RedisModuleCtx *ctx, RedisModuleString *name, KeyMode key_mode) {
29 | if (name == nullptr) {
30 | throw Error("cannot open key with a null name");
31 | }
32 |
33 | int mode = 0;
34 | switch (key_mode) {
35 | case KeyMode::READONLY:
36 | mode = REDISMODULE_READ;
37 | break;
38 |
39 | case KeyMode::WRITEONLY:
40 | mode = REDISMODULE_WRITE;
41 | break;
42 |
43 | case KeyMode::READWRITE:
44 | mode = REDISMODULE_READ | REDISMODULE_WRITE;
45 | break;
46 |
47 | default:
48 | assert(false);
49 | }
50 |
51 | return RedisKey(static_cast(RedisModule_OpenKey(ctx, name, mode)));
52 | }
53 |
54 | bool key_exists(RedisModuleKey *key, RedisModuleType *key_type) {
55 | // key can be nullptr.
56 | auto type = RedisModule_KeyType(key);
57 | if (type == REDISMODULE_KEYTYPE_EMPTY) {
58 | return false;
59 | }
60 |
61 | if (RedisModule_ModuleTypeGetType(key) == key_type) {
62 | return true;
63 | }
64 |
65 | throw WrongTypeError(REDISMODULE_ERRORMSG_WRONGTYPE);
66 | }
67 |
68 | int reply_with_error(RedisModuleCtx *ctx, const Error &err) {
69 | auto msg = std::string("ERR ") + err.what();
70 |
71 | return RedisModule_ReplyWithError(ctx, msg.data());
72 | }
73 |
74 | google::protobuf::Message* get_msg_by_key(RedisModuleKey *key) {
75 | auto *msg = static_cast(RedisModule_ModuleTypeGetValue(key));
76 | if (msg == nullptr) {
77 | throw Error("failed to get message by key");
78 | }
79 |
80 | return msg;
81 | }
82 |
83 | }
84 |
85 | }
86 |
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/module_api.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_MODULE_API_H
18 | #define SEWENEW_REDISPROTOBUF_MODULE_API_H
19 |
20 | #ifdef __cplusplus
21 |
22 | extern "C" {
23 |
24 | #endif
25 |
26 | #include "redismodule.h"
27 |
28 | #ifdef __cplusplus
29 |
30 | }
31 |
32 | #endif
33 |
34 | #include
35 | #include
36 | #include "errors.h"
37 |
38 | namespace sw {
39 |
40 | namespace redis {
41 |
42 | namespace pb {
43 |
44 | namespace api {
45 |
46 | template
47 | void warning(RedisModuleCtx *ctx, const char *fmt, Args &&...args) {
48 | RedisModule_Log(ctx, "warning", fmt, std::forward(args)...);
49 | }
50 |
51 | template
52 | void notice(RedisModuleCtx *ctx, const char *fmt, Args &&...args) {
53 | RedisModule_Log(ctx, "notice", fmt, std::forward(args)...);
54 | }
55 |
56 | template
57 | void debug(RedisModuleCtx *ctx, const char *fmt, Args &&...args) {
58 | RedisModule_Log(ctx, "debug", fmt, std::forward(args)...);
59 | }
60 |
61 | template
62 | void verbose(RedisModuleCtx *ctx, const char *fmt, Args &&...args) {
63 | RedisModule_Log(ctx, "verbose", fmt, std::forward(args)...);
64 | }
65 |
66 | struct RedisKeyCloser {
67 | void operator()(RedisModuleKey *key) const {
68 | RedisModule_CloseKey(key);
69 | }
70 | };
71 |
72 | using RedisKey = std::unique_ptr;
73 |
74 | enum class KeyMode {
75 | READONLY,
76 | WRITEONLY,
77 | READWRITE
78 | };
79 |
80 | RedisKey open_key(RedisModuleCtx *ctx, RedisModuleString *name, KeyMode mode);
81 |
82 | // If key doesn't exist return false.
83 | // If key type is NOT *key_type*, throw WrongTypeError.
84 | // Otherwise, return true.
85 | bool key_exists(RedisModuleKey *key, RedisModuleType *key_type);
86 |
87 | int reply_with_error(RedisModuleCtx *ctx, const Error &err);
88 |
89 | google::protobuf::Message* get_msg_by_key(RedisModuleKey *key);
90 |
91 | }
92 |
93 | }
94 |
95 | }
96 |
97 | }
98 |
99 | #endif // end SEWENEW_REDISPROTOBUF_MODULE_API_H
100 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/module_entry.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "module_entry.h"
18 | #include
19 | #include "redis_protobuf.h"
20 | #include "errors.h"
21 | #include "module_api.h"
22 |
23 | int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
24 | assert(ctx != nullptr);
25 |
26 | using namespace sw::redis::pb;
27 |
28 | try {
29 | auto &m = RedisProtobuf::instance();
30 |
31 | m.load(ctx, argv, argc);
32 | } catch (const Error &e) {
33 | api::warning(ctx, "%s", e.what());
34 | return REDISMODULE_ERR;
35 | }
36 |
37 | return REDISMODULE_OK;
38 | }
39 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/module_entry.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_MODULE_ENTRY_H
18 | #define SEWENEW_REDISPROTOBUF_MODULE_ENTRY_H
19 |
20 | #include "module_api.h"
21 |
22 | #ifdef __cplusplus
23 |
24 | extern "C" {
25 |
26 | #endif
27 |
28 | int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
29 |
30 | #ifdef __cplusplus
31 |
32 | }
33 |
34 | #endif
35 |
36 | #endif // end SEWENEW_REDISPROTOBUF_MODULE_ENTRY_H
37 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/options.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "options.h"
18 | #include
19 | #include "redis_protobuf.h"
20 | #include "errors.h"
21 | #include "utils.h"
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | void Options::load(RedisModuleString **argv, int argc) {
30 | Options opts;
31 |
32 | auto idx = 0;
33 | while (idx < argc) {
34 | auto opt = StringView(argv[idx]);
35 |
36 | if (util::str_case_equal(opt, "--DIR")) {
37 | if (!opts.proto_dir.empty()) {
38 | throw Error("duplicate --DIR option");
39 | }
40 |
41 | ++idx;
42 |
43 | opts.proto_dir = util::sv_to_string(StringView(argv[idx]));
44 | } else {
45 | throw Error("unknown option: " + util::sv_to_string(opt));
46 | }
47 |
48 | ++idx;
49 | }
50 |
51 | if (opts.proto_dir.empty()) {
52 | throw Error("option '--DIR dir' is required");
53 | }
54 |
55 | *this = std::move(opts);
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/options.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_OPTIONS_H
18 | #define SEWENEW_REDISPROTOBUF_OPTIONS_H
19 |
20 | #include "module_api.h"
21 | #include
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | struct Options {
30 | void load(RedisModuleString **argv, int argc);
31 |
32 | std::string proto_dir;
33 | };
34 |
35 | }
36 |
37 | }
38 |
39 | }
40 |
41 | #endif // end SEWENEW_REDISPROTOBUF_OPTIONS_H
42 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/path.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "path.h"
18 | #include "errors.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | Path::Path(const StringView &type, const StringView &path) :
27 | _type(type.data(), type.size()), _fields(_parse_fields(path)) {}
28 |
29 | std::vector Path::_parse_fields(const StringView &path) const {
30 | if (path.size() <= 1) {
31 | throw Error("empty path");
32 | }
33 |
34 | if (*(path.data()) != '/') {
35 | throw Error("invalid path: should begin with /");
36 | }
37 |
38 | std::vector fields;
39 | auto start = 1U;
40 | const auto *ptr = path.data();
41 | for (auto idx = start; idx != path.size(); ++idx) {
42 | if (ptr[idx] == '/') {
43 | if (idx <= start) {
44 | throw Error("empty field");
45 | }
46 |
47 | fields.emplace_back(ptr + start, idx - start);
48 | start = idx + 1;
49 | }
50 | }
51 |
52 | if (path.size() <= start) {
53 | throw Error("empty field");
54 | }
55 |
56 | fields.emplace_back(ptr + start, path.size() - start);
57 |
58 | return fields;
59 | }
60 |
61 | }
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/path.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_PATH_H
18 | #define SEWENEW_REDISPROTOBUF_PATH_H
19 |
20 | #include
21 | #include
22 | #include "utils.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | class Path {
31 | public:
32 | Path() = default;
33 |
34 | Path(const StringView &type, const StringView &path);
35 |
36 | explicit Path(const StringView &type) : _type(type.data(), type.size()) {}
37 |
38 | const std::string& type() const {
39 | return _type;
40 | }
41 |
42 | const std::vector& fields() const {
43 | return _fields;
44 | }
45 |
46 | bool empty() const {
47 | return _fields.empty();
48 | }
49 |
50 | private:
51 | std::vector _parse_fields(const StringView &path) const;
52 |
53 | std::string _type;
54 |
55 | std::vector _fields;
56 | };
57 |
58 | }
59 |
60 | }
61 |
62 | }
63 |
64 | #endif // end SEWENEW_REDISPROTOBUF_PATH_H
65 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/proto_factory.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "proto_factory.h"
18 | #include
19 | #include
20 | #include "utils.h"
21 | #include "errors.h"
22 |
23 | namespace sw {
24 |
25 | namespace redis {
26 |
27 | namespace pb {
28 |
29 | void FactoryErrorCollector::_add_error(const std::string &type,
30 | const std::string &filename,
31 | int line,
32 | int column,
33 | const std::string &message) {
34 | auto err = type + ":" + filename + ":"
35 | + std::to_string(line) + ":"
36 | + std::to_string(column) + ":"
37 | + message;
38 |
39 | _errors.push_back(std::move(err));
40 | }
41 |
42 | std::string FactoryErrorCollector::last_errors() const {
43 | std::string err_str;
44 | for (const auto &err : _errors) {
45 | if (!err_str.empty()) {
46 | err_str += "\n";
47 | }
48 |
49 | err_str += err;
50 | }
51 |
52 | return err_str;
53 | }
54 |
55 | ProtoFactory::ProtoFactory(const std::string &proto_dir) :
56 | _proto_dir(_canonicalize_path(proto_dir)),
57 | _importer(&_source_tree, &_error_collector) {
58 | _source_tree.MapPath("", _proto_dir);
59 |
60 | _load_protos(_proto_dir);
61 |
62 | _async_loader = std::thread([this]() { this->_async_load(); });
63 | }
64 |
65 | ProtoFactory::~ProtoFactory() {
66 | _stop_loader = true;
67 | _cv.notify_one();
68 | if (_async_loader.joinable()) {
69 | _async_loader.join();
70 | }
71 | }
72 |
73 | MsgUPtr ProtoFactory::create(const std::string &type) {
74 | const auto *desc = descriptor(type);
75 | if (desc == nullptr) {
76 | throw Error("unknown protobuf type: " + type);
77 | }
78 |
79 | const auto *prototype = _factory.GetPrototype(desc);
80 |
81 | assert(prototype != nullptr);
82 |
83 | return MsgUPtr(prototype->New());
84 | }
85 |
86 | MsgUPtr ProtoFactory::create(const std::string &type, const StringView &sv) {
87 | auto msg = create(type);
88 |
89 | const auto *ptr = sv.data();
90 | auto len = sv.size();
91 | if (len >= 2 && ptr[0] == '{' && ptr[len - 1] == '}') {
92 | auto status = gp::util::JsonStringToMessage(gp::StringPiece(ptr, len), msg.get());
93 | if (!status.ok()) {
94 | throw Error("failed to parse json to " + type + ": " + status.ToString());
95 | }
96 | } else {
97 | if (!msg->ParseFromArray(ptr, len)) {
98 | throw Error("failed to parse binary to " + type);
99 | }
100 | }
101 |
102 | return msg;
103 | }
104 |
105 | const gp::Descriptor* ProtoFactory::descriptor(const std::string &type) {
106 | auto iter = _descriptor_cache.find(type);
107 | if (iter != _descriptor_cache.end()) {
108 | return iter->second;
109 | }
110 |
111 | const auto *desc = _importer.pool()->FindMessageTypeByName(type);
112 | if (desc != nullptr) {
113 | _descriptor_cache.emplace(type, desc);
114 | }
115 |
116 | return desc;
117 | }
118 |
119 | void ProtoFactory::load(const std::string &filename, const std::string &content) {
120 | {
121 | std::lock_guard lock(_mtx);
122 |
123 | _tasks[filename] = content;
124 | }
125 |
126 | _cv.notify_one();
127 | }
128 |
129 | std::unordered_map ProtoFactory::last_loaded() {
130 | std::unordered_map last_loaded_files;
131 | {
132 | std::lock_guard lock(_mtx);
133 |
134 | _last_loaded_files.swap(last_loaded_files);
135 | }
136 |
137 | return last_loaded_files;
138 | }
139 |
140 | void ProtoFactory::_load_protos(const std::string &proto_dir) {
141 | auto files = io::list_dir(proto_dir);
142 | for (const auto &file : files) {
143 | if (!io::is_regular(file) || io::extension(file) != "proto") {
144 | continue;
145 | }
146 |
147 | auto prefix_size = proto_dir.size() + 1;
148 | if (file.size() < prefix_size) {
149 | continue;
150 | }
151 |
152 | _load(file.substr(prefix_size));
153 | }
154 | }
155 |
156 | void ProtoFactory::_load(const std::string &file) {
157 | // Clear last errors.
158 | _error_collector.clear();
159 |
160 | auto *desc = _importer.Import(file);
161 | if (desc == nullptr || _error_collector.has_error()) {
162 | throw Error("failed to load " + file + "\n" + _error_collector.last_errors());
163 | }
164 |
165 | _loaded_files.insert(file);
166 | }
167 |
168 | std::string ProtoFactory::_canonicalize_path(std::string proto_dir) const {
169 | // Remove trailing '/'
170 | while (!proto_dir.empty() && proto_dir.back() == '/') {
171 | proto_dir.resize(proto_dir.size() - 1);
172 | }
173 |
174 | if (proto_dir.empty()) {
175 | throw Error("invalid proto dir: " + proto_dir);
176 | }
177 |
178 | return proto_dir;
179 | }
180 |
181 | void ProtoFactory::_async_load() {
182 | while (!_stop_loader) {
183 | std::unordered_map tasks;
184 | {
185 | std::unique_lock lock(_mtx);
186 | _cv.wait(lock, [this]() { return this->_stop_loader || !(this->_tasks).empty(); });
187 |
188 | tasks.swap(_tasks);
189 | }
190 |
191 | std::unordered_map status;
192 | for (const auto &task : tasks) {
193 | const auto &filename = task.first;
194 | const auto &content = task.second;
195 | try {
196 | _load(filename, content);
197 |
198 | status[filename] = "OK";
199 | } catch (const Error &err) {
200 | status[filename] = std::string("ERR ") + err.what();
201 | }
202 | }
203 |
204 | if (!status.empty()) {
205 | std::lock_guard lock(_mtx);
206 |
207 | for (auto &&ele : status) {
208 | _last_loaded_files[ele.first] = std::move(ele.second);
209 | }
210 | }
211 | }
212 | }
213 |
214 | void ProtoFactory::_load(const std::string &filename, const std::string &content) {
215 | auto iter = _loaded_files.find(filename);
216 | if (iter != _loaded_files.end()) {
217 | throw Error("already imported");
218 | }
219 |
220 | _dump_to_disk(filename, content);
221 |
222 | try {
223 | _load(filename);
224 | } catch (const Error &) {
225 | io::remove_file(_absolute_path(filename));
226 | throw;
227 | }
228 | }
229 |
230 | void ProtoFactory::_dump_to_disk(const std::string &filename, const std::string &content) const {
231 | auto path = _absolute_path(filename);
232 |
233 | std::ofstream file(path);
234 | if (!file) {
235 | throw Error("failed to open proto file for writing: " + path);
236 | }
237 |
238 | file << content;
239 | }
240 |
241 | std::string ProtoFactory::_absolute_path(const std::string &path) const {
242 | return _proto_dir + "/" + path;
243 | }
244 |
245 | }
246 |
247 | }
248 |
249 | }
250 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/proto_factory.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_PROTO_FACTORY_H
18 | #define SEWENEW_REDISPROTOBUF_PROTO_FACTORY_H
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "utils.h"
32 |
33 | namespace sw {
34 |
35 | namespace redis {
36 |
37 | namespace pb {
38 |
39 | class FactoryErrorCollector : public gp::compiler::MultiFileErrorCollector {
40 | public:
41 | virtual void AddError(const std::string &file_name,
42 | int line,
43 | int column,
44 | const std::string &message) override {
45 | _add_error("error", file_name, line, column, message);
46 | }
47 |
48 | virtual void AddWarning(const std::string &file_name,
49 | int line,
50 | int column,
51 | const std::string &message) override {
52 | _add_error("warning", file_name, line, column, message);
53 | }
54 |
55 | std::string last_errors() const;
56 |
57 | bool has_error() const {
58 | return !_errors.empty();
59 | }
60 |
61 | void clear() {
62 | _errors.clear();
63 | }
64 |
65 | private:
66 | void _add_error(const std::string &type,
67 | const std::string &filename,
68 | int line,
69 | int column,
70 | const std::string &message);
71 |
72 | std::vector _errors;
73 | };
74 |
75 | class ProtoFactory {
76 | public:
77 | explicit ProtoFactory(const std::string &proto_dir);
78 |
79 | ProtoFactory(const ProtoFactory &) = delete;
80 | ProtoFactory& operator=(const ProtoFactory &) = delete;
81 |
82 | ProtoFactory(ProtoFactory &&) = delete;
83 | ProtoFactory& operator=(ProtoFactory &&) = delete;
84 |
85 | ~ProtoFactory();
86 |
87 | MsgUPtr create(const std::string &type);
88 |
89 | MsgUPtr create(const std::string &type, const StringView &sv);
90 |
91 | const gp::Descriptor* descriptor(const std::string &type);
92 |
93 | void load(const std::string &file, const std::string &content);
94 |
95 | std::unordered_map last_loaded();
96 |
97 | private:
98 | void _load_protos(const std::string &proto_dir);
99 |
100 | void _load(const std::string &file);
101 |
102 | void _load(const std::string &filename, const std::string &content);
103 |
104 | std::string _canonicalize_path(std::string proto_dir) const;
105 |
106 | void _async_load();
107 |
108 | void _dump_to_disk(const std::string &filename, const std::string &content) const;
109 |
110 | std::string _absolute_path(const std::string &path) const;
111 |
112 | // Dir where .proto file are saved.
113 | std::string _proto_dir;
114 |
115 | gp::compiler::DiskSourceTree _source_tree;
116 |
117 | FactoryErrorCollector _error_collector;
118 |
119 | gp::compiler::Importer _importer;
120 |
121 | gp::DynamicMessageFactory _factory;
122 |
123 | std::unordered_map _descriptor_cache;
124 |
125 | std::unordered_set _loaded_files;
126 |
127 | std::mutex _mtx;
128 |
129 | std::condition_variable _cv;
130 |
131 | // map
132 | std::unordered_map _tasks;
133 |
134 | // map
135 | std::unordered_map _last_loaded_files;
136 |
137 | std::atomic _stop_loader{false};
138 |
139 | std::thread _async_loader;
140 | };
141 |
142 | }
143 |
144 | }
145 |
146 | }
147 |
148 | #endif // end SEWENEW_REDISPROTOBUF_PROTO_FACTORY_H
149 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/redis_protobuf.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "redis_protobuf.h"
18 | #include
19 | #include
20 | #include
21 | #include "errors.h"
22 | #include "commands.h"
23 |
24 | namespace {
25 |
26 | struct StringDeleter {
27 | void operator()(char *str) const {
28 | if (str != nullptr) {
29 | RedisModule_Free(str);
30 | }
31 | }
32 | };
33 |
34 | using StringUPtr = std::unique_ptr;
35 |
36 | struct RDBString {
37 | StringUPtr str;
38 | std::size_t len;
39 | };
40 |
41 | RDBString rdb_load_string(RedisModuleIO *rdb);
42 |
43 | std::pair rdb_load_value(RedisModuleIO *rdb);
44 |
45 | std::pair serialize_message(void *value);
46 |
47 | }
48 |
49 | namespace sw {
50 |
51 | namespace redis {
52 |
53 | namespace pb {
54 |
55 | RedisProtobuf& RedisProtobuf::instance() {
56 | static RedisProtobuf redis_proto;
57 |
58 | return redis_proto;
59 | }
60 |
61 | void RedisProtobuf::load(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
62 | assert(ctx != nullptr);
63 |
64 | if (RedisModule_Init(ctx,
65 | module_name().data(),
66 | module_version(),
67 | REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
68 | throw Error("fail to init module of " + module_name() + " type");
69 | }
70 |
71 | _options.load(argv, argc);
72 |
73 | RedisModuleTypeMethods methods = {
74 | REDISMODULE_TYPE_METHOD_VERSION,
75 | _rdb_load,
76 | _rdb_save,
77 | _aof_rewrite,
78 | nullptr,
79 | nullptr,
80 | _free_msg
81 | };
82 |
83 | _module_type = RedisModule_CreateDataType(ctx,
84 | type_name().data(),
85 | encoding_version(),
86 | &methods);
87 | if (_module_type == nullptr) {
88 | throw Error(std::string("failed to create ") + type_name() + " type");
89 | }
90 |
91 | _proto_factory = std::unique_ptr(new ProtoFactory(options().proto_dir));
92 |
93 | cmd::create_commands(ctx);
94 | }
95 |
96 | void* RedisProtobuf::_rdb_load(RedisModuleIO *rdb, int encver) {
97 | try {
98 | assert(rdb != nullptr);
99 |
100 | auto &m = RedisProtobuf::instance();
101 |
102 | if (encver != m.encoding_version()) {
103 | throw Error("cannot load data of version: " + std::to_string(encver));
104 | }
105 |
106 | RDBString type_str;
107 | RDBString data_str;
108 | std::tie(type_str, data_str) = rdb_load_value(rdb);
109 |
110 | auto type = std::string(type_str.str.get(), type_str.len);
111 |
112 | auto *factory = m.proto_factory();
113 |
114 | assert(factory != nullptr);
115 |
116 | auto msg = factory->create(type);
117 | if (!msg) {
118 | throw Error("unknown protobuf type: " + type);
119 | }
120 |
121 | if (!msg->ParseFromArray(data_str.str.get(), data_str.len)) {
122 | throw Error("failed to parse protobuf of type: " + type);
123 | }
124 |
125 | return msg.release();
126 | } catch (const Error &e) {
127 | RedisModule_LogIOError(rdb, "warning", e.what());
128 | return nullptr;
129 | }
130 | }
131 |
132 | void RedisProtobuf::_rdb_save(RedisModuleIO *rdb, void *value) {
133 | try {
134 | assert(rdb != nullptr);
135 |
136 | std::string type;
137 | std::string buf;
138 | std::tie(type, buf) = serialize_message(value);
139 |
140 | RedisModule_SaveStringBuffer(rdb, type.data(), type.size());
141 |
142 | RedisModule_SaveStringBuffer(rdb, buf.data(), buf.size());
143 | } catch (const Error &e) {
144 | RedisModule_LogIOError(rdb, "warning", e.what());
145 | }
146 | }
147 |
148 | void RedisProtobuf::_aof_rewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) {
149 | try {
150 | assert(aof != nullptr);
151 |
152 | if (key == nullptr) {
153 | throw Error("null key to rewrite aof");
154 | }
155 |
156 | std::string type;
157 | std::string buf;
158 | std::tie(type, buf) = serialize_message(value);
159 |
160 | RedisModule_EmitAOF(aof,
161 | "PB.SET",
162 | "sbb",
163 | key,
164 | type.data(),
165 | type.size(),
166 | buf.data(),
167 | buf.size());
168 | } catch (const Error &e) {
169 | RedisModule_LogIOError(aof, "warning", e.what());
170 | }
171 | }
172 |
173 | void RedisProtobuf::_free_msg(void *value) {
174 | if (value != nullptr) {
175 | auto *msg = static_cast(value);
176 | delete msg;
177 | }
178 | }
179 |
180 | }
181 |
182 | }
183 |
184 | }
185 |
186 | namespace {
187 |
188 | using sw::redis::pb::Error;
189 |
190 | RDBString rdb_load_string(RedisModuleIO *rdb) {
191 | std::size_t len = 0;
192 | auto *buf = RedisModule_LoadStringBuffer(rdb, &len);
193 | if (buf == nullptr) {
194 | throw Error("failed to load string buffer from rdb");
195 | }
196 |
197 | return {StringUPtr(buf), len};
198 | }
199 |
200 | std::pair rdb_load_value(RedisModuleIO *rdb) {
201 | auto type = rdb_load_string(rdb);
202 |
203 | auto data = rdb_load_string(rdb);
204 |
205 | return {std::move(type), std::move(data)};
206 | }
207 |
208 | std::pair serialize_message(void *value) {
209 | if (value == nullptr) {
210 | throw Error("Null value to serialize");
211 | }
212 |
213 | auto *msg = static_cast(value);
214 |
215 | auto type = msg->GetTypeName();
216 |
217 | std::string buf;
218 | if (!msg->SerializeToString(&buf)) {
219 | throw Error("failed to serialize protobuf message of type " + type);
220 | }
221 |
222 | return {std::move(type), std::move(buf)};
223 | }
224 |
225 | }
226 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/redis_protobuf.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_REDIS_PROTOBUF_H
18 | #define SEWENEW_REDISPROTOBUF_REDIS_PROTOBUF_H
19 |
20 | #include "module_api.h"
21 | #include "proto_factory.h"
22 | #include "options.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | class RedisProtobuf {
31 | public:
32 | static RedisProtobuf& instance();
33 |
34 | void load(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
35 |
36 | int module_version() const {
37 | return _MODULE_VERSION;
38 | }
39 |
40 | int encoding_version() const {
41 | return _ENCODING_VERSION;
42 | }
43 |
44 | const std::string& module_name() const {
45 | return _MODULE_NAME;
46 | }
47 |
48 | const std::string& type_name() const {
49 | return _TYPE_NAME;
50 | }
51 |
52 | RedisModuleType* type() {
53 | return _module_type;
54 | }
55 |
56 | const Options& options() const {
57 | return _options;
58 | }
59 |
60 | ProtoFactory* proto_factory() {
61 | return _proto_factory.get();
62 | }
63 |
64 | private:
65 | RedisProtobuf() = default;
66 |
67 | static void* _rdb_load(RedisModuleIO *rdb, int encver);
68 |
69 | static void _rdb_save(RedisModuleIO *rdb, void *value);
70 |
71 | static void _aof_rewrite(RedisModuleIO *aof, RedisModuleString *key, void *value);
72 |
73 | static void _free_msg(void *value);
74 |
75 | const int _MODULE_VERSION = 1;
76 |
77 | const int _ENCODING_VERSION = 0;
78 |
79 | const std::string _MODULE_NAME = "PB";
80 |
81 | const std::string _TYPE_NAME = "PROTOC-SW";
82 |
83 | RedisModuleType *_module_type = nullptr;
84 |
85 | std::unique_ptr _proto_factory;
86 |
87 | Options _options;
88 | };
89 |
90 | }
91 |
92 | }
93 |
94 | }
95 |
96 | #endif // end SEWENEW_REDISPROTOBUF_REDIS_PROTOBUF_H
97 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/redismodule.cpp:
--------------------------------------------------------------------------------
1 | // This file is copied from Redis 4.0, and I splited the original header into
2 | // a header file and a cpp file, i.e. redismodule.h and redismodule.cpp.
3 | // So that it can be compiled with C++ compiler.
4 |
5 | #include "redismodule.h"
6 |
7 | #ifndef REDISMODULE_CORE
8 |
9 | void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes);
10 | void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes);
11 | void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr);
12 | void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size);
13 | char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str);
14 | int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *);
15 | int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep);
16 | void REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver);
17 | int REDISMODULE_API_FUNC(RedisModule_IsModuleNameBusy)(const char *name);
18 | int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx);
19 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll);
20 | int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx);
21 | int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid);
22 | void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode);
23 | void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp);
24 | int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp);
25 | size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp);
26 | int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele);
27 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where);
28 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
29 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len);
30 | void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply);
31 | int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply);
32 | long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply);
33 | size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply);
34 | RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx);
35 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len);
36 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll);
37 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str);
38 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...);
39 | void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str);
40 | const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len);
41 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err);
42 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg);
43 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len);
44 | void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len);
45 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len);
46 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str);
47 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx);
48 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d);
49 | int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply);
50 | int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll);
51 | int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d);
52 | void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx);
53 | int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...);
54 | int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx);
55 | const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len);
56 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply);
57 | int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key);
58 | int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str);
59 | char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode);
60 | int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen);
61 | mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key);
62 | int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire);
63 | int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr);
64 | int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore);
65 | int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score);
66 | int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted);
67 | void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key);
68 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
69 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex);
70 | int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
71 | int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max);
72 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score);
73 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key);
74 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key);
75 | int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key);
76 | int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...);
77 | int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...);
78 | int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx);
79 | void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos);
80 | unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx);
81 | int REDISMODULE_API_FUNC(RedisModule_GetContextFlags)(RedisModuleCtx *ctx);
82 | void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes);
83 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods);
84 | int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value);
85 | RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key);
86 | void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key);
87 | void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value);
88 | uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io);
89 | void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value);
90 | int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io);
91 | void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...);
92 | void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s);
93 | void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len);
94 | RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io);
95 | char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr);
96 | void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value);
97 | double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
98 | void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value);
99 | float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io);
100 | void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...);
101 | void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...);
102 | int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len);
103 | void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str);
104 | int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b);
105 | RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io);
106 | long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void);
107 | void REDISMODULE_API_FUNC(RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len);
108 | void REDISMODULE_API_FUNC(RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele);
109 | void REDISMODULE_API_FUNC(RedisModule_DigestEndSequence)(RedisModuleDigest *md);
110 |
111 | #ifdef REDISMODULE_EXPERIMENTAL_API
112 |
113 | RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms);
114 | int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata);
115 | int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx);
116 | int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx);
117 | void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx);
118 | int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc);
119 | RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc);
120 | void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx);
121 | void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx);
122 | void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx);
123 |
124 | #endif
125 |
126 | #endif
127 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/schema_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "schema_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 | #include "field_ref.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | int SchemaCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
29 | try {
30 | assert(ctx != nullptr);
31 |
32 | auto args = _parse_args(argv, argc);
33 | const auto &type = args.type;
34 |
35 | auto *desc = RedisProtobuf::instance().proto_factory()->descriptor(type);
36 | if (desc == nullptr) {
37 | RedisModule_ReplyWithNull(ctx);
38 | } else {
39 | //auto schema = _format(desc->DebugString());
40 | auto schema = desc->DebugString();
41 |
42 | RedisModule_ReplyWithStringBuffer(ctx, schema.data(), schema.size());
43 | }
44 |
45 | return REDISMODULE_OK;
46 | } catch (const WrongArityError &err) {
47 | return RedisModule_WrongArity(ctx);
48 | } catch (const Error &err) {
49 | return api::reply_with_error(ctx, err);
50 | }
51 |
52 | return REDISMODULE_ERR;
53 | }
54 |
55 | SchemaCommand::Args SchemaCommand::_parse_args(RedisModuleString **argv, int argc) const {
56 | assert(argv != nullptr);
57 |
58 | if (argc != 2) {
59 | throw WrongArityError();
60 | }
61 |
62 | return {Path(argv[1]).type()};
63 | }
64 |
65 | std::string SchemaCommand::_format(const std::string &schema) const {
66 | std::string formated_schema;
67 | formated_schema.reserve(schema.size() * 2);
68 |
69 | for (auto ch : schema) {
70 | if (ch != '.') {
71 | formated_schema.push_back(ch);
72 | } else {
73 | if (formated_schema.empty()) {
74 | // This should not happen.
75 | throw Error("invalid schema");
76 | }
77 |
78 | if (formated_schema.back() != ' ') {
79 | // '.' => '::'
80 | formated_schema.append("::");
81 | } // else discard leading '.'
82 | }
83 | }
84 |
85 | return formated_schema;
86 | }
87 |
88 | }
89 |
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/schema_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_SCHEMA_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_SCHEMA_COMMANDS_H
19 |
20 | #include
21 | #include "module_api.h"
22 | #include "utils.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | // command: PB.SCHEMA type
31 | // return: Bulk string reply: return the schema of the specified type. If
32 | // the type doesn't exist, return a nil reply.
33 | class SchemaCommand {
34 | public:
35 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
36 |
37 | private:
38 | struct Args {
39 | std::string type;
40 | };
41 |
42 | Args _parse_args(RedisModuleString **argv, int argc) const;
43 |
44 | std::string _format(const std::string &schema) const;
45 | };
46 |
47 | }
48 |
49 | }
50 |
51 | }
52 |
53 | #endif // end SEWENEW_REDISPROTOBUF_SCHEMA_COMMANDS_H
54 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/set_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_SET_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_SET_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include
24 | #include "utils.h"
25 | #include "field_ref.h"
26 |
27 | namespace sw {
28 |
29 | namespace redis {
30 |
31 | namespace pb {
32 |
33 | // command: PB.SET key [--NX|--XX] [--EX seconds | --PX milliseconds] type [path] value
34 | // return: Integer reply: 1 if set successfully. 0, otherwise, e.g. option --NX has
35 | // been set, while key already exists.
36 | // error: If the type doesn't match the protobuf message type of the
37 | // key, or the path doesn't exist, return an error reply.
38 | class SetCommand {
39 | public:
40 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
41 |
42 | private:
43 | struct Args {
44 | RedisModuleString *key_name;
45 |
46 | enum class Opt {
47 | NX = 0,
48 | XX,
49 | NONE
50 | };
51 |
52 | Opt opt = Opt::NONE;
53 |
54 | std::chrono::milliseconds expire{0};
55 |
56 | Path path;
57 | StringView val;
58 | };
59 |
60 | int _run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
61 |
62 | friend class MergeCommand;
63 |
64 | Args _parse_args(RedisModuleString **argv, int argc) const;
65 |
66 | // Return the position of the first non-option argument.
67 | int _parse_opts(RedisModuleString **argv, int argc, Args &args) const;
68 |
69 | int64_t _parse_expire(const StringView &sv) const;
70 |
71 | void _create_msg(RedisModuleKey &key,
72 | const Path &path,
73 | const StringView &val) const;
74 |
75 | void _set_msg(RedisModuleKey &key,
76 | const Path &path,
77 | const StringView &val) const;
78 |
79 | void _set_scalar_field(MutableFieldRef &field, const StringView &val) const;
80 |
81 | void _set_map_element(MutableFieldRef &field, const StringView &val) const;
82 |
83 | void _set_array_element(MutableFieldRef &field, const StringView &val) const;
84 |
85 | void _set_field(MutableFieldRef &field, const StringView &sv) const;
86 |
87 | void _set_int32(MutableFieldRef &field, const StringView &sv) const;
88 |
89 | void _set_int64(MutableFieldRef &field, const StringView &sv) const;
90 |
91 | void _set_uint32(MutableFieldRef &field, const StringView &sv) const;
92 |
93 | void _set_uint64(MutableFieldRef &field, const StringView &sv) const;
94 |
95 | void _set_double(MutableFieldRef &field, const StringView &sv) const;
96 |
97 | void _set_float(MutableFieldRef &field, const StringView &sv) const;
98 |
99 | void _set_bool(MutableFieldRef &field, const StringView &sv) const;
100 |
101 | void _set_enum(MutableFieldRef &field, const StringView &sv) const;
102 |
103 | void _set_string(MutableFieldRef &field, const StringView &sv) const;
104 |
105 | void _set_msg(MutableFieldRef &field, const StringView &sv) const;
106 |
107 | void _set_repeated_int32(MutableFieldRef &field, const StringView &sv) const;
108 |
109 | void _set_repeated_int64(MutableFieldRef &field, const StringView &sv) const;
110 |
111 | void _set_repeated_uint32(MutableFieldRef &field, const StringView &sv) const;
112 |
113 | void _set_repeated_uint64(MutableFieldRef &field, const StringView &sv) const;
114 |
115 | void _set_repeated_double(MutableFieldRef &field, const StringView &sv) const;
116 |
117 | void _set_repeated_float(MutableFieldRef &field, const StringView &sv) const;
118 |
119 | void _set_repeated_bool(MutableFieldRef &field, const StringView &sv) const;
120 |
121 | void _set_repeated_enum(MutableFieldRef &field, const StringView &sv) const;
122 |
123 | void _set_repeated_string(MutableFieldRef &field, const StringView &sv) const;
124 |
125 | void _set_repeated_msg(MutableFieldRef &field, const StringView &sv) const;
126 |
127 | void _set_mapped_int32(MutableFieldRef &field, const StringView &sv) const;
128 |
129 | void _set_mapped_int64(MutableFieldRef &field, const StringView &sv) const;
130 |
131 | void _set_mapped_uint32(MutableFieldRef &field, const StringView &sv) const;
132 |
133 | void _set_mapped_uint64(MutableFieldRef &field, const StringView &sv) const;
134 |
135 | void _set_mapped_double(MutableFieldRef &field, const StringView &sv) const;
136 |
137 | void _set_mapped_float(MutableFieldRef &field, const StringView &sv) const;
138 |
139 | void _set_mapped_bool(MutableFieldRef &field, const StringView &sv) const;
140 |
141 | void _set_mapped_enum(MutableFieldRef &field, const StringView &sv) const;
142 |
143 | void _set_mapped_string(MutableFieldRef &field, const StringView &sv) const;
144 |
145 | void _set_mapped_msg(MutableFieldRef &field, const StringView &sv) const;
146 | };
147 |
148 | }
149 |
150 | }
151 |
152 | }
153 |
154 | #endif // end SEWENEW_REDISPROTOBUF_SET_COMMANDS_H
155 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/type_command.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "type_command.h"
18 | #include "errors.h"
19 | #include "redis_protobuf.h"
20 | #include "utils.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | int TypeCommand::run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const {
29 | try {
30 | assert(ctx != nullptr);
31 |
32 | auto args = _parse_args(argv, argc);
33 |
34 | auto key = api::open_key(ctx, args.key_name, api::KeyMode::READONLY);
35 | if (!api::key_exists(key.get(), RedisProtobuf::instance().type())) {
36 | return RedisModule_ReplyWithNull(ctx);
37 | }
38 |
39 | auto *msg = api::get_msg_by_key(key.get());
40 | assert(msg != nullptr);
41 |
42 | auto type = _format_type(msg->GetTypeName());
43 |
44 | return RedisModule_ReplyWithSimpleString(ctx, type.data());
45 | } catch (const WrongArityError &err) {
46 | return RedisModule_WrongArity(ctx);
47 | } catch (const Error &err) {
48 | return api::reply_with_error(ctx, err);
49 | }
50 | }
51 |
52 | TypeCommand::Args TypeCommand::_parse_args(RedisModuleString **argv, int argc) const {
53 | assert(argv != nullptr);
54 |
55 | if (argc != 2) {
56 | throw WrongArityError();
57 | }
58 |
59 | return Args{argv[1]};
60 | }
61 |
62 | std::string TypeCommand::_format_type(std::string type) const {
63 | auto pos = type.find('.');
64 | if (pos == std::string::npos) {
65 | // No namespace.
66 | return type;
67 | }
68 |
69 | std::string type_str;
70 | type_str.reserve(type.size() * 2);
71 |
72 | type_str = type.substr(0, pos);
73 |
74 | for (std::size_t idx = pos; idx != type.size(); ++idx) {
75 | auto ch = type[idx];
76 | if (ch != '.') {
77 | type_str.push_back(ch);
78 | } else {
79 | type_str.append("::");
80 | }
81 | }
82 |
83 | return type_str;
84 | }
85 |
86 | }
87 |
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/type_command.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TYPE_COMMANDS_H
18 | #define SEWENEW_REDISPROTOBUF_TYPE_COMMANDS_H
19 |
20 | #include "module_api.h"
21 | #include
22 | #include
23 | #include "utils.h"
24 |
25 | namespace sw {
26 |
27 | namespace redis {
28 |
29 | namespace pb {
30 |
31 | // command: PB.TYPE key
32 | // return: Simple string reply: the protobuf type of the key.
33 | // If key doesn't exist, return a nil reply.
34 | class TypeCommand {
35 | public:
36 | int run(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) const;
37 |
38 | private:
39 | struct Args {
40 | RedisModuleString *key_name;
41 | };
42 |
43 | Args _parse_args(RedisModuleString **argv, int argc) const;
44 |
45 | std::string _format_type(std::string type) const;
46 | };
47 |
48 | }
49 |
50 | }
51 |
52 | }
53 |
54 | #endif // end SEWENEW_REDISPROTOBUF_TYPE_COMMANDS_H
55 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/utils.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "utils.h"
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include "errors.h"
25 |
26 | namespace {
27 |
28 | mode_t file_type(const std::string &file);
29 |
30 | }
31 |
32 | namespace sw {
33 |
34 | namespace redis {
35 |
36 | namespace pb {
37 |
38 | StringView::StringView(RedisModuleString *str) {
39 | if (str == nullptr) {
40 | throw Error("null string");
41 | }
42 |
43 | _data = RedisModule_StringPtrLen(str, &_size);
44 | }
45 |
46 | namespace util {
47 |
48 | std::string msg_to_json(const gp::Message &msg) {
49 | std::string json;
50 | auto status = gp::util::MessageToJsonString(msg, &json);
51 | if (!status.ok()) {
52 | throw Error("failed to parse message to json");
53 | }
54 |
55 | return json;
56 | }
57 |
58 | int32_t sv_to_int32(const StringView &sv) {
59 | try {
60 | return std::stoi(std::string(sv.data(), sv.size()));
61 | } catch (const std::exception &e) {
62 | throw Error("not int32");
63 | }
64 | }
65 |
66 | int64_t sv_to_int64(const StringView &sv) {
67 | try {
68 | return std::stoll(std::string(sv.data(), sv.size()));
69 | } catch (const std::exception &e) {
70 | throw Error("not int64");
71 | }
72 | }
73 |
74 | uint32_t sv_to_uint32(const StringView &sv) {
75 | try {
76 | // TODO: check if it's overflow
77 | return std::stoul(std::string(sv.data(), sv.size()));
78 | } catch (const std::exception &e) {
79 | throw Error("not uint32");
80 | }
81 | }
82 |
83 | uint64_t sv_to_uint64(const StringView &sv) {
84 | try {
85 | return std::stoull(std::string(sv.data(), sv.size()));
86 | } catch (const std::exception &e) {
87 | throw Error("not uint64");
88 | }
89 | }
90 |
91 | double sv_to_double(const StringView &sv) {
92 | try {
93 | return std::stod(std::string(sv.data(), sv.size()));
94 | } catch (const std::exception &e) {
95 | throw Error("not double");
96 | }
97 | }
98 |
99 | float sv_to_float(const StringView &sv) {
100 | try {
101 | return std::stof(std::string(sv.data(), sv.size()));
102 | } catch (const std::exception &e) {
103 | throw Error("not float");
104 | }
105 | }
106 |
107 | bool sv_to_bool(const StringView &sv) {
108 | bool b = false;
109 | auto s = std::string(sv.data(), sv.size());
110 | // TODO: make it case insensitive
111 | if (s == "true") {
112 | b = true;
113 | } else if (s == "false") {
114 | b = false;
115 | } else {
116 | try {
117 | auto val = std::stoi(s);
118 | if (val == 0) {
119 | b = false;
120 | } else {
121 | b = true;
122 | }
123 | } catch (const std::exception &e) {
124 | throw Error("not bool");
125 | }
126 | }
127 |
128 | return b;
129 | }
130 |
131 | std::string sv_to_string(const StringView &sv) {
132 | return std::string(sv.data(), sv.size());
133 | }
134 |
135 | bool str_case_equal(const StringView &s1, const StringView &s2) {
136 | if (s1.size() != s2.size()) {
137 | return false;
138 | }
139 |
140 | const auto *p1 = s1.data();
141 | const auto *p2 = s2.data();
142 | for (std::size_t idx = 0; idx != s1.size(); ++idx) {
143 | if (static_cast(std::toupper(static_cast(p1[idx])))
144 | != static_cast(std::toupper(static_cast(p2[idx])))) {
145 | return false;
146 | }
147 | }
148 |
149 | return true;
150 | }
151 |
152 | }
153 |
154 | namespace io {
155 |
156 | bool is_regular(const std::string &file) {
157 | return S_ISREG(file_type(file));
158 | }
159 |
160 | bool is_directory(const std::string &file) {
161 | return S_ISDIR(file_type(file));
162 | }
163 |
164 | std::vector list_dir(const std::string &path) {
165 | if (!is_directory(path)) {
166 | throw Error(path + " is not a directory");
167 | }
168 |
169 | auto *dir = opendir(path.c_str());
170 | if (dir == nullptr) {
171 | throw Error("failed to open directory: " + path);
172 | }
173 |
174 | std::vector files;
175 | dirent *entry = nullptr;
176 | while ((entry = readdir(dir)) != nullptr) {
177 | std::string name = entry->d_name;
178 |
179 | // Skip "." and ".."
180 | if (name == "." || name == "..") {
181 | continue;
182 | }
183 |
184 | auto file_path = path + "/" + name;
185 | if (is_directory(file_path)) {
186 | auto sub_files = list_dir(file_path);
187 | files.insert(files.end(), sub_files.begin(), sub_files.end());
188 | } else {
189 | files.push_back(file_path);
190 | }
191 | }
192 |
193 | closedir(dir);
194 |
195 | return files;
196 | }
197 |
198 | std::string extension(const std::string &file) {
199 | auto pos = file.rfind(".");
200 | if (pos == std::string::npos) {
201 | return {};
202 | }
203 |
204 | return file.substr(pos + 1);
205 | }
206 |
207 | void remove_file(const std::string &path) {
208 | std::remove(path.data());
209 | }
210 |
211 | }
212 |
213 | }
214 |
215 | }
216 |
217 | }
218 |
219 | namespace {
220 |
221 | mode_t file_type(const std::string &file) {
222 | struct stat buf;
223 | if (stat(file.c_str(), &buf) < 0) {
224 | throw sw::redis::pb::Error("failed to get file status: " + file);
225 | }
226 |
227 | return buf.st_mode;
228 | }
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/src/sw/redis-protobuf/utils.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2019 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_UTILS_H
18 | #define SEWENEW_REDISPROTOBUF_UTILS_H
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "module_api.h"
26 |
27 | namespace sw {
28 |
29 | namespace redis {
30 |
31 | namespace pb {
32 |
33 | namespace gp = google::protobuf;
34 |
35 | using MsgUPtr = std::unique_ptr;
36 |
37 | // By now, not all compilers support std::string_view,
38 | // so we make our own implementation.
39 | class StringView {
40 | public:
41 | constexpr StringView() noexcept = default;
42 |
43 | constexpr StringView(const char *data, std::size_t size) : _data(data), _size(size) {}
44 |
45 | StringView(const char *data) : _data(data), _size(std::strlen(data)) {}
46 |
47 | StringView(const std::string &str) : _data(str.data()), _size(str.size()) {}
48 |
49 | StringView(RedisModuleString *str);
50 |
51 | constexpr StringView(const StringView &) noexcept = default;
52 |
53 | StringView& operator=(const StringView &) noexcept = default;
54 |
55 | constexpr const char* data() const noexcept {
56 | return _data;
57 | }
58 |
59 | constexpr std::size_t size() const noexcept {
60 | return _size;
61 | }
62 |
63 | constexpr bool empty() const noexcept {
64 | return _size == 0;
65 | }
66 |
67 | private:
68 | const char *_data = nullptr;
69 | std::size_t _size = 0;
70 | };
71 |
72 | template
73 | class Optional {
74 | public:
75 | Optional() = default;
76 |
77 | Optional(const Optional &) = default;
78 | Optional& operator=(const Optional &) = default;
79 |
80 | Optional(Optional &&) = default;
81 | Optional& operator=(Optional &&) = default;
82 |
83 | ~Optional() = default;
84 |
85 | template
86 | explicit Optional(Args &&...args) : _value(true, T(std::forward(args)...)) {}
87 |
88 | explicit operator bool() const {
89 | return _value.first;
90 | }
91 |
92 | T& value() {
93 | return _value.second;
94 | }
95 |
96 | const T& value() const {
97 | return _value.second;
98 | }
99 |
100 | T* operator->() {
101 | return &(_value.second);
102 | }
103 |
104 | const T* operator->() const {
105 | return &(_value.second);
106 | }
107 |
108 | T& operator*() {
109 | return _value.second;
110 | }
111 |
112 | const T& operator*() const {
113 | return _value.second;
114 | }
115 |
116 | void reset() noexcept {
117 | _value.first = false;
118 | }
119 |
120 | private:
121 | std::pair _value;
122 | };
123 |
124 | namespace util {
125 |
126 | std::string msg_to_json(const gp::Message &msg);
127 |
128 | int32_t sv_to_int32(const StringView &sv);
129 |
130 | int64_t sv_to_int64(const StringView &sv);
131 |
132 | uint32_t sv_to_uint32(const StringView &sv);
133 |
134 | uint64_t sv_to_uint64(const StringView &sv);
135 |
136 | double sv_to_double(const StringView &sv);
137 |
138 | float sv_to_float(const StringView &sv);
139 |
140 | bool sv_to_bool(const StringView &sv);
141 |
142 | std::string sv_to_string(const StringView &sv);
143 |
144 | bool str_case_equal(const StringView &s1, const StringView &s2);
145 |
146 | }
147 |
148 | namespace io {
149 |
150 | bool is_regular(const std::string &file);
151 |
152 | bool is_directory(const std::string &file);
153 |
154 | std::vector list_dir(const std::string &path);
155 |
156 | std::string extension(const std::string &file);
157 |
158 | void remove_file(const std::string &path);
159 |
160 | }
161 |
162 | }
163 |
164 | }
165 |
166 | }
167 |
168 | #endif // end SEWENEW_REDISPROTOBUF_UTILS_H
169 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/append_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "append_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void AppendTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("append");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"i" : 1})") == 1,
35 | "failed to test pb.append command");
36 |
37 | REDIS_ASSERT(r.command("PB.APPEND", key, "Msg",
38 | "/sub/s", "abc") == 3,
39 | "failed to test appending string");
40 |
41 | REDIS_ASSERT(r.command("PB.APPEND", key, "Msg",
42 | "/sub/s", "123") == 6,
43 | "failed to test appending string");
44 |
45 | REDIS_ASSERT(r.command("PB.GET", key, "Msg",
46 | "/sub/s") == "abc123",
47 | "failed to test pb.append");
48 |
49 | REDIS_ASSERT(r.command("PB.APPEND", key, "Msg",
50 | "/arr", 1, 2) == 2,
51 | "failed to test appending array");
52 |
53 | REDIS_ASSERT(r.command("PB.APPEND", key, "Msg",
54 | "/arr", 3, 4) == 4,
55 | "failed to test appending array");
56 |
57 | REDIS_ASSERT(r.command("PB.GET", key, "Msg",
58 | "/arr/0") == 1,
59 | "failed to test pb.append");
60 | try {
61 | r.command("PB.APPEND", key, "Msg",
62 | "/i", 2);
63 | REDIS_ASSERT(false, "failed to test pb.append");
64 | } catch (const sw::redis::Error &) {
65 | }
66 | }
67 |
68 | }
69 |
70 | }
71 |
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/append_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_APPEND_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_APPEND_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class AppendTest : public ProtoTest {
31 | public:
32 | explicit AppendTest(sw::redis::Redis &r) : ProtoTest("PB.APPEND", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_APPEND_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/clear_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "clear_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void ClearTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("clear");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"i" : 1, "sub" : {"s" : "hello"}, "arr" : [1, 2]})") == 1,
35 | "failed to test pb.append command");
36 |
37 | REDIS_ASSERT(r.command("PB.CLEAR", key, "Msg") == 1 &&
38 | r.command("PB.GET", key, "Msg", "/i") == 0,
39 | "failed to test clear whole message");
40 |
41 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
42 | R"({"i" : 1, "sub" : {"s" : "hello", "i" : 23}, "arr" : [1, 2]})") == 1,
43 | "failed to test pb.clear command");
44 |
45 | REDIS_ASSERT(r.command("PB.CLEAR", key, "Msg", "/i") == 1 &&
46 | r.command("PB.GET", key, "Msg", "/i") == 0,
47 | "failed to test clear int");
48 |
49 | REDIS_ASSERT(r.command("PB.CLEAR", key, "Msg", "/sub/s") == 1 &&
50 | r.command("PB.GET", key, "Msg", "/sub/s").empty(),
51 | "failed to test clear string");
52 |
53 | REDIS_ASSERT(r.command("PB.CLEAR", key, "Msg", "/arr") == 1 &&
54 | r.command("PB.LEN", key, "Msg", "/arr") == 0,
55 | "failed to test clear array");
56 |
57 | REDIS_ASSERT(r.command("PB.CLEAR", key, "Msg", "/sub") == 1 &&
58 | r.command("PB.GET", key, "Msg", "/sub/i") == 0,
59 | "failed to test clear sub message");
60 | }
61 |
62 | }
63 |
64 | }
65 |
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/clear_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_CLEAR_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_CLEAR_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class ClearTest : public ProtoTest {
31 | public:
32 | explicit ClearTest(sw::redis::Redis &r) : ProtoTest("PB.CLEAR", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_CLEAR_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/del_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "del_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void DelTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("del");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"i" : 1, "arr" : [1, 2], "m" : {"key" : "val"}})") == 1,
35 | "failed to test pb.del command");
36 |
37 | REDIS_ASSERT(r.command("PB.DEL", key, "Msg", "/arr/0") == 1 &&
38 | r.command("PB.LEN", key, "Msg", "/arr") == 1,
39 | "failed to test del array element");
40 | /*
41 | TODO: support delete whole array and whole map, and map element
42 | REDIS_ASSERT(r.command("PB.DEL", key, "Msg", "/arr") == 1 &&
43 | r.command("PB.LEN", key, "Msg", "/arr") == 0,
44 | "failed to test del array");
45 |
46 | REDIS_ASSERT(r.command("PB.DEL", key, "Msg", "/m") == 1 &&
47 | r.command("PB.LEN", key, "Msg", "/m") == 0,
48 | "failed to test del map");
49 | */
50 |
51 | REDIS_ASSERT(r.command("PB.DEL", key, "Msg") == 1 &&
52 | r.exists(key) == 0,
53 | "failed to test del message");
54 | }
55 |
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/del_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_DEL_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_DEL_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class DelTest : public ProtoTest {
31 | public:
32 | explicit DelTest(sw::redis::Redis &r) : ProtoTest("PB.DEL", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_DEL_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/import_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "import_test.h"
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include "utils.h"
23 |
24 | namespace sw {
25 |
26 | namespace redis {
27 |
28 | namespace pb {
29 |
30 | namespace test {
31 |
32 | void ImportTest::_run(sw::redis::Redis &r) {
33 | auto key = test_key("import");
34 |
35 | KeyDeleter deleter(r, key);
36 |
37 | std::string name{"test_import.proto"};
38 | auto proto = R"(
39 | syntax = "proto3";
40 | package sw.redis.pb;
41 | message Msg {
42 | int32 i = 1;
43 | string s = 2;
44 | }
45 | )";
46 | r.command("PB.IMPORT", name, proto);
47 |
48 | // Ensure proto has been loaded
49 | std::this_thread::sleep_for(std::chrono::seconds(1));
50 |
51 | auto res = r.command>("PB.LASTIMPORT");
52 | REDIS_ASSERT(res.size() == 1 && res[name] == "OK",
53 | "failed to test pb.import command");
54 |
55 | REDIS_ASSERT(r.command("PB.SET", key, "sw.redis.pb.Msg", "/i", 123) &&
56 | r.command("PB.GET", key, "sw.redis.pb.Msg", "/i") == 123,
57 | "failed to test pb.import command");
58 | }
59 |
60 | }
61 |
62 | }
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/import_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_IMPORT_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_IMPORT_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class ImportTest : public ProtoTest {
31 | public:
32 | explicit ImportTest(sw::redis::Redis &r) : ProtoTest("PB.IMPORT", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_IMPORT_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/len_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "len_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void LenTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("len");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"sub" : {"s" : "hello"}, "arr" : [1, 2, 3], "m" : {"k1" : "v1", "k2" : "v2"}})") == 1,
35 | "failed to test pb.len command");
36 |
37 | REDIS_ASSERT(r.command("PB.LEN", key, "Msg",
38 | "/sub/s") == 5,
39 | "failed to test pb.len with string");
40 |
41 | REDIS_ASSERT(r.command("PB.LEN", key, "Msg",
42 | "/arr") == 3,
43 | "failed to test pb.len with array");
44 |
45 | REDIS_ASSERT(r.command("PB.LEN", key, "Msg",
46 | "/m") == 2,
47 | "failed to test pb.len with map");
48 | }
49 |
50 | }
51 |
52 | }
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/len_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_LEN_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_LEN_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class LenTest : public ProtoTest {
31 | public:
32 | explicit LenTest(sw::redis::Redis &r) : ProtoTest("PB.LEN", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_LEN_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/merge_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "merge_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void MergeTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("merge");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"i" : 1, "m" : {"k1" : "v1"}})") == 1,
35 | "failed to test pb.merge command");
36 |
37 | REDIS_ASSERT(r.command("PB.MERGE", key, "Msg",
38 | R"({"arr" : [1, 2]})") == 1,
39 | "failed to test pb.merge command");
40 |
41 | REDIS_ASSERT(r.command("PB.GET", key, "Msg",
42 | "/arr/0") == 1,
43 | "failed to test pb.merge command");
44 |
45 | REDIS_ASSERT(r.command("PB.LEN", key, "Msg",
46 | "/arr") == 2,
47 | "failed to test pb.merge command");
48 |
49 | REDIS_ASSERT(r.command("PB.MERGE", key, "Msg",
50 | R"({"m" : {"k2" : "v2"}})") == 1,
51 | "failed to test pb.merge command");
52 |
53 | REDIS_ASSERT(r.command("PB.GET", key, "Msg",
54 | "/m/k2") == "v2",
55 | "failed to test pb.merge command");
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/merge_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_MERGE_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_MERGE_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class MergeTest : public ProtoTest {
31 | public:
32 | explicit MergeTest(sw::redis::Redis &r) : ProtoTest("PB.MERGE", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_MERGE_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/proto_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "proto_test.h"
18 | #include
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void ProtoTest::run() {
29 | std::cout << "Test " << _name << ": ";
30 |
31 | _run(_redis);
32 |
33 | std::cout << "pass" << std::endl;
34 | }
35 |
36 | }
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/proto_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_PROTO_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_PROTO_TEST_H
19 |
20 | #include
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class ProtoTest {
31 | public:
32 | ProtoTest(const std::string &name, sw::redis::Redis &r) :
33 | _name(name), _redis(r) {}
34 |
35 | virtual ~ProtoTest() = default;
36 |
37 | void run();
38 |
39 | const std::string& name() const {
40 | return _name;
41 | }
42 |
43 | private:
44 | virtual void _run(sw::redis::Redis &r) = 0;
45 |
46 | std::string _name;
47 |
48 | sw::redis::Redis &_redis;
49 | };
50 |
51 | }
52 |
53 | }
54 |
55 | }
56 |
57 | }
58 |
59 | #endif // endif SEWENEW_REDISPROTOBUF_TEST_PROTO_TEST_H
60 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/schema_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "schema_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void SchemaTest::_run(sw::redis::Redis &r) {
29 | auto schema = r.command("PB.SCHEMA", "Msg");
30 | REDIS_ASSERT(schema && !schema->empty(), "failed to test pb.schema command");
31 |
32 | schema = r.command("PB.SCHEMA",
33 | "sw.redis.pb.not-exist-Msg-type");
34 | REDIS_ASSERT(!schema, "failed to test pb.schema command");
35 | }
36 |
37 | }
38 |
39 | }
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/schema_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_SCHEMA_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_SCHEMA_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class SchemaTest : public ProtoTest {
31 | public:
32 | explicit SchemaTest(sw::redis::Redis &r) : ProtoTest("PB.SCHEMA", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_SCHEMA_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/set_get_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "set_get_test.h"
18 | #include "utils.h"
19 | #include
20 |
21 | namespace sw {
22 |
23 | namespace redis {
24 |
25 | namespace pb {
26 |
27 | namespace test {
28 |
29 | void SetGetTest::_run(sw::redis::Redis &r) {
30 | auto key = test_key("set-get");
31 |
32 | KeyDeleter deleter(r, key);
33 |
34 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
35 | R"({"i" : 1})") == 1 &&
36 | r.command("PB.GET", key, "Msg", "/i") == 1,
37 | "failed to test pb.set and pb.get command");
38 |
39 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
40 | "/i", 2) == 1 &&
41 | r.command("PB.GET", key, "Msg", "/i") == 2,
42 | "failed to test pb.set and pb.get command");
43 |
44 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
45 | R"({"sub" : {"s" : "hello"}})") == 1 &&
46 | r.command("PB.GET", key, "Msg", "/sub/s") == "hello",
47 | "failed to test pb.set and pb.get command");
48 |
49 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
50 | "/sub/s", "world") == 1 &&
51 | r.command("PB.GET", key, "Msg", "/sub/s") == "world",
52 | "failed to test pb.set and pb.get command");
53 |
54 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
55 | R"({"i" : 123, "sub" : {"s" : "hello", "i" : 123}, "arr" : [1, 2], "m" : {"k" : "v"}})") == 1 &&
56 | r.command("PB.GET", key, "Msg", "/sub/s") == "hello" &&
57 | r.command("PB.GET", key, "Msg", "/arr/0") == 1,
58 | "failed to test pb.set and pb.get command");
59 |
60 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
61 | "/m/key", "world") == 1 &&
62 | r.command("PB.GET", key, "Msg", "/m/key") == "world",
63 | "failed to test pb.set and pb.get command");
64 |
65 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
66 | R"({"arr" : [4, 5, 6]})") == 1,
67 | "failed to test pb.set command");
68 |
69 | auto arr = r.command>("PB.GET", key, "Msg", "/arr");
70 | auto tmp = std::vector{4, 5, 6};
71 | REDIS_ASSERT(arr == tmp, "failed to test pb.get command");
72 |
73 | REDIS_ASSERT(r.command("PB.SET", key, "--NX", "Msg",
74 | "/sub/s", "world") == 0,
75 | "failed to test pb.set and pb.get command");
76 | }
77 |
78 | }
79 |
80 | }
81 |
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/set_get_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_SET_TEST_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_SET_TEST_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class SetGetTest : public ProtoTest {
31 | public:
32 | explicit SetGetTest(sw::redis::Redis &r) : ProtoTest("PB.GET PB.SET", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_SET_TEST_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/test_main.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include
18 | #include
19 | #include "append_test.h"
20 | #include "clear_test.h"
21 | #include "del_test.h"
22 | #include "type_test.h"
23 | #include "schema_test.h"
24 | #include "set_get_test.h"
25 | #include "len_test.h"
26 | #include "merge_test.h"
27 | #include "import_test.h"
28 |
29 | int main() {
30 | try {
31 | auto r = sw::redis::Redis("tcp://127.0.0.1");
32 |
33 | sw::redis::pb::test::AppendTest append_test(r);
34 | append_test.run();
35 |
36 | sw::redis::pb::test::ClearTest clear_test(r);
37 | clear_test.run();
38 |
39 | sw::redis::pb::test::DelTest del_test(r);
40 | del_test.run();
41 |
42 | sw::redis::pb::test::TypeTest type_test(r);
43 | type_test.run();
44 |
45 | sw::redis::pb::test::SchemaTest schema_test(r);
46 | schema_test.run();
47 |
48 | sw::redis::pb::test::SetGetTest set_get_test(r);
49 | set_get_test.run();
50 |
51 | sw::redis::pb::test::LenTest len_test(r);
52 | len_test.run();
53 |
54 | sw::redis::pb::test::MergeTest merge_test(r);
55 | merge_test.run();
56 |
57 | sw::redis::pb::test::ImportTest import_test(r);
58 | import_test.run();
59 |
60 | std::cout << "pass all tests" << std::endl;
61 | } catch (const sw::redis::Error &e) {
62 | std::cerr << "failed to do test: " << e.what() << std::endl;
63 | }
64 |
65 | return 0;
66 | }
67 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/type_test.cpp:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #include "type_test.h"
18 | #include "utils.h"
19 |
20 | namespace sw {
21 |
22 | namespace redis {
23 |
24 | namespace pb {
25 |
26 | namespace test {
27 |
28 | void TypeTest::_run(sw::redis::Redis &r) {
29 | auto key = test_key("type");
30 |
31 | KeyDeleter deleter(r, key);
32 |
33 | REDIS_ASSERT(r.command("PB.SET", key, "Msg",
34 | R"({"i" : 1})") == 1,
35 | "failed to test pb.type command");
36 |
37 | auto type = r.command("PB.TYPE", key);
38 | REDIS_ASSERT(type && *type == "Msg",
39 | "failed to test pb.type command");
40 |
41 | type = r.command("PB.TYPE", "sw.redis.pb.not-exist-Msg-type");
42 | REDIS_ASSERT(!type, "failed to test pb.type command");
43 | }
44 |
45 | }
46 |
47 | }
48 |
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/type_test.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2022 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_TYPE_TEST_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_TYPE_TEST_H
19 |
20 | #include "proto_test.h"
21 |
22 | namespace sw {
23 |
24 | namespace redis {
25 |
26 | namespace pb {
27 |
28 | namespace test {
29 |
30 | class TypeTest : public ProtoTest {
31 | public:
32 | explicit TypeTest(sw::redis::Redis &r) : ProtoTest("PB.TYPE", r) {}
33 |
34 | private:
35 | virtual void _run(sw::redis::Redis &r) override;
36 | };
37 |
38 | }
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | #endif // end SEWENEW_REDISPROTOBUF_TEST_TYPE_TEST_H
47 |
--------------------------------------------------------------------------------
/test/src/sw/redis-protobuf/utils.h:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright (c) 2017 sewenew
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | *************************************************************************/
16 |
17 | #ifndef SEWENEW_REDISPROTOBUF_TEST_UTILS_H
18 | #define SEWENEW_REDISPROTOBUF_TEST_UTILS_H
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | #define REDIS_ASSERT(condition, msg) \
25 | sw::redis::pb::test::redis_assert((condition), (msg), __FILE__, __LINE__)
26 |
27 | namespace sw {
28 |
29 | namespace redis {
30 |
31 | namespace pb {
32 |
33 | namespace test {
34 |
35 | inline void redis_assert(bool condition,
36 | const std::string &msg,
37 | const std::string &file,
38 | int line) {
39 | if (!condition) {
40 | auto err_msg = "ASSERT: " + msg + ". " + file + ":" + std::to_string(line);
41 | throw Error(err_msg);
42 | }
43 | }
44 |
45 | inline std::string key_prefix(const std::string &key = "") {
46 | static std::string KEY_PREFIX = "sw::redis::test";
47 | if (!key.empty()) {
48 | KEY_PREFIX = key;
49 | }
50 |
51 | return KEY_PREFIX;
52 | }
53 |
54 | inline std::string test_key(const std::string &k) {
55 | // Key prefix with hash tag,
56 | // so that we can call multiple-key commands on RedisCluster.
57 | return "{" + key_prefix() + "}::" + k;
58 | }
59 |
60 | class KeyDeleter {
61 | public:
62 | template
63 | KeyDeleter(sw::redis::Redis &redis, Input first, Input last) : _redis(redis), _keys(first, last) {
64 | _delete();
65 | }
66 |
67 | KeyDeleter(sw::redis::Redis &redis, std::initializer_list il) :
68 | KeyDeleter(redis, il.begin(), il.end()) {}
69 |
70 | KeyDeleter(sw::redis::Redis &redis, const std::string &key) : KeyDeleter(redis, {key}) {}
71 |
72 | ~KeyDeleter() {
73 | _delete();
74 | }
75 |
76 | private:
77 | void _delete() {
78 | if (!_keys.empty()) {
79 | _redis.del(_keys.begin(), _keys.end());
80 | }
81 | }
82 |
83 | sw::redis::Redis &_redis;
84 | std::vector _keys;
85 | };
86 |
87 | }
88 |
89 | }
90 |
91 | }
92 |
93 | }
94 |
95 | #endif // end SEWENEW_REDISPROTOBUF_TEST_UTILS_H
96 |
--------------------------------------------------------------------------------